const canvas = document.querySelector("#canvas");
const selectedDiv = document.querySelector("#selected");
const charlistTable = document.querySelector("#charlist");
const exportButton = document.querySelector("#export");
const exportAreaCode = document.querySelector("#export-area");
const [width, height] = [400, 400];
canvas.width = width;
canvas.height = height;
canvas.style.width = width + "px";
canvas.style.height = height + "px";
const g = canvas.getContext("2d");
g.imageSmoothingEnabled = false;
const state = new Array(64).fill(false);
function render() {
g.fillStyle = "black";
g.fillRect(0, 0, width, height);
g.fillStyle = "white";
for (let y = 0; y < 8; ++y) {
for (let x = 0; x < 8; ++x) {
if (state[y * 8 + x]) {
g.fillRect(
x * (width / 8),
y * (height / 8),
width / 8,
height / 8,
);
}
}
}
renderGrid();
}
function renderGrid() {
g.strokeStyle = "gray";
g.lineWidth = 1;
g.beginPath();
for (let y = 0; y < 8; ++y) {
for (let x = 0; x < 8; ++x) {
g.moveTo(x * (width / 8), 0);
g.lineTo(x * (width / 8), height);
g.moveTo(0, y * (height / 8));
g.lineTo(width, y * (height / 8));
}
}
g.moveTo(width - 1, 0);
g.lineTo(width - 1, height);
g.moveTo(0, height - 1);
g.lineTo(width, height - 1);
g.stroke();
}
const specialChars = Object.fromEntries(
Object.entries({
"\0": "0",
"\n": "n",
"\r": "r",
"\t": "t",
}).map(([ch, r]) => [ch.charCodeAt(0), "\\" + r]),
);
const chars = new Array(127).fill(0).map((_, i) => ({
i,
ch: specialChars[i] ?? (i > 31 ? String.fromCharCode(i) : ""),
hex: new Array(8).fill(0),
}));
let selected = { i: 0, ch: "\0", hex: new Array(8).fill(0) };
function stateToHex(state) {
let hex = new Array(8).fill(0);
for (let y = 0; y < 8; ++y) {
let byte = 0;
for (let x = 0; x < 8; ++x) {
if (state[y * 8 + x]) {
byte |= 1 << 7 - x;
}
}
hex[y] = byte;
}
return hex;
}
function stateFromHex(state, hex) {
for (let y = 0; y < 8; ++y) {
for (let x = 0; x < 8; ++x) {
state[y * 8 + x] = (hex[y] >> 7 - x & 1) != 0;
}
}
}
function html(strings, ...values) {
return strings[0] +
strings.slice(1).map((v, i) => values[i].toString() + v).join("");
}
function renderSelectedChar() {
const { i, ch, hex } = selected;
selectedDiv.innerHTML = html`
${i}
${ch}
0x${hex.map((v) => v.toString(16).padStart(2, "0")).join(
"",
)}
`;
document.querySelector("#selected-save")
.onclick = () => {
const overwrite = document.querySelector("#overwrite").value;
if (overwrite) {
const hex = new Array(8).fill(0);
for (let i = 0; i < 8; ++i) {
hex[i] = parseInt(
overwrite.slice(i * 2 + 2, i * 2 + 4),
16,
);
}
chars[selected.i].hex = hex;
selected.hex = hex.map((v) => v);
stateFromHex(state, hex);
renderCharlist();
renderSelectedChar();
render();
} else {
chars[selected.i].hex = selected.hex.map((v) => v);
renderCharlist();
}
};
}
function renderCharlist() {
charlistTable.innerHTML = html`
${i}${ch}0x${hex.map((v) =>
v.toString(16).padStart(2, "0")
).join("")}