Last active
August 12, 2021 14:25
-
-
Save AnastasiaDunbar/b7892e8e7d93143f2f51eab3a7180746 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function clamp(x,minVal,maxVal){return Math.min(Math.max(x,minVal),maxVal);} | |
function pointInRect(px,py,x,y,w,h){return px>=x&&py>=y&&px<x+w&&py<y+h;} | |
function drawASCIItable(x,y,w,h,columns=8,fromChar=32,toChar=126){ | |
stroke(255);noFill(); | |
rect(x,y,w,h); | |
if(user.click){user.ASCIItableClicked=pointInRect(mouseX,mouseY,x,y,w,h);} | |
var charCount=(toChar-fromChar)+1; | |
for(var i=1;i<columns;i++){ | |
line(x+(i/columns)*w,y,x+(i/columns)*w,y+h); | |
} | |
var rows=columns>=1?Math.ceil(charCount/columns):charCount, | |
missing=(rows*columns)-charCount, | |
ylp=13; | |
for(var i=0;i<rows;i++){ | |
var yl=y+(i/rows)*h; | |
line(x,yl,x+w,yl); | |
yl+=ylp; | |
line(x,yl,i===rows-1?(x+w)-((w/columns)*missing):x+w,yl); | |
} | |
if(missing){ | |
noStroke();fill(255,32); | |
rect((x+w)-((missing/columns)*w),(y+h)-(h/rows),(missing/columns)*w,h/rows); | |
} | |
noStroke();fill(255); | |
textAlign(CENTER,TOP);textSize(10); | |
for(var yi=0;yi<rows;yi++){ | |
for(var xi=0;xi<columns;xi++){ | |
if((yi===rows-1)&&((yi*columns)+xi>=charCount)){break;} | |
text( | |
String.fromCharCode(fromChar+(yi*columns)+xi), | |
x+((xi+0.5)*(w/columns))-.5, | |
y+(yi*(h/rows))+2 | |
); | |
if(fromChar+(yi*columns)+xi in myFont.render){ | |
image( | |
myFont.render[fromChar+(yi*columns)+xi], | |
Math.floor(x+((xi+0.5)*(w/columns))-((myFont.w*myFont.renderSize)/2))-0.5, | |
Math.floor(y+(ylp/2)+((yi+0.5)*(h/rows))-((myFont.h*myFont.renderSize)/2))-0.5 | |
); | |
} | |
} | |
} | |
if(pointInRect(mouseX,mouseY,x,y,w,h)){ | |
noStroke();fill(255,64); | |
var s=clamp(Math.floor((mouseY-y)/(h/rows)),0,rows-1)*columns; | |
s+=clamp(Math.floor((mouseX-x)/(w/columns)),0,columns-1); | |
if(s<charCount){ | |
rect(x+((s%columns)*(w/columns)),y+(Math.floor(s/columns)*(h/rows)),w/columns,h/rows); | |
if(user.ASCIItableClicked&&mouseIsPressed){user.currentChar=fromChar+s;} | |
} | |
} | |
stroke(255,0,0);noFill(); | |
var s=user.currentChar-fromChar; | |
rect( | |
x+((s%columns)*(w/columns)), | |
y+(Math.floor(s/columns)*(h/rows)), | |
w/columns,h/rows | |
); | |
} | |
var user={ | |
click:false,releaseClick:false, | |
currentChar:65, | |
ASCIItableClicked:false, | |
editorClicked:false, | |
pen:1 | |
}; | |
function mousePressed(){user.click=true;} | |
function mouseReleased(){user.releaseClick=true;} | |
var myFont={ | |
w:3,h:5,char:{},render:{},renderSize:3 | |
}; | |
function renderChar(char){ | |
if(!(char in myFont.render)){ | |
myFont.render[char]=createGraphics(myFont.w*myFont.renderSize,myFont.h*myFont.renderSize); | |
} | |
if(myFont.render[char].width!==myFont.w*myFont.renderSize||myFont.render[char].height!==myFont.h*myFont.renderSize){ | |
myFont.render[char].resizeCanvas(myFont.w*myFont.renderSize,myFont.h*myFont.renderSize); | |
} | |
myFont.render[char].clear(); | |
//myFont.render[char].fill(255); | |
for(var yi=0;yi<myFont.h;yi++){ | |
for(var xi=0;xi<myFont.w;xi++){ | |
if(myFont.char[char][yi][xi]){ | |
myFont.render[char].drawingContext.fillRect( | |
xi*myFont.renderSize, | |
yi*myFont.renderSize, | |
myFont.renderSize, | |
myFont.renderSize | |
); | |
} | |
} | |
} | |
} | |
function drawEditor(x,y,pixelSize){ | |
stroke(255);noFill(); | |
rect(x,y,myFont.w*pixelSize,myFont.h*pixelSize); | |
var pointInEditor=pointInRect(mouseX,mouseY,x,y,myFont.w*pixelSize,myFont.h*pixelSize); | |
if(user.click){user.editorClicked=pointInEditor;} | |
if(user.editorClicked){ | |
if(!(user.currentChar in myFont.char)){ | |
myFont.char[user.currentChar]=[]; | |
for(var yi=0;yi<myFont.h;yi++){ | |
myFont.char[user.currentChar][yi]=[]; | |
for(var xi=0;xi<myFont.w;xi++){ | |
myFont.char[user.currentChar][yi].push(0); | |
} | |
} | |
} | |
} | |
if(user.currentChar in myFont.char){ | |
noStroke();fill(255); | |
if(user.editorClicked&&mouseIsPressed&&pointInEditor){ | |
var mx=clamp(Math.floor((mouseX-x)/pixelSize),0,myFont.w-1), | |
my=clamp(Math.floor((mouseY-y)/pixelSize),0,myFont.h-1); | |
if(user.click){user.pen=myFont.char[user.currentChar][my][mx]?0:1;} | |
myFont.char[user.currentChar][my][mx]=user.pen; | |
renderChar(user.currentChar); | |
} | |
for(var yi=0;yi<myFont.h;yi++){ | |
for(var xi=0;xi<myFont.w;xi++){ | |
if(myFont.char[user.currentChar][yi][xi]){ | |
rect(x+(xi*pixelSize),y+(yi*pixelSize),pixelSize,pixelSize); | |
} | |
} | |
} | |
} | |
stroke(255,user.currentChar in myFont.char?128:32); | |
for(var i=1;i<myFont.w;i++){line(x+(i*pixelSize),y,x+(i*pixelSize),y+(myFont.h*pixelSize));} | |
for(var i=1;i<myFont.h;i++){line(x,y+(i*pixelSize),x+(myFont.w*pixelSize),y+(i*pixelSize));} | |
} | |
class Button{ | |
constructor(string,x,y,w,h,f){ | |
this.x=x;this.y=y; | |
this.w=w;this.h=h; | |
this.string=string; | |
this.hold=false; | |
this.f=f; | |
} | |
render(){ | |
var inside=pointInRect(mouseX,mouseY,this.x,this.y,this.w,this.h); | |
stroke(255);fill(inside?64:0); | |
rect(this.x,this.y,this.w,this.h); | |
noStroke();fill(255); | |
textAlign(CENTER,CENTER);textSize(12); | |
text(this.string,this.x+(this.w/2),this.y+(this.h/2)); | |
if(inside&&user.click){ | |
this.hold=true; | |
} | |
if(this.hold&&user.releaseClick){ | |
if(inside){ | |
this.f(); | |
} | |
this.hold=false; | |
} | |
} | |
} | |
function pointInCircle(px,py,x,y,d){return Math.hypot(x-px,y-py)<(d/2);} | |
class Stepper{ | |
constructor(string,value,x,y,f=()=>{},min=1,max=16){ | |
this.string=string;this.value=value;this.x=x;this.y=y; | |
this.f=f; | |
this.min=min;this.max=max; | |
this.hover=0; | |
//this.hold=0; (this.value would react upon this as well) | |
} | |
render(){ | |
stroke(255); | |
var s=20,d=14,i=(d/2)-3; | |
this.hover=pointInCircle(mouseX,mouseY,this.x+s,this.y,d)?1:(pointInCircle(mouseX,mouseY,this.x-s,this.y,d)?-1:0); | |
fill((this.hover===-1)*128); | |
circle(this.x-s,this.y,d); | |
line((this.x-s)-i,this.y,(this.x-s)+i,this.y); | |
fill((this.hover===1)*128); | |
circle(this.x+s,this.y,d); | |
line((this.x+s)-i,this.y,(this.x+s)+i,this.y); | |
line(this.x+s,this.y-i,this.x+s,this.y+i); | |
if(this.hover!==0&&user.click){ | |
this.value=Math.max(Math.min(this.value+this.hover,this.max),this.min); | |
this.f(this.value); | |
} | |
noStroke();fill(255); | |
textAlign(CENTER,CENTER);textSize(16); | |
text(this.value,this.x,this.y+1); | |
textAlign(RIGHT,CENTER); | |
text(this.string+": ",this.x-(s+(d/2)),this.y+1); | |
} | |
} | |
function exportFont(){ | |
var char=Object.entries(myFont.char).map( | |
e=>[String.fromCharCode(e[0]),e[1].map(a=>a.reduce((b,c,i)=>b|(c<<i),0))] | |
); | |
console.log(JSON.stringify({width:myFont.w,height:myFont.h,font:Object.fromEntries(char)})); | |
} | |
function numberTo1BitArray(n,s){for(var a=[],i=0;i<s;i++){a[i]=n&1<<i?1:0;}return a;} | |
function importFont(object){ | |
myFont.w=object.width;myFont.h=object.height; | |
var char=Object.entries(object.font).map( | |
e=>[e[0].charCodeAt(0),e[1].map(a=>numberTo1BitArray(a,object.width))] | |
); | |
myFont.char=Object.fromEntries(char); | |
Object.keys(myFont.char).forEach(x=>{renderChar(x);}); | |
} | |
function createArray(s,v){for(var f=(typeof v==="function"),a=[],i=0;i<s;i++){a[i]=f?v(i):v;}return a;} | |
var expButton,newButton,delButton,copyButton,pasteButton,charCopy, | |
wStepper,hStepper; | |
function setup(){ | |
createCanvas(windowWidth,windowHeight); | |
expButton=new Button("Export",16,16+704+2,192,16,exportFont); | |
importFont({ | |
"width":3,"height":5,"font":{ | |
"0":[7,5,5,5,7],"1":[2,3,2,2,7],"2":[3,4,2,1,7],"3":[3,4,2,4,3], | |
"4":[5,5,7,4,4],"5":[7,1,3,4,3],"6":[6,1,7,5,7],"7":[7,4,2,2,2], | |
"8":[7,5,7,5,7],"9":[7,5,7,4,3],"!":[2,2,2,0,2],"\"":[5,5,0,0,0], | |
"#":[5,7,5,7,5],"$":[6,3,6,3,2],"%":[5,4,2,1,5],"&":[3,3,6,5,7], | |
"'":[2,2,0,0,0],"(":[4,2,2,2,4],")":[1,2,2,2,1],"*":[5,2,5,0,0], | |
"+":[0,2,7,2,0],",":[0,0,0,2,1],"-":[0,0,7,0,0],".":[0,0,0,0,2], | |
"/":[4,4,2,1,1],":":[0,2,0,2,0],";":[0,2,0,2,1],"<":[4,2,1,2,4], | |
"=":[0,7,0,7,0],">":[1,2,4,2,1],"?":[3,4,2,0,2],"@":[2,5,7,1,6], | |
"A":[2,5,7,5,5],"B":[3,5,3,5,3],"C":[6,1,1,1,6],"D":[3,5,5,5,3], | |
"E":[7,1,7,1,7],"F":[7,1,7,1,1],"G":[6,1,5,5,6],"H":[5,5,7,5,5], | |
"I":[7,2,2,2,7],"J":[4,4,4,5,2],"K":[5,5,3,5,5],"L":[1,1,1,1,7], | |
"M":[7,7,5,5,5],"N":[3,5,5,5,5],"O":[2,5,5,5,2],"P":[3,5,3,1,1], | |
"Q":[2,5,5,3,6],"R":[3,5,3,5,5],"S":[6,1,2,4,3],"T":[7,2,2,2,2], | |
"U":[5,5,5,5,7],"V":[5,5,5,5,2],"W":[5,5,5,7,7],"X":[5,5,2,5,5], | |
"Y":[5,5,2,2,2],"Z":[7,4,2,1,7],"[":[6,2,2,2,6],"\\":[1,1,2,4,4], | |
"]":[3,2,2,2,3],"^":[2,5,0,0,0],"_":[0,0,0,0,7],"`":[1,2,0,0,0], | |
"a":[0,0,3,4,7],"b":[1,1,3,5,3],"c":[0,0,6,1,6],"d":[4,4,6,5,6], | |
"e":[0,0,7,1,6],"f":[4,2,7,2,2],"g":[0,0,7,4,3],"h":[1,1,3,5,5], | |
"i":[2,0,3,2,2],"j":[2,0,2,2,1],"k":[1,1,5,3,5],"l":[3,2,2,2,4], | |
"m":[0,0,7,7,5],"n":[0,0,3,5,5],"o":[0,0,2,5,2],"p":[0,0,7,7,1], | |
"q":[0,0,7,7,4],"r":[0,0,5,3,1],"s":[0,0,6,2,3],"t":[2,2,7,2,4], | |
"u":[0,0,5,5,7],"v":[0,0,5,5,2],"w":[0,0,5,7,7],"x":[0,0,5,2,5], | |
"y":[0,0,5,6,3],"z":[0,0,3,2,6],"{":[6,2,3,2,6],"|":[2,2,2,2,2], | |
"}":[3,2,6,2,3],"~":[0,4,7,1,0] | |
}}); | |
newButton=new Button("New",16,16+704+2+16+2,192,16,()=>{ | |
myFont.char={};myFont.render={}; | |
}); | |
var x=16+192+2,y=16+17; //16+17+2+(64*myFont.h) | |
delButton=new Button("Delete",x,y,70,16,()=>{ | |
delete myFont.char[user.currentChar]; | |
delete myFont.render[user.currentChar]; | |
}); | |
x+=72; | |
copyButton=new Button("Copy",x,y,70,16,()=>{ | |
charCopy=JSON.stringify(myFont.char[user.currentChar]); | |
}); | |
x+=72; | |
pasteButton=new Button("Paste",x,y,70,16,()=>{ | |
if(charCopy){ | |
myFont.char[user.currentChar]=JSON.parse(charCopy); | |
renderChar(user.currentChar); | |
} | |
}); | |
x=16+192+2+85; | |
y+=16+9; | |
wStepper=new Stepper("Width",myFont.w,x,y,value=>{ | |
myFont.w=value; | |
for(var c in myFont.char){ | |
myFont.char[c].forEach(a=>{ | |
if(myFont.w>a.length){ | |
a.push(0); | |
}else if(myFont.w<a.length){ | |
a.pop(); | |
} | |
}); | |
renderChar(c); | |
} | |
}); | |
y+=16; | |
hStepper=new Stepper("Height",myFont.h,x,y,value=>{ | |
myFont.h=value; | |
for(var c in myFont.char){ | |
if(myFont.h>myFont.char[c].length){ | |
myFont.char[c].push(createArray(myFont.w,0)); | |
}else if(myFont.h<myFont.char[c].length){ | |
myFont.char[c].pop(); | |
} | |
renderChar(c); | |
} | |
}); | |
} | |
function drawFont(string,x,y,size=1){ | |
noStroke(); | |
var xs=0,ys=0; | |
for(var c,i=0;i<string.length;i++){ | |
c=string.charCodeAt(i); | |
if(c in myFont.char){ | |
for(var yi=0;yi<myFont.h;yi++){ | |
for(var xi=0;xi<myFont.w;xi++){ | |
if(myFont.char[c][yi][xi]){ | |
drawingContext.fillRect(x+(((xs*(myFont.w+1))+xi)*size),y+(((ys*(myFont.h+1))+yi)*size),size,size); | |
} | |
} | |
} | |
} | |
if(string[i]==="\n"){ | |
xs=0;ys++; | |
}else{ | |
xs++; | |
} | |
} | |
} | |
function draw(){ | |
background(0); | |
translate(.5,.5); | |
drawASCIItable(16,16,192,704,6); | |
noStroke();fill(255); | |
textAlign(LEFT,TOP);textSize(16); | |
text(`Current character: ${String.fromCharCode(user.currentChar)} (${user.currentChar})`,16+192+2,16); | |
drawEditor(16+192+2,16+17+51,64); | |
expButton.render(); | |
newButton.render(); | |
delButton.render(); | |
copyButton.render(); | |
pasteButton.render(); | |
wStepper.render();hStepper.render(); | |
drawFont("A quick brown fox jumps over the lazy dog.\nA QUICK BROWN FOX JUMPS OVER THE LAZY DOG!",450-.5,16-.5,2); | |
user.click=false;user.releaseClick=false; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment