Compare commits
80 Commits
initial-id
...
deno-test-
Author | SHA1 | Date | |
---|---|---|---|
401a76da84 | |||
694eb006b9 | |||
f8c1cebedb | |||
04f206814c | |||
ae3fa89a8b | |||
79738cfb79 | |||
d7fec98714 | |||
6dc5127926 | |||
e955a4c00d | |||
b394f81477 | |||
ef8cb2c4cf | |||
d68a207df6 | |||
26c0ff590c | |||
38eabd380a | |||
90b97a30bd | |||
292d1d365e | |||
f8b3f5d645 | |||
194209f18f | |||
1211891f53 | |||
2ac5f3dff7 | |||
b248a016a9 | |||
7f9e873323 | |||
e5276de775 | |||
a7ed7b87f2 | |||
8c750ac2dc | |||
ad5acdeb12 | |||
107a5370b1 | |||
5ed92b5ff4 | |||
c53373ea47 | |||
87d3e6fc9b | |||
cc03a0e765 | |||
fcf78f3d56 | |||
5760a3f03b | |||
6bd5f7ae01 | |||
3518538b39 | |||
86d8a8b166 | |||
13b600eb95 | |||
9f67a59033 | |||
64c889e16a | |||
471fa9e0b6 | |||
0adfdabffa | |||
2e3b689c16 | |||
24bed7bd89 | |||
5d4db0a914 | |||
60542b63c0 | |||
7bf0838e4e | |||
550f1b44b2 | |||
3ad23f3a91 | |||
9685568f90 | |||
b02d5155bd | |||
4b99599b31 | |||
12bc0cb385 | |||
1fa58961fc | |||
99eb6b82f2 | |||
5e4b76ebb3 | |||
9d2dc99a32 | |||
a3abb0d2d3 | |||
6c9710d4d9 | |||
f2b5978cae | |||
b87529bf56 | |||
b58a0d8cb1 | |||
99655e663c | |||
2e8923e2e7 | |||
e52c8c69a0 | |||
1e91232bd6 | |||
6b90d883e9 | |||
2a7003b443 | |||
dca54e76ec | |||
ce7da27cc3 | |||
1482288b0c | |||
7de521bd39 | |||
99a8c500c7 | |||
253b8e9567 | |||
fdc8f97aee | |||
a7b675d541 | |||
5d742d5964 | |||
1781ae3bba | |||
078b7806dd | |||
e85dbb1a33 | |||
d7c2d5adb9 |
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
build
|
4
.vscode/settings.json
vendored
Normal file
4
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"deno.enable": true,
|
||||
"deno.unstable": true
|
||||
}
|
11
README.md
11
README.md
@ -1,2 +1,13 @@
|
||||
# fantasy-console
|
||||
|
||||
To run,
|
||||
```
|
||||
deno task run
|
||||
```
|
||||
|
||||
To compile
|
||||
```
|
||||
deno task build
|
||||
```
|
||||
|
||||
You may need to install `xsel` on Linux machines to use this.
|
195
builtins.ts
Normal file
195
builtins.ts
Normal file
@ -0,0 +1,195 @@
|
||||
import {
|
||||
setPixelsInRect,
|
||||
clearScreen,
|
||||
fillRect,
|
||||
cameraPos,
|
||||
fillCircle,
|
||||
outlineCircle,
|
||||
fillEllipse,
|
||||
outlineEllipse,
|
||||
setPixelColor,
|
||||
} from "./window.ts";
|
||||
import { CHAR, Font, font } from "./font.ts";
|
||||
import { K, keyDown, keyPressed, keyReleased } from "./keyboard.ts";
|
||||
import { addToContext, runCode } from "./runcode.ts";
|
||||
import { resetRepl } from "./repl.ts";
|
||||
import { COLOR } from "./colors.ts";
|
||||
import { getSheet, getCodeSheet, getMapSheet } from "./sheet.ts";
|
||||
import { saveCart, loadCart } from "./cart.ts";
|
||||
import { outlineRect } from "./util.ts";
|
||||
|
||||
let spritesheet: number | null = null;
|
||||
|
||||
export const getSpritesheet = () => {
|
||||
return spritesheet;
|
||||
}
|
||||
|
||||
export const useSpritesheet = (sheet: number) => {
|
||||
spritesheet = sheet;
|
||||
}
|
||||
|
||||
export const drawSprite = (x: number, y: number, spr: number) => {
|
||||
if (!spritesheet) {
|
||||
return;
|
||||
}
|
||||
const {sheet_type, value: sprites} = getSheet(spritesheet);
|
||||
if (sheet_type !== "spritesheet") {
|
||||
throw "Trying to run a non-code sheet as code."
|
||||
}
|
||||
setPixelsInRect(x, y, 8, sprites[spr]);
|
||||
}
|
||||
|
||||
export const drawIcon = (x: number, y: number, icon: Array<number>, color: number) => {
|
||||
setPixelsInRect(x, y, 8, icon.map(n => n*color));
|
||||
}
|
||||
|
||||
export const measureCharFont = (char: string, fnt: Font) => {
|
||||
return (fnt.chars[char]?.length ?? 0)/fnt.height;
|
||||
}
|
||||
|
||||
export const drawCharFont = (x: number, y: number, char: string, fnt: Font, color: number) => {
|
||||
const w = measureCharFont(char, fnt);
|
||||
if (!fnt.chars[char]) {
|
||||
return 0;
|
||||
}
|
||||
setPixelsInRect(x, y, w, fnt.chars[char].map(n => n*color));
|
||||
return w;
|
||||
}
|
||||
|
||||
export const drawTextFont = (x: number, y: number, text: string, fnt: Font, color?: number) => {
|
||||
let dx = 0;
|
||||
[...text].forEach((char) => {
|
||||
dx += 1+drawCharFont(x+dx, y, char, fnt, color ?? COLOR.WHITE);
|
||||
});
|
||||
return dx-1;
|
||||
}
|
||||
|
||||
export const measureTextFont = (text: string, fnt: Font) => {
|
||||
let w = 0;
|
||||
[...text].forEach((char) => {
|
||||
w += measureCharFont(char, fnt)+1;
|
||||
});
|
||||
return Math.max(0, w-1);
|
||||
}
|
||||
|
||||
export const drawText = (x: number, y: number, text: string, color?: number) => {
|
||||
return drawTextFont(x, y, text, font, color);
|
||||
}
|
||||
|
||||
export const measureText = (text: string) => {
|
||||
return measureTextFont(text, font);
|
||||
}
|
||||
|
||||
export const camera = (x: number, y: number) => {
|
||||
cameraPos.x = x;
|
||||
cameraPos.y = y;
|
||||
};
|
||||
|
||||
const faux = {
|
||||
// Graphics
|
||||
cls: () => {
|
||||
resetRepl();
|
||||
clearScreen();
|
||||
},
|
||||
camera,
|
||||
sprsht: useSpritesheet,
|
||||
spr: drawSprite,
|
||||
txt: drawText,
|
||||
rectfill: fillRect,
|
||||
rect: outlineRect,
|
||||
circfill: fillCircle,
|
||||
circ: outlineCircle,
|
||||
ovalfill: fillEllipse,
|
||||
oval: outlineEllipse,
|
||||
pset: setPixelColor,
|
||||
map: (mapSheet: number, tileX: number, tileY: number, screenX: number, screenY: number, tileW: number, tileH: number) => {
|
||||
const originalSpritesheet = getSpritesheet() ?? 0;
|
||||
getMapSheet(mapSheet).values.forEach(([sprSheet, spr], i) => {
|
||||
const x = i%64;
|
||||
const y = Math.floor(i/64);
|
||||
if (x >= tileX && y >= tileY && x < tileX + tileW && y < tileY + tileH) {
|
||||
useSpritesheet(sprSheet);
|
||||
drawSprite(screenX + (x-tileX)*8, screenY + (y-tileY)*8, spr);
|
||||
}
|
||||
});
|
||||
useSpritesheet(originalSpritesheet);
|
||||
},
|
||||
// Map
|
||||
mgetsht: (mapSheet: number, x: number, y: number) => {
|
||||
if (x < 0 || x >= 64 || y < 0 || y >= 64) {
|
||||
return undefined;
|
||||
}
|
||||
return getMapSheet(mapSheet).get(x, y)[0];
|
||||
},
|
||||
mgetspr: (mapSheet: number, x: number, y: number) => {
|
||||
if (x < 0 || x >= 64 || y < 0 || y >= 64) {
|
||||
return undefined;
|
||||
}
|
||||
return getMapSheet(mapSheet).get(x, y)[1];
|
||||
},
|
||||
mset: (mapSheet: number, x: number, y: number, sprSheet: number, spr: number) => {
|
||||
if (x < 0 || x >= 64 || y < 0 || y >= 64) {
|
||||
return;
|
||||
}
|
||||
getMapSheet(mapSheet).set(x, y, [sprSheet, spr]);
|
||||
},
|
||||
// Input
|
||||
[CHAR.UP]: K.ARROW_UP,
|
||||
[CHAR.DOWN]: K.ARROW_DOWN,
|
||||
[CHAR.LEFT]: K.ARROW_LEFT,
|
||||
[CHAR.RIGHT]: K.ARROW_RIGHT,
|
||||
btn: keyDown,
|
||||
btnp: keyPressed,
|
||||
btnr: keyReleased,
|
||||
// Cart
|
||||
save: saveCart,
|
||||
load: loadCart,
|
||||
// JS
|
||||
Array,
|
||||
BigInt: BigInt,
|
||||
Boolean,
|
||||
Date,
|
||||
Error,
|
||||
Function,
|
||||
Infinity: Infinity,
|
||||
JSON: JSON,
|
||||
Map,
|
||||
NaN: NaN,
|
||||
Number,
|
||||
Object,
|
||||
Promise,
|
||||
Proxy,
|
||||
Reflect: Reflect,
|
||||
RegExp,
|
||||
Set,
|
||||
String,
|
||||
Symbol: Symbol,
|
||||
WeakMap,
|
||||
WeakRef,
|
||||
WeakSet,
|
||||
isFinite,
|
||||
isNaN,
|
||||
// Math
|
||||
max: Math.max,
|
||||
min: Math.min,
|
||||
floor: Math.floor,
|
||||
ceil: Math.ceil,
|
||||
sin: Math.sin,
|
||||
cos: Math.cos,
|
||||
atan2: Math.atan2,
|
||||
sqrt: Math.sqrt,
|
||||
abs: Math.abs,
|
||||
rand: Math.random,
|
||||
[CHAR.PI]: Math.PI,
|
||||
// Other
|
||||
code: (n: number) => {
|
||||
return runCode(getCodeSheet(n));
|
||||
},
|
||||
log: console.log,
|
||||
};
|
||||
|
||||
for (const key in faux) {
|
||||
addToContext(key, faux[key as keyof typeof faux]);
|
||||
}
|
||||
|
||||
export default faux;
|
22
cart.ts
Normal file
22
cart.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import { path } from "./deps.ts";
|
||||
import initialCart from "./initialCart.json" assert { type: "json" };
|
||||
import { Sheet } from "./sheet.ts";
|
||||
|
||||
let cart = initialCart as Array<Sheet>;
|
||||
|
||||
const virtualPathToRealPath = (virtualFname: string) => {
|
||||
const realPath = path.join(".", "carts", ...virtualFname.split("/"));
|
||||
return realPath;
|
||||
}
|
||||
|
||||
export const saveCart = async (fname: string) => {
|
||||
await Deno.writeTextFile(virtualPathToRealPath(fname+".fx"), JSON.stringify(getCart()));
|
||||
}
|
||||
|
||||
export const loadCart = async (fname: string) => {
|
||||
cart = JSON.parse(await Deno.readTextFile(virtualPathToRealPath(fname+".fx")));
|
||||
}
|
||||
|
||||
export const getCart = () => {
|
||||
return cart;
|
||||
}
|
1
carts/empty.fx
Normal file
1
carts/empty.fx
Normal file
@ -0,0 +1 @@
|
||||
[{"sheet_type":"code","value":""},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null}]
|
707
carts/test.fx
Normal file
707
carts/test.fx
Normal file
@ -0,0 +1,707 @@
|
||||
[
|
||||
{
|
||||
"sheet_type": "code",
|
||||
"value": "x = code(1);\nreturn {\n\tinit: () => {y = 0},\n\tupdate: () => {\n\t\ty += speed;\n\t\tif (y > 127) {\n\t\t\ty = -6\n\t\t}\n\t},\n\tdraw: () => {\n\t\tcls();\n\t\ttxt(x, y, 'hello world')\n\t}\n}"
|
||||
},
|
||||
{
|
||||
"sheet_type": "code",
|
||||
"value": "sprsht(15);\nspeed = 2;\nreturn 8;"
|
||||
},
|
||||
{
|
||||
"sheet_type": "none",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"sheet_type": "none",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"sheet_type": "none",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"sheet_type": "none",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"sheet_type": "none",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"sheet_type": "none",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"sheet_type": "none",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"sheet_type": "none",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"sheet_type": "none",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"sheet_type": "none",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"sheet_type": "none",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"sheet_type": "none",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"sheet_type": "none",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"sheet_type": "spritesheet",
|
||||
"value": [
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 2, 0, 0, 2, 0, 0,
|
||||
0, 0, 0, 2, 2, 0, 0, 0,
|
||||
0, 0, 0, 2, 2, 0, 0, 0,
|
||||
0, 0, 2, 0, 0, 2, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 3, 3, 1, 1, 3, 3, 1,
|
||||
1, 3, 3, 1, 1, 3, 3, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 3, 3, 1, 1, 3, 3, 1,
|
||||
1, 3, 3, 1, 1, 3, 3, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1
|
||||
],
|
||||
[
|
||||
6, 6, 6, 4, 4, 4, 5, 5,
|
||||
6, 6, 4, 4, 4, 5, 5, 5,
|
||||
6, 4, 4, 4, 5, 5, 5, 6,
|
||||
4, 4, 4, 5, 5, 5, 6, 6,
|
||||
4, 4, 5, 5, 5, 6, 6, 6,
|
||||
4, 5, 5, 5, 6, 6, 6, 4,
|
||||
5, 5, 5, 6, 6, 6, 4, 4,
|
||||
5, 5, 6, 6, 6, 4, 4, 4
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
],
|
||||
[
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
1
carts/tmp/circ.fx
Normal file
1
carts/tmp/circ.fx
Normal file
@ -0,0 +1 @@
|
||||
[{"sheet_type":"code","value":"// Sample\n\nlet r = 0;\nlet d = 1;\nreturn {\n\tinit() {},\n\tupdate() {\n\t\tif (r >= 20) {\n\t\t\td = -1;\n\t\t} else if (r < 0) {\n\t\t\td = 1;\n\t\t}\n\t\tr += d*0.1;\t\n\t},\n\tdraw() {\n\t\tcls();\n\t\tcirc(50, 50, 6, 17);\n\t\ttxt(10,10,\"Hello, World!\");\n\t}\n}"},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null}]
|
1
carts/tmp/cyandino.fx
Normal file
1
carts/tmp/cyandino.fx
Normal file
File diff suppressed because one or more lines are too long
1
carts/tmp/maptest.fx
Normal file
1
carts/tmp/maptest.fx
Normal file
File diff suppressed because one or more lines are too long
1
carts/tmp/oval.fx
Normal file
1
carts/tmp/oval.fx
Normal file
@ -0,0 +1 @@
|
||||
[{"sheet_type":"code","value":"// Sample\n\nlet r = 0;\nlet d = 1;\nreturn {\n\tinit() {},\n\tupdate() {\n\t\tif (r >= 20) {\n\t\t\td = -1;\n\t\t} else if (r < 0) {\n\t\t\td = 1;\n\t\t}\n\t\tr += d*0.1;\t\n\t},\n\tdraw() {\n\t\tcls();\n\t\trectfill(50,50,46,21,6);\n\t\toval(50, 50, 95, 70, 17);\n\t\ttxt(10,10,\"Hello, World!\");\n\t}\n}"},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null}]
|
1
carts/tmp/pa6.fx
Normal file
1
carts/tmp/pa6.fx
Normal file
File diff suppressed because one or more lines are too long
1
carts/tmp/pa7.fx
Normal file
1
carts/tmp/pa7.fx
Normal file
File diff suppressed because one or more lines are too long
1
carts/tmp/playingaround.fx
Normal file
1
carts/tmp/playingaround.fx
Normal file
@ -0,0 +1 @@
|
||||
[{"sheet_type":"code","value":"\nx = 0;\nbool = true;\nstring = \"hi\";\n\nreturn {\n\tinit() {\n\t\t// init\n\t},\n\tupdate() {\n\t\t// update\n\t},\n\tdraw() {\n\t\t// draw\n\t\tcls();\n\t\ttxt(20, 20, \"hello, world\");\n\t}\n}"},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null}]
|
1
carts/tmp/playingaround2.fx
Normal file
1
carts/tmp/playingaround2.fx
Normal file
@ -0,0 +1 @@
|
||||
[{"sheet_type":"code","value":"\nx = 0;\nbool = true;\nstring = \"hi\";\ntext = code(1);\n\nreturn {\n\tinit() {\n\t\t// init\n\t},\n\tupdate() {\n\t\t// update\n\t},\n\tdraw() {\n\t\t// draw\n\t\tcls();\n\t\ttxt(20, 20, text);\n\t}\n}"},{"sheet_type":"code","value":"return \"hi from sheet 01.\";"},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null}]
|
1
carts/tmp/playingaround3.fx
Normal file
1
carts/tmp/playingaround3.fx
Normal file
File diff suppressed because one or more lines are too long
1
carts/tmp/playingaround4.fx
Normal file
1
carts/tmp/playingaround4.fx
Normal file
File diff suppressed because one or more lines are too long
1
carts/tmp/playingaround5.fx
Normal file
1
carts/tmp/playingaround5.fx
Normal file
File diff suppressed because one or more lines are too long
1
carts/tmp/some_sprites.fx
Normal file
1
carts/tmp/some_sprites.fx
Normal file
File diff suppressed because one or more lines are too long
694
codetab.ts
Normal file
694
codetab.ts
Normal file
@ -0,0 +1,694 @@
|
||||
import { clearScreen, fillRect } from "./window.ts";
|
||||
import { CHAR, font } from "./font.ts";
|
||||
import { drawText, measureText } from "./builtins.ts";
|
||||
import { COLOR } from "./colors.ts";
|
||||
import { getCodeSheet, setSheet } from "./sheet.ts";
|
||||
import { K, ctrlKeyDown, getKeyboardString, keyPressed, shiftKeyDown } from "./keyboard.ts";
|
||||
import { clipboard, tokenize } from "./deps.ts";
|
||||
import { getBuiltins } from "./runcode.ts";
|
||||
import { page } from "./viewsheets.ts";
|
||||
import { mouseDown, mouseHeld, mousePos } from "./mouse.ts";
|
||||
|
||||
const historyDebounceFrames = 20;
|
||||
|
||||
const fontHeight = font.height;
|
||||
|
||||
const keywords = [
|
||||
"break",
|
||||
"case",
|
||||
"catch",
|
||||
"class",
|
||||
"const",
|
||||
"continue",
|
||||
"debugger",
|
||||
"default",
|
||||
"delete",
|
||||
"do",
|
||||
"else",
|
||||
"export",
|
||||
"extends",
|
||||
"finally",
|
||||
"for",
|
||||
"function",
|
||||
"if",
|
||||
"import",
|
||||
"in",
|
||||
"instanceof",
|
||||
"new",
|
||||
"return",
|
||||
"super",
|
||||
"switch",
|
||||
"this",
|
||||
"throw",
|
||||
"try",
|
||||
"typeof",
|
||||
"var",
|
||||
"void",
|
||||
"while",
|
||||
"with",
|
||||
"let",
|
||||
"static",
|
||||
"yield",
|
||||
"await",
|
||||
"enum",
|
||||
"implements",
|
||||
"interface",
|
||||
"package",
|
||||
"private",
|
||||
"protected",
|
||||
"public",
|
||||
"=>",
|
||||
];
|
||||
const values = [
|
||||
"false",
|
||||
"null",
|
||||
"true",
|
||||
"undefined",
|
||||
"NaN",
|
||||
"Infinity",
|
||||
CHAR.PI,
|
||||
];
|
||||
const operator = [
|
||||
"&&",
|
||||
"||",
|
||||
"??",
|
||||
"--",
|
||||
"++",
|
||||
".",
|
||||
"?.",
|
||||
"<",
|
||||
"<=",
|
||||
">",
|
||||
">=",
|
||||
"!=",
|
||||
"!==",
|
||||
"==",
|
||||
"===",
|
||||
"+",
|
||||
"-",
|
||||
"%",
|
||||
"&",
|
||||
"|",
|
||||
"^",
|
||||
"/",
|
||||
"*",
|
||||
"**",
|
||||
"<<",
|
||||
">>",
|
||||
">>>",
|
||||
"=",
|
||||
"+=",
|
||||
"-=",
|
||||
"%=",
|
||||
"&=",
|
||||
"|=",
|
||||
"^=",
|
||||
"/=",
|
||||
"*=",
|
||||
"**=",
|
||||
"<<=",
|
||||
">>=",
|
||||
">>>=",
|
||||
"!",
|
||||
"?",
|
||||
"~",
|
||||
"...",
|
||||
];
|
||||
const punctuation = [
|
||||
"(",
|
||||
")",
|
||||
"[",
|
||||
"]",
|
||||
"{",
|
||||
"}",
|
||||
".",
|
||||
":",
|
||||
";",
|
||||
",",
|
||||
];
|
||||
|
||||
const builtinColor = COLOR.BLUE;
|
||||
const keywordColor = COLOR.PURPLE;
|
||||
const operatorColor = COLOR.CYAN;
|
||||
const valueColor = COLOR.ORANGE;
|
||||
const stringColor = COLOR.GREEN;
|
||||
const regexColor = COLOR.PINK;
|
||||
const punctuationColor = COLOR.LIGHTGRAY;
|
||||
const commentColor = COLOR.DARKGREEN;
|
||||
const identifierColor = COLOR.YELLOW;
|
||||
const invalidColor = COLOR.RED;
|
||||
|
||||
const caretColor = COLOR.WHITE;
|
||||
const selectionColor = COLOR.DARKBLUE;
|
||||
|
||||
const backgroundColor = COLOR.DARKERBLUE;
|
||||
|
||||
const tokenColors = {
|
||||
"StringLiteral": stringColor,
|
||||
"NoSubstitutionTemplate": stringColor,
|
||||
"TemplateHead": stringColor,
|
||||
"TemplateMiddle": stringColor,
|
||||
"TemplateTail": stringColor,
|
||||
"RegularExpressionLiteral": regexColor,
|
||||
"MultiLineComment": commentColor,
|
||||
"SingleLineComment": commentColor,
|
||||
"IdentifierName": identifierColor,
|
||||
"PrivateIdentifier": identifierColor,
|
||||
"NumericLiteral": valueColor,
|
||||
"Punctuator": punctuationColor,
|
||||
"WhiteSpace": punctuationColor,
|
||||
"LineTerminatorSequence": punctuationColor,
|
||||
"Invalid": invalidColor,
|
||||
}
|
||||
|
||||
const transformForCopy = (text: string) => {
|
||||
text = text.replaceAll(CHAR.UP, "⬆️");
|
||||
text = text.replaceAll(CHAR.LEFT, "⬅️");
|
||||
text = text.replaceAll(CHAR.DOWN, "⬇️");
|
||||
text = text.replaceAll(CHAR.RIGHT, "➡️");
|
||||
return text;
|
||||
}
|
||||
|
||||
const transformForPaste = (text: string) => {
|
||||
let newstr = "";
|
||||
text = text.replaceAll("⬆️", CHAR.UP);
|
||||
text = text.replaceAll("⬅️", CHAR.LEFT);
|
||||
text = text.replaceAll("⬇️", CHAR.DOWN);
|
||||
text = text.replaceAll("➡️", CHAR.RIGHT);
|
||||
for (const char of text) {
|
||||
if (char in font.chars) {
|
||||
newstr += char;
|
||||
}
|
||||
}
|
||||
return newstr;
|
||||
}
|
||||
|
||||
const state = {
|
||||
doubleClickTimer: 0,
|
||||
history: [] as Array<{code: string, anchor: number, focus: number}>,
|
||||
historyDebounce: 0,
|
||||
historyIndex: 0,
|
||||
undo() {
|
||||
console.log('undoing');
|
||||
if (this.historyIndex === this.history.length && this.historyDebounce > 0) {
|
||||
this.snapshot();
|
||||
}
|
||||
console.log('historyIndex', this.historyIndex);
|
||||
if (this.historyIndex > 0) {
|
||||
this.historyIndex -= 1;
|
||||
const snap = this.history[this.historyIndex];
|
||||
console.log('historyIndex', this.historyIndex);
|
||||
this.code = snap.code;
|
||||
this.setSelection(snap.anchor, snap.focus);
|
||||
}
|
||||
},
|
||||
redo() {
|
||||
console.log('redoing');
|
||||
if (this.historyIndex < this.history.length-1) {
|
||||
this.historyIndex += 1;
|
||||
const snap = this.history[this.historyIndex];
|
||||
this.code = snap.code;
|
||||
this.setSelection(snap.anchor, snap.focus);
|
||||
}
|
||||
},
|
||||
snapshot() {
|
||||
const snap = {
|
||||
code: this.code,
|
||||
anchor: this.anchor,
|
||||
focus: this.focus,
|
||||
};
|
||||
this.history.push(snap);
|
||||
console.log('took snapshot', this.historyIndex, snap);
|
||||
},
|
||||
startSnapping() {
|
||||
console.log('start snapping', this.historyIndex);
|
||||
if (this.historyDebounce <= 0) {
|
||||
this.historyIndex += 1;
|
||||
}
|
||||
if (this.history.length > this.historyIndex) {
|
||||
this.history.length = this.historyIndex;
|
||||
}
|
||||
this.historyDebounce = historyDebounceFrames;
|
||||
},
|
||||
wordMode: false,
|
||||
scrollX: 0,
|
||||
scrollY: 0,
|
||||
anchor: 0,
|
||||
focus: 0,
|
||||
get focusX() {return indexToGrid(this.code, this.focus).x;},
|
||||
get focusY() {return indexToGrid(this.code, this.focus).y;},
|
||||
get anchorX() {return indexToGrid(this.code, this.anchor).x;},
|
||||
get anchorY() {return indexToGrid(this.code, this.anchor).y;},
|
||||
get focusPixelX() {return indexToRect(this.code, this.focus).x;},
|
||||
get focusPixelY() {return indexToRect(this.code, this.focus).y;},
|
||||
get anchorPixelX() {return indexToRect(this.code, this.anchor).x;},
|
||||
get anchorPixelY() {return indexToRect(this.code, this.anchor).y;},
|
||||
isCollapsed() {
|
||||
return this.anchor === this.focus;
|
||||
},
|
||||
clampInRange(n: number) {
|
||||
return Math.max(0, Math.min(n, this.code.length))
|
||||
},
|
||||
findNearestWordBoundaryLeft(index: number) {
|
||||
if (index === this.code.length-1) {
|
||||
return index;
|
||||
}
|
||||
const words1 = this.code.slice(0, index+1).split(/\b/g);
|
||||
if (words1[words1.length-1].length === 1) {
|
||||
return index;
|
||||
}
|
||||
const words = this.code.slice(0, index).split(/\b/g);
|
||||
if (!words.length) {
|
||||
return 0;
|
||||
}
|
||||
return index-words[words.length-1].length;
|
||||
},
|
||||
findNearestWordBoundaryRight(index: number) {
|
||||
if (index === 0) {
|
||||
return index;
|
||||
}
|
||||
const words1 = this.code.slice(index-1).split(/\b/g);
|
||||
if (words1[0].length === 1) {
|
||||
return index;
|
||||
}
|
||||
const words = this.code.slice(index).split(/\b/g);
|
||||
if (!words.length) {
|
||||
return this.code.length;
|
||||
}
|
||||
return index+words[0].length;
|
||||
},
|
||||
setSelection(anchor: number | {x: number, y: number}, focus?: number | {x: number, y: number}) {
|
||||
if (typeof anchor !== "number") {
|
||||
anchor = gridToIndex(this.code, anchor.x, anchor.y);
|
||||
}
|
||||
focus = focus ?? anchor;
|
||||
if (typeof focus !== "number") {
|
||||
focus = gridToIndex(this.code, focus.x, focus.y);
|
||||
}
|
||||
this.anchor = this.clampInRange(anchor);
|
||||
this.focus = this.clampInRange(focus);
|
||||
if (this.wordMode) {
|
||||
console.log('word mode', this.anchor, this.focus, this.findNearestWordBoundaryLeft(this.anchor), this.findNearestWordBoundaryRight(this.focus));
|
||||
if (this.anchor <= this.focus) {
|
||||
this.anchor = this.findNearestWordBoundaryLeft(this.anchor);
|
||||
this.focus = this.findNearestWordBoundaryRight(this.focus);
|
||||
} else {
|
||||
this.anchor = this.findNearestWordBoundaryRight(this.anchor);
|
||||
this.focus = this.findNearestWordBoundaryLeft(this.focus);
|
||||
}
|
||||
}
|
||||
this.anchor = this.clampInRange(this.anchor);
|
||||
this.focus = this.clampInRange(this.focus);
|
||||
},
|
||||
setFocus(focus: number | {x: number, y: number}) {
|
||||
if (typeof focus !== "number") {
|
||||
focus = gridToIndex(this.code, focus.x, focus.y);
|
||||
}
|
||||
this.focus = this.clampInRange(focus);
|
||||
if (this.wordMode) {
|
||||
if (this.anchor <= this.focus) {
|
||||
this.anchor = this.findNearestWordBoundaryLeft(this.anchor);
|
||||
this.focus = this.findNearestWordBoundaryRight(this.focus);
|
||||
} else {
|
||||
this.anchor = this.findNearestWordBoundaryRight(this.anchor);
|
||||
this.focus = this.findNearestWordBoundaryLeft(this.focus);
|
||||
}
|
||||
}
|
||||
this.focus = this.clampInRange(this.focus);
|
||||
},
|
||||
insertText(text: string) {
|
||||
const {code, anchor, focus} = this;
|
||||
this.code = code.slice(0, Math.min(anchor, focus)) + text + code.slice(Math.max(anchor, focus));
|
||||
this.setSelection(Math.min(anchor, focus) + text.length);
|
||||
this.startSnapping();
|
||||
},
|
||||
toggleComment() {
|
||||
const lines = this.code.split("\n");
|
||||
const {focusX, focusY, anchorX, anchorY} = this;
|
||||
const lineInSelection = (i: number) => i >= Math.min(focusY, anchorY) && i <= Math.max(focusY, anchorY);
|
||||
const allLinesAreCommented = lines.every((line, i) => {
|
||||
if (lineInSelection(i) && !line.trim().startsWith("// ")) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
const newLines = lines.map((line, i) => {
|
||||
if (lineInSelection(i)) {
|
||||
if (allLinesAreCommented) {
|
||||
return line.slice(3);
|
||||
} else {
|
||||
return "// "+line;
|
||||
}
|
||||
} else {
|
||||
return line;
|
||||
}
|
||||
});
|
||||
this.code = newLines.join("\n");
|
||||
const shiftBy = allLinesAreCommented ? -3 : 3;
|
||||
this.setSelection({x: anchorX+shiftBy, y: anchorY}, {x: focusX+shiftBy, y: focusY});
|
||||
this.startSnapping();
|
||||
},
|
||||
indent(indentString: string) {
|
||||
const lines = this.code.split("\n");
|
||||
const {focusX, focusY, anchorX, anchorY} = this;
|
||||
const newLines = lines.map((line, i) => {
|
||||
if (i >= Math.min(focusY, anchorY) && i <= Math.max(focusY, anchorY)) {
|
||||
return indentString+line;
|
||||
} else {
|
||||
return line;
|
||||
}
|
||||
});
|
||||
this.code = newLines.join("\n");
|
||||
this.setSelection({x: anchorX+1, y: anchorY}, {x: focusX+1, y: focusY});
|
||||
this.startSnapping();
|
||||
},
|
||||
outdent(outdentRegex: RegExp) {
|
||||
const lines = this.code.split("\n");
|
||||
const {focusX, focusY, anchorX, anchorY} = this;
|
||||
const newLines = lines.map((line, i) => {
|
||||
const match = line.match(outdentRegex);
|
||||
if (i >= Math.min(focusY, anchorY) && i <= Math.max(focusY, anchorY) && match) {
|
||||
return line.slice(match[0].length);
|
||||
} else {
|
||||
return line;
|
||||
}
|
||||
});
|
||||
this.code = newLines.join("\n");
|
||||
this.setSelection({x: Math.max(0,anchorX-1), y: anchorY}, {x: Math.max(0,focusX-1), y: focusY});
|
||||
this.startSnapping();
|
||||
},
|
||||
backspace() {
|
||||
const {code, focus} = this;
|
||||
if (this.isCollapsed()) {
|
||||
if (focus > 0) {
|
||||
this.code = code.slice(0, focus-1) + code.slice(focus);
|
||||
this.setSelection(focus-1);
|
||||
this.startSnapping();
|
||||
}
|
||||
} else {
|
||||
this.insertText("");
|
||||
}
|
||||
},
|
||||
delete() {
|
||||
const {code, focus} = this;
|
||||
if (this.isCollapsed()) {
|
||||
if (focus < code.length) {
|
||||
this.code = code.slice(0, focus) + code.slice(1+focus);
|
||||
this.startSnapping();
|
||||
}
|
||||
} else {
|
||||
this.insertText("");
|
||||
}
|
||||
},
|
||||
async copy() {
|
||||
const {code, anchor, focus} = this;
|
||||
const selected = code.slice(Math.min(anchor,focus), Math.max(anchor,focus));
|
||||
await clipboard.writeText(transformForCopy(selected));
|
||||
},
|
||||
async cut() {
|
||||
await this.copy();
|
||||
this.insertText("");
|
||||
},
|
||||
async paste() {
|
||||
this.insertText(transformForPaste(await clipboard.readText()));
|
||||
},
|
||||
scrollToCursor() {
|
||||
const {focusY, scrollY, scrollX, focus} = this;
|
||||
const fh = fontHeight + 1;
|
||||
const rect = indexToRect(this.code, focus);
|
||||
if (focusY*fh < scrollY) {
|
||||
this.scrollY = focusY*fh;
|
||||
}
|
||||
if (focusY*fh > scrollY+112-fh) {
|
||||
this.scrollY = focusY*fh-112+fh;
|
||||
}
|
||||
if (rect.x < scrollX) {
|
||||
this.scrollX = rect.x;
|
||||
}
|
||||
if (rect.x+rect.w > scrollX+128) {
|
||||
this.scrollX = rect.x-128+rect.w+1;
|
||||
}
|
||||
},
|
||||
currentIndentation() {
|
||||
const lines = this.code.slice(0, this.focus).split("\n");
|
||||
const line = lines[lines.length-1];
|
||||
const match = line.match(/^\s*/);
|
||||
if (!match) {
|
||||
return "";
|
||||
}
|
||||
return match[0];
|
||||
},
|
||||
get code() {
|
||||
return getCodeSheet(page.activeSheet);
|
||||
},
|
||||
set code(val) {
|
||||
setSheet(page.activeSheet, "code", val);
|
||||
}
|
||||
}
|
||||
|
||||
const indexToGrid = (str: string, index: number) => {
|
||||
const linesUpTo = str.slice(0,index).split("\n");
|
||||
return {
|
||||
x: linesUpTo[linesUpTo.length-1].length,
|
||||
y: linesUpTo.length - 1,
|
||||
}
|
||||
}
|
||||
|
||||
const gridToIndex = (str: string, x: number, y: number) => {
|
||||
const lines = str.split("\n");
|
||||
if (y < 0) {
|
||||
return 0;
|
||||
}
|
||||
if (y >= lines.length) {
|
||||
return str.length;
|
||||
}
|
||||
return lines.slice(0, y).join("\n").length+Math.min(x, lines[y].length)+(y === 0 ? 0 : 1);
|
||||
}
|
||||
|
||||
const indexToRect = (str: string, index: number) => {
|
||||
const linesUpTo = str.slice(0,index).split("\n");
|
||||
let extra = 0;
|
||||
if (linesUpTo[linesUpTo.length-1].length > 0) {
|
||||
extra = 1;
|
||||
}
|
||||
return {
|
||||
x: measureText(linesUpTo[linesUpTo.length-1]) + extra,
|
||||
y: (fontHeight + 1)*(linesUpTo.length - 1),
|
||||
w: measureText(str[index] ?? "\n"),
|
||||
h: fontHeight+1,
|
||||
}
|
||||
}
|
||||
|
||||
const pixelToIndex = (str: string, x: number, y: number) => {
|
||||
const lines = str.split("\n");
|
||||
if (y < 0) {
|
||||
return 0;
|
||||
}
|
||||
if (y >= (fontHeight+1)*lines.length) {
|
||||
return str.length;
|
||||
}
|
||||
const yy = Math.floor(y/(fontHeight+1));
|
||||
const prefix = lines.slice(0, yy).join("\n").length+(yy === 0 ? 0 : 1);
|
||||
const line = lines[yy];
|
||||
let j = 0;
|
||||
while (measureText(line.slice(0, j)) < x && j < line.length) {
|
||||
j+=1;
|
||||
}
|
||||
if (measureText(line) < x) {
|
||||
j+=1;
|
||||
}
|
||||
return prefix + Math.max(0, j-1);
|
||||
}
|
||||
|
||||
const update = async () => {
|
||||
const { focus } = state;
|
||||
if (state.history.length === 0) {
|
||||
state.snapshot();
|
||||
}
|
||||
if (state.historyDebounce > 0) {
|
||||
state.historyDebounce -= 1;
|
||||
if (state.historyDebounce <= 0) {
|
||||
state.snapshot();
|
||||
}
|
||||
}
|
||||
if (state.doubleClickTimer > 0) {
|
||||
state.doubleClickTimer -= 1;
|
||||
}
|
||||
|
||||
if (mouseDown() && !shiftKeyDown()) {
|
||||
if (state.doubleClickTimer > 0) {
|
||||
state.wordMode = true;
|
||||
} else {
|
||||
state.doubleClickTimer = 10;
|
||||
}
|
||||
const {x, y} = mousePos();
|
||||
state.setSelection(pixelToIndex(state.code, x+state.scrollX, y+state.scrollY-8));
|
||||
state.scrollToCursor();
|
||||
} else if (mouseHeld()) {
|
||||
const {x, y} = mousePos();
|
||||
state.setFocus(pixelToIndex(state.code, x+state.scrollX, y+state.scrollY-8));
|
||||
state.scrollToCursor();
|
||||
} else {
|
||||
state.wordMode = false;
|
||||
}
|
||||
|
||||
const keyboardString = getKeyboardString();
|
||||
if (keyboardString) {
|
||||
state.insertText(keyboardString);
|
||||
state.scrollToCursor();
|
||||
}
|
||||
|
||||
if (keyPressed(K.ENTER)) {
|
||||
state.insertText("\n"+state.currentIndentation());
|
||||
state.scrollToCursor();
|
||||
}
|
||||
if (keyPressed(K.TAB)) {
|
||||
if (!shiftKeyDown()) {
|
||||
if (state.isCollapsed()) {
|
||||
state.insertText("\t");
|
||||
} else {
|
||||
state.indent("\t");
|
||||
}
|
||||
} else {
|
||||
state.outdent(/^(\t| )/);
|
||||
}
|
||||
state.scrollToCursor();
|
||||
}
|
||||
if (keyPressed(K.BACKSPACE)) {
|
||||
state.backspace();
|
||||
state.scrollToCursor();
|
||||
}
|
||||
if (keyPressed(K.DELETE)) {
|
||||
state.delete();
|
||||
state.scrollToCursor();
|
||||
}
|
||||
if (keyPressed(K.ARROW_RIGHT)) {
|
||||
if (shiftKeyDown()) {
|
||||
state.setFocus(focus+1);
|
||||
} else {
|
||||
state.setSelection(focus+1);
|
||||
}
|
||||
state.scrollToCursor();
|
||||
}
|
||||
if (keyPressed(K.ARROW_LEFT)) {
|
||||
if (shiftKeyDown()) {
|
||||
state.setFocus(focus-1);
|
||||
} else {
|
||||
state.setSelection(focus-1);
|
||||
}
|
||||
state.scrollToCursor();
|
||||
}
|
||||
if (keyPressed(K.ARROW_DOWN)) {
|
||||
const rect = indexToRect(state.code, focus);
|
||||
const newIndex = pixelToIndex(state.code, rect.x, rect.y+rect.h+1+1);
|
||||
if (shiftKeyDown()) {
|
||||
state.setFocus(newIndex);
|
||||
} else {
|
||||
state.setSelection(newIndex);
|
||||
}
|
||||
state.scrollToCursor();
|
||||
}
|
||||
if (keyPressed(K.ARROW_UP)) {
|
||||
const rect = indexToRect(state.code, focus);
|
||||
const newIndex = pixelToIndex(state.code, rect.x, rect.y-1-1);
|
||||
if (shiftKeyDown()) {
|
||||
state.setFocus(newIndex);
|
||||
} else {
|
||||
state.setSelection(newIndex);
|
||||
}
|
||||
state.scrollToCursor();
|
||||
}
|
||||
if (keyPressed("C") && ctrlKeyDown()) {
|
||||
await state.copy();
|
||||
state.scrollToCursor();
|
||||
}
|
||||
if (keyPressed("X") && ctrlKeyDown()) {
|
||||
await state.cut();
|
||||
state.scrollToCursor();
|
||||
}
|
||||
if (keyPressed("V") && ctrlKeyDown()) {
|
||||
await state.paste();
|
||||
state.scrollToCursor();
|
||||
}
|
||||
if (keyPressed("Z") && ctrlKeyDown()) {
|
||||
if (shiftKeyDown()) {
|
||||
state.redo();
|
||||
} else {
|
||||
state.undo();
|
||||
}
|
||||
}
|
||||
if (keyPressed("Y") && ctrlKeyDown()) {
|
||||
state.redo();
|
||||
}
|
||||
if (keyPressed("/") && ctrlKeyDown()) {
|
||||
state.toggleComment();
|
||||
}
|
||||
}
|
||||
|
||||
const draw = () => {
|
||||
clearScreen();
|
||||
const {
|
||||
scrollX,
|
||||
scrollY,
|
||||
anchor,
|
||||
focus,
|
||||
code,
|
||||
} = state;
|
||||
const x = 0;
|
||||
const y = 8;
|
||||
const w = 128;
|
||||
const h = 112;
|
||||
fillRect(x, y, w, h, backgroundColor);
|
||||
if (anchor !== focus) {
|
||||
for (let i = Math.min(anchor, focus); i < Math.max(anchor, focus); i++) {
|
||||
const sel = indexToRect(code, i);
|
||||
fillRect(x+sel.x-scrollX, y+sel.y-scrollY, sel.w+2, sel.h, selectionColor);
|
||||
}
|
||||
}
|
||||
const rect = indexToRect(code, focus);
|
||||
fillRect(x+rect.x-scrollX, y+rect.y-scrollY, 1, rect.h, caretColor);
|
||||
|
||||
const builtins = Object.keys(getBuiltins());
|
||||
const tokens = [...tokenize(code)];
|
||||
let cx = 0;
|
||||
let cy = 0;
|
||||
tokens.forEach((token) => {
|
||||
if (token.type === "LineTerminatorSequence") {
|
||||
cx=0;
|
||||
cy+=fontHeight+1;
|
||||
return;
|
||||
}
|
||||
const lines = token.value.split("\n");
|
||||
lines.forEach((line, i) => {
|
||||
let color = tokenColors[token.type];
|
||||
if (builtins.includes(token.value)) {
|
||||
color = builtinColor;
|
||||
}
|
||||
if (keywords.includes(token.value)) {
|
||||
color = keywordColor;
|
||||
}
|
||||
if (values.includes(token.value)) {
|
||||
color = valueColor;
|
||||
}
|
||||
if (operator.includes(token.value)) {
|
||||
color = operatorColor;
|
||||
}
|
||||
if (punctuation.includes(token.value)) {
|
||||
color = punctuationColor;
|
||||
}
|
||||
drawText(1+x+cx-scrollX, 1+y+cy-scrollY, line, color);
|
||||
if (i === lines.length-1) {
|
||||
cx += measureText(line)+1;
|
||||
} else {
|
||||
cx=0;
|
||||
cy+=fontHeight+1;
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
export const codetab = {
|
||||
update,
|
||||
draw,
|
||||
}
|
119
colors.ts
Normal file
119
colors.ts
Normal file
@ -0,0 +1,119 @@
|
||||
const hue_gray = 230;
|
||||
const hue_brown = 30;
|
||||
const hue_orange = 37;
|
||||
const hue_purple = 280;
|
||||
const hue_pink = 310;
|
||||
const hue_red = 340;
|
||||
const hue_red_shade = 335;
|
||||
const hue_yellow = 57;
|
||||
const hue_green = 130;
|
||||
const hue_green_shade = 145;
|
||||
const hue_sky = 203;
|
||||
const hue_blue = 224;
|
||||
const hue_blue_shade = 235;
|
||||
const hue_blue_shade_2 = 240;
|
||||
|
||||
const saturation_max = 90;
|
||||
const saturation_normal = 60;
|
||||
const saturation_low = 40;
|
||||
const saturation_min = 13;
|
||||
|
||||
const lightness_max = 95;
|
||||
const lightness_light = 67;
|
||||
const lightness_mediumlight = 62;
|
||||
const lightness_medium = 50;
|
||||
const lightness_mediumdark = 40;
|
||||
const lightness_dark = 30;
|
||||
const lightness_almostverydark = 25;
|
||||
const lightness_verydark = 20;
|
||||
const lightness_min = 5;
|
||||
|
||||
/**
|
||||
* Converts an HSL color value to RGB. Conversion formula
|
||||
* adapted from http://en.wikipedia.org/wiki/HSL_color_space.
|
||||
* Assumes h, s, and l are contained in the set [0, 1] and
|
||||
* returns r, g, and b in the set [0, 255].
|
||||
*
|
||||
* @param Number h The hue
|
||||
* @param Number s The saturation
|
||||
* @param Number l The lightness
|
||||
* @return Array The RGB representation
|
||||
*/
|
||||
function hsl(h: number, s: number, l: number): [number, number, number] {
|
||||
h = h / 360;
|
||||
s = s/100;
|
||||
l = l/100;
|
||||
let r, g, b;
|
||||
|
||||
if (s == 0) {
|
||||
r = g = b = l; // achromatic
|
||||
} else {
|
||||
const hue2rgb = (p: number, q: number, t: number) => {
|
||||
if (t < 0) t += 1;
|
||||
if (t > 1) t -= 1;
|
||||
if (t < 1/6) return p + (q - p) * 6 * t;
|
||||
if (t < 1/2) return q;
|
||||
if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
|
||||
return p;
|
||||
}
|
||||
|
||||
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
||||
const p = 2 * l - q;
|
||||
|
||||
r = hue2rgb(p, q, h + 1/3);
|
||||
g = hue2rgb(p, q, h);
|
||||
b = hue2rgb(p, q, h - 1/3);
|
||||
}
|
||||
|
||||
return [ r , g , b ];
|
||||
}
|
||||
|
||||
const colors = {
|
||||
TRANSPARENT: [0, 0, 0],
|
||||
BLACK2: [0, 0, 0],
|
||||
BLACK3: [0, 0, 0],
|
||||
BLACK4: [0, 0, 0],
|
||||
WHITE: hsl(hue_gray, saturation_min, lightness_max),
|
||||
LIGHTGRAY: hsl(hue_gray, saturation_min, lightness_light),
|
||||
DARKGRAY: hsl(hue_gray, saturation_min, lightness_dark),
|
||||
BLACK: hsl(hue_gray, saturation_min, lightness_min),
|
||||
ORANGE: hsl(hue_orange, saturation_normal, lightness_medium),
|
||||
TAN: hsl(hue_brown, saturation_low, lightness_light),
|
||||
BROWN: hsl(hue_brown, saturation_low, lightness_mediumdark),
|
||||
DARKBROWN: hsl(hue_brown, saturation_low, lightness_almostverydark),
|
||||
PURPLE: hsl(hue_purple, saturation_normal, lightness_medium),
|
||||
PINK: hsl(hue_pink, saturation_normal, lightness_light),
|
||||
RED: hsl(hue_red, saturation_normal, lightness_medium),
|
||||
DARKRED: hsl(hue_red_shade, saturation_normal, lightness_dark),
|
||||
YELLOW: hsl(hue_yellow, saturation_max, lightness_mediumlight),
|
||||
GREEN: hsl(hue_green, saturation_normal, lightness_medium),
|
||||
DARKGREEN: hsl(hue_green_shade, saturation_normal, lightness_dark),
|
||||
DARKERGREEN: hsl(hue_green_shade, saturation_normal, lightness_verydark),
|
||||
CYAN: hsl(hue_sky, saturation_max, lightness_light),
|
||||
BLUE: hsl(hue_blue, saturation_normal, lightness_medium),
|
||||
DARKBLUE: hsl(hue_blue_shade, saturation_normal, lightness_mediumdark),
|
||||
DARKERBLUE: hsl(hue_blue_shade_2, saturation_normal, lightness_dark),
|
||||
} as const;
|
||||
|
||||
// const colors = {
|
||||
// TRANSPARENT: [0, 0, 0],
|
||||
// BLACK: [0, 0, 0],
|
||||
// WHITE: [1, 1, 1],
|
||||
// RED: [1, 0, 0],
|
||||
// YELLOW: [1, 1, 0],
|
||||
// GREEN: [0, 1, 0],
|
||||
// BLUE: [0.1, 0.5, 1],
|
||||
// DARKBLUE: [0.05, 0.1, 0.3],
|
||||
// BROWN: [0.6, 0.5, 0.4],
|
||||
// GRAY: [0.5, 0.5, 0.5],
|
||||
// PURPLE: [0.7, 0.1, 0.85],
|
||||
// ORANGE: [0.95, 0.75, 0.25],
|
||||
// CYAN: [0, 0.9, 0.9],
|
||||
// LIGHTGRAY: [0.75, 0.75, 0.75],
|
||||
// REDDISH: [216/255, 59/255, 113/255],
|
||||
// DARKGREEN: [0, 0.6, 0.2],
|
||||
// } as const;
|
||||
|
||||
export const palette: Array<[number, number, number, number]> = Object.values(colors).map(val => [...val, 1]);
|
||||
|
||||
export const COLOR = Object.fromEntries(Object.keys(colors).map((name, i) => [name, Number(i)])) as {[key in keyof typeof colors]: number};
|
11
deno.json
Normal file
11
deno.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"fmt": {
|
||||
"useTabs": true
|
||||
},
|
||||
"tasks": {
|
||||
"run": "deno run -A --unstable index.ts",
|
||||
"build": "deno compile --output build/faux -A --unstable index.ts",
|
||||
"build_linux": "deno compile --output build/faux_linux --target x86_64-unknown-linux-gnu -A --unstable index.ts",
|
||||
"build_windows": "deno compile --output build/faux_windows --target x86_64-pc-windows-msvc -A --unstable index.ts"
|
||||
}
|
||||
}
|
73
deno.lock
generated
Normal file
73
deno.lock
generated
Normal file
@ -0,0 +1,73 @@
|
||||
{
|
||||
"version": "2",
|
||||
"remote": {
|
||||
"https://deno.land/std@0.186.0/_util/asserts.ts": "178dfc49a464aee693a7e285567b3d0b555dc805ff490505a8aae34f9cfb1462",
|
||||
"https://deno.land/std@0.186.0/_util/os.ts": "d932f56d41e4f6a6093d56044e29ce637f8dcc43c5a90af43504a889cf1775e3",
|
||||
"https://deno.land/std@0.186.0/path/_constants.ts": "e49961f6f4f48039c0dfed3c3f93e963ca3d92791c9d478ac5b43183413136e0",
|
||||
"https://deno.land/std@0.186.0/path/_interface.ts": "6471159dfbbc357e03882c2266d21ef9afdb1e4aa771b0545e90db58a0ba314b",
|
||||
"https://deno.land/std@0.186.0/path/_util.ts": "d7abb1e0dea065f427b89156e28cdeb32b045870acdf865833ba808a73b576d0",
|
||||
"https://deno.land/std@0.186.0/path/common.ts": "ee7505ab01fd22de3963b64e46cff31f40de34f9f8de1fff6a1bd2fe79380000",
|
||||
"https://deno.land/std@0.186.0/path/glob.ts": "d479e0a695621c94d3fd7fe7abd4f9499caf32a8de13f25073451c6ef420a4e1",
|
||||
"https://deno.land/std@0.186.0/path/mod.ts": "ee161baec5ded6510ee1d1fb6a75a0f5e4b41f3f3301c92c716ecbdf7dae910d",
|
||||
"https://deno.land/std@0.186.0/path/posix.ts": "8b7c67ac338714b30c816079303d0285dd24af6b284f7ad63da5b27372a2c94d",
|
||||
"https://deno.land/std@0.186.0/path/separator.ts": "0fb679739d0d1d7bf45b68dacfb4ec7563597a902edbaf3c59b50d5bcadd93b1",
|
||||
"https://deno.land/std@0.186.0/path/win32.ts": "d186344e5583bcbf8b18af416d13d82b35a317116e6460a5a3953508c3de5bba",
|
||||
"https://deno.land/std@0.97.0/_util/assert.ts": "2f868145a042a11d5ad0a3c748dcf580add8a0dbc0e876eaa0026303a5488f58",
|
||||
"https://deno.land/std@0.97.0/_util/os.ts": "e282950a0eaa96760c0cf11e7463e66babd15ec9157d4c9ed49cc0925686f6a7",
|
||||
"https://deno.land/std@0.97.0/encoding/base64.ts": "eecae390f1f1d1cae6f6c6d732ede5276bf4b9cd29b1d281678c054dc5cc009e",
|
||||
"https://deno.land/std@0.97.0/encoding/hex.ts": "f952e0727bddb3b2fd2e6889d104eacbd62e92091f540ebd6459317a61932d9b",
|
||||
"https://deno.land/std@0.97.0/fs/_util.ts": "f2ce811350236ea8c28450ed822a5f42a0892316515b1cd61321dec13569c56b",
|
||||
"https://deno.land/std@0.97.0/fs/ensure_dir.ts": "b7c103dc41a3d1dbbb522bf183c519c37065fdc234831a4a0f7d671b1ed5fea7",
|
||||
"https://deno.land/std@0.97.0/fs/exists.ts": "b0d2e31654819cc2a8d37df45d6b14686c0cc1d802e9ff09e902a63e98b85a00",
|
||||
"https://deno.land/std@0.97.0/hash/_wasm/hash.ts": "cb6ad1ab429f8ac9d6eae48f3286e08236d662e1a2e5cfd681ba1c0f17375895",
|
||||
"https://deno.land/std@0.97.0/hash/_wasm/wasm.js": "94b1b997ae6fb4e6d2156bcea8f79cfcd1e512a91252b08800a92071e5e84e1a",
|
||||
"https://deno.land/std@0.97.0/hash/hasher.ts": "57a9ec05dd48a9eceed319ac53463d9873490feea3832d58679df6eec51c176b",
|
||||
"https://deno.land/std@0.97.0/hash/mod.ts": "5d032bd34186cda2f8d17fc122d621430953a6030d4b3f11172004715e3e2441",
|
||||
"https://deno.land/std@0.97.0/path/_constants.ts": "1247fee4a79b70c89f23499691ef169b41b6ccf01887a0abd131009c5581b853",
|
||||
"https://deno.land/std@0.97.0/path/_interface.ts": "1fa73b02aaa24867e481a48492b44f2598cd9dfa513c7b34001437007d3642e4",
|
||||
"https://deno.land/std@0.97.0/path/_util.ts": "2e06a3b9e79beaf62687196bd4b60a4c391d862cfa007a20fc3a39f778ba073b",
|
||||
"https://deno.land/std@0.97.0/path/common.ts": "eaf03d08b569e8a87e674e4e265e099f237472b6fd135b3cbeae5827035ea14a",
|
||||
"https://deno.land/std@0.97.0/path/glob.ts": "314ad9ff263b895795208cdd4d5e35a44618ca3c6dd155e226fb15d065008652",
|
||||
"https://deno.land/std@0.97.0/path/mod.ts": "4465dc494f271b02569edbb4a18d727063b5dbd6ed84283ff906260970a15d12",
|
||||
"https://deno.land/std@0.97.0/path/posix.ts": "f56c3c99feb47f30a40ce9d252ef6f00296fa7c0fcb6dd81211bdb3b8b99ca3b",
|
||||
"https://deno.land/std@0.97.0/path/separator.ts": "8fdcf289b1b76fd726a508f57d3370ca029ae6976fcde5044007f062e643ff1c",
|
||||
"https://deno.land/std@0.97.0/path/win32.ts": "77f7b3604e0de40f3a7c698e8a79e7f601dc187035a1c21cb1e596666ce112f8",
|
||||
"https://deno.land/x/cache@0.2.13/deps.ts": "6f14e76a1a09f329e3f3830c6e72bd10b53a89a75769d5ea886e5d8603e503e6",
|
||||
"https://deno.land/x/cache@0.2.13/directories.ts": "ef48531cab3f827252e248596d15cede0de179a2fb15392ae24cf8034519994f",
|
||||
"https://deno.land/x/dwm@0.3.3/mod.ts": "8a8ca602442d250eaa7cef67c14245a41aa7dc8de2fa337008e433a2ed1fe2f1",
|
||||
"https://deno.land/x/dwm@0.3.3/src/core/common.ts": "dd4cd26f45fca187c5a6192bfb7b3b4a01a23c66dddf64e19e013de7748f988d",
|
||||
"https://deno.land/x/dwm@0.3.3/src/core/event.ts": "715cce309021e9dcd45b7e3f41bddea961d4b157dcf6f29a21e910825aae90a8",
|
||||
"https://deno.land/x/dwm@0.3.3/src/core/mod.ts": "4c54848365ea17b67e65d4d58c7c94378c9bbc6ea2a59d7d11f1d701e6a5483a",
|
||||
"https://deno.land/x/dwm@0.3.3/src/core/monitor.ts": "b291ebad386095285fb7c430990be0a9f1f5f81fbcb338058ce72a538a75d667",
|
||||
"https://deno.land/x/dwm@0.3.3/src/core/platform.ts": "6cab5f575198848673204673fe82d242c9c87549c16cbed9a64c838eb99dd2d4",
|
||||
"https://deno.land/x/dwm@0.3.3/src/core/window.ts": "1ccd738d6e4e28836327a76480c3c47855f617fa7ed7552a035f2d7bf0fd6c6d",
|
||||
"https://deno.land/x/dwm@0.3.3/src/platform/glfw/constants.ts": "832295fa6a4bd66aea638bd09ad2cc48b3756daff814c7c0ae2a544f228be9e5",
|
||||
"https://deno.land/x/dwm@0.3.3/src/platform/glfw/ffi.ts": "0c6a521a8374aa8c912417edfa5c263423286363f4a7c827d4d26ead8b954ee6",
|
||||
"https://deno.land/x/dwm@0.3.3/src/platform/glfw/monitor.ts": "05506c5d21c527a6ea456d24e00f88a01a9292a68f45a845499137ecb6fb80c7",
|
||||
"https://deno.land/x/dwm@0.3.3/src/platform/glfw/platform.ts": "cca2684151f34be392e74a9828f89f8c3ed46db25e59aec1f638b4ccf82535e9",
|
||||
"https://deno.land/x/dwm@0.3.3/src/platform/glfw/scancode_win.json": "711ee525f88fe92129acd7d66fd6a5665b68ce6a60f590ae24de67e1ee916b8f",
|
||||
"https://deno.land/x/dwm@0.3.3/src/platform/glfw/window.ts": "a6dd426a95cd93ba4905da151a0d06e9376becca273ee8bc8d1c9a7bd16e0d81",
|
||||
"https://deno.land/x/dwm@0.3.3/src/platform/mod.ts": "20572d937c62ec543e0ca87cf8ed32cd15505d254f97a6fae98b936e480f2157",
|
||||
"https://deno.land/x/gluten@0.1.6/api/gles23.2.ts": "99cad13b74938ff987a1a707f73d72a82ddf66935e45b59d1980928cd3af3495",
|
||||
"https://esm.sh/js-tokens@8.0.1": "7b08a51f91034b720edcde4f0b4314abc39ee14da57861e3e676f1ed1f4fb4ab",
|
||||
"https://esm.sh/v119/js-tokens@8.0.1/deno/js-tokens.mjs": "0fa55e76fa97785f8f938db8ea55e0db57825ea81cdcad20bd925f9902f678c1",
|
||||
"https://esm.sh/v119/js-tokens@8.0.1/index.d.ts": "9b178631a934bd5e4832b478d4f74083d4dc357615a0d1a632357dfafe898cdb",
|
||||
"https://glfw-binaries.deno.dev/3.4.0-patch2/glfw3_darwin.js": "48911f26fff723a9c5f2f38e39be42fc65ed8dea6f2ba1f1acb464d3f0aa435b",
|
||||
"https://glfw-binaries.deno.dev/3.4.0-patch2/glfw3_darwin_aarch64.js": "ae4d795d93830b8a27714ab6c20b69b67f3d4ad3544c50e344558756cf2e92f3",
|
||||
"https://glfw-binaries.deno.dev/3.4.0-patch2/glfw3_linux.js": "b064aedb175fee1a977937f07584238f313a1958f9869273e7e672c42f09932d",
|
||||
"https://glfw-binaries.deno.dev/3.4.0-patch2/glfw3_windows.js": "6ac603e03520c8c333e1475cb00f982adb1f8a99de7f4bb0b8953da66f210159",
|
||||
"https://raw.githubusercontent.com/Nisgrak/deno-clipboard/fix-deno-1.0.0/mod.ts": "85282325a499c75c6f9ed3603fc5f8baf4bf661a616add43b4e6f033def52680",
|
||||
"https://unpkg.com/js-tokens@8.0.1/index.js": "322c95254ceef0ac195f4e71adac2a90adf379a2d67fbb948402295a780fdbc0"
|
||||
},
|
||||
"npm": {
|
||||
"specifiers": {
|
||||
"js-tokens": "js-tokens@8.0.1"
|
||||
},
|
||||
"packages": {
|
||||
"js-tokens@8.0.1": {
|
||||
"integrity": "sha512-3AGrZT6tuMm1ZWWn9mLXh7XMfi2YtiLNPALCVxBCiUVq0LD1OQMxV/AdS/s7rLJU5o9i/jBZw/N4vXXL5dm29A==",
|
||||
"dependencies": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
43
deps.ts
Normal file
43
deps.ts
Normal file
@ -0,0 +1,43 @@
|
||||
// dwm
|
||||
export {
|
||||
createWindow,
|
||||
getProcAddress,
|
||||
mainloop,
|
||||
} from "https://deno.land/x/dwm@0.3.3/mod.ts";
|
||||
export * as gl from "https://deno.land/x/gluten@0.1.6/api/gles23.2.ts";
|
||||
|
||||
// jsTokens
|
||||
import jsTokens from "https://esm.sh/js-tokens@8.0.1";
|
||||
export function tokenize(input: string): Iterable<Token> {
|
||||
// deno-lint-ignore no-explicit-any
|
||||
return (jsTokens as any)(input);
|
||||
}
|
||||
type Token =
|
||||
| { type: "StringLiteral"; value: string; closed: boolean }
|
||||
| { type: "NoSubstitutionTemplate"; value: string; closed: boolean }
|
||||
| { type: "TemplateHead"; value: string }
|
||||
| { type: "TemplateMiddle"; value: string }
|
||||
| { type: "TemplateTail"; value: string; closed: boolean }
|
||||
| { type: "RegularExpressionLiteral"; value: string; closed: boolean }
|
||||
| { type: "MultiLineComment"; value: string; closed: boolean }
|
||||
| { type: "SingleLineComment"; value: string }
|
||||
| { type: "IdentifierName"; value: string }
|
||||
| { type: "PrivateIdentifier"; value: string }
|
||||
| { type: "NumericLiteral"; value: string }
|
||||
| { type: "Punctuator"; value: string }
|
||||
| { type: "WhiteSpace"; value: string }
|
||||
| { type: "LineTerminatorSequence"; value: string }
|
||||
| { type: "Invalid"; value: string };
|
||||
|
||||
// clipboard
|
||||
import { clipboard } from "https://raw.githubusercontent.com/Nisgrak/deno-clipboard/fix-deno-1.0.0/mod.ts";
|
||||
export { clipboard } from "https://raw.githubusercontent.com/Nisgrak/deno-clipboard/fix-deno-1.0.0/mod.ts";
|
||||
try {
|
||||
await clipboard.readText();
|
||||
} catch (err) {
|
||||
console.log("If you are running this on linux, please make sure you have 'xsel' installed.");
|
||||
throw err;
|
||||
}
|
||||
|
||||
// path
|
||||
export * as path from "https://deno.land/std@0.186.0/path/mod.ts";
|
95
editmode.ts
Normal file
95
editmode.ts
Normal file
@ -0,0 +1,95 @@
|
||||
import { clearScreen, fillRect } from "./window.ts";
|
||||
import { codetab } from "./codetab.ts";
|
||||
import { spritetab } from "./spritetab.ts";
|
||||
import { viewsheets, page } from "./viewsheets.ts";
|
||||
import { COLOR } from "./colors.ts";
|
||||
import { mouseClick, mousePos } from "./mouse.ts";
|
||||
import { drawIcon } from "./builtins.ts";
|
||||
import { inRect } from "./util.ts";
|
||||
import { sheetsIcon, trashIcon } from "./icons.ts";
|
||||
import { SheetType, setSheet } from "./sheet.ts";
|
||||
import { nonetab } from "./nonetab.ts";
|
||||
import { maptab } from "./maptab.ts";
|
||||
|
||||
type TabName = SheetType; // "code" | "sprite" | "map" | "sfx" | "music" | "sheet";
|
||||
|
||||
const buttons: Array<{update: () => void, draw: () => void}> = [];
|
||||
const makeTabButton = (tabname: TabName | "sheet", x: number, y: number, icon: Array<number>) => {
|
||||
buttons.push({
|
||||
update() {
|
||||
if (mouseClick()) {
|
||||
const {x: mouseX, y: mouseY} = mousePos();
|
||||
if (inRect(mouseX, mouseY, x, y, 8, 8)) {
|
||||
page.tab = tabname;
|
||||
}
|
||||
}
|
||||
},
|
||||
draw() {
|
||||
drawIcon(x, y, icon, page.tab === tabname ? COLOR.YELLOW : COLOR.WHITE);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const makeTrashButton = (x: number, y: number, icon: Array<number>) => {
|
||||
buttons.push({
|
||||
update() {
|
||||
if (page.tab !== "sheet") {
|
||||
return
|
||||
}
|
||||
if (mouseClick()) {
|
||||
const {x: mouseX, y: mouseY} = mousePos();
|
||||
if (inRect(mouseX, mouseY, x, y, 8, 8)) {
|
||||
setSheet(page.activeSheet, "none", null);
|
||||
page.tab = "sheet";
|
||||
}
|
||||
}
|
||||
},
|
||||
draw() {
|
||||
if (page.tab !== "sheet") {
|
||||
return
|
||||
}
|
||||
drawIcon(x, y, icon, COLOR.BLACK);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
makeTabButton("sheet", 120, 0, sheetsIcon);
|
||||
makeTrashButton(0, 0, trashIcon);
|
||||
|
||||
const update = () => {
|
||||
buttons.forEach(button => button.update());
|
||||
if (page.tab === "code") {
|
||||
codetab.update();
|
||||
} else if (page.tab === "spritesheet") {
|
||||
spritetab.update();
|
||||
} else if (page.tab === "map") {
|
||||
maptab.update();
|
||||
} else if (page.tab === "sheet") {
|
||||
viewsheets.update();
|
||||
} else if (page.tab === "none") {
|
||||
nonetab.update();
|
||||
}
|
||||
}
|
||||
|
||||
const draw = () => {
|
||||
clearScreen();
|
||||
if (page.tab === "code") {
|
||||
codetab.draw();
|
||||
} else if (page.tab === "spritesheet") {
|
||||
spritetab.draw();
|
||||
} else if (page.tab === "map") {
|
||||
maptab.draw();
|
||||
} else if (page.tab === "sheet") {
|
||||
viewsheets.draw();
|
||||
} else if (page.tab === "none") {
|
||||
nonetab.draw();
|
||||
}
|
||||
fillRect(0, 0, 128, 8, COLOR.RED);
|
||||
fillRect(0, 120, 128, 8, COLOR.RED);
|
||||
buttons.forEach(button => button.draw());
|
||||
}
|
||||
|
||||
export const editmode = {
|
||||
update,
|
||||
draw,
|
||||
}
|
854
font.ts
Normal file
854
font.ts
Normal file
@ -0,0 +1,854 @@
|
||||
/**
|
||||
* Perhaps fonts can be their own type of sheet. By the calculation below, we can fit ~4 fonts per fontsheet
|
||||
*
|
||||
* 3 bits for height
|
||||
* 5 more metadata bits
|
||||
* = 1 byte
|
||||
*
|
||||
* Per character:
|
||||
* - 3 bits for width
|
||||
* - 5 bits for metadata
|
||||
* - 64 bits for pixels
|
||||
* = 9 bytes per character
|
||||
*
|
||||
* 96 chars * 9 bytes =
|
||||
*/
|
||||
|
||||
// export const fontWidth = 4;
|
||||
// export const fontHeight = 6;
|
||||
|
||||
export const CHAR = {
|
||||
UP: "À",
|
||||
LEFT: "Á",
|
||||
DOWN: "Â",
|
||||
RIGHT: "Ã",
|
||||
PI: "π"
|
||||
}
|
||||
|
||||
export type Font = {
|
||||
height: 6,
|
||||
chars: {[key: string]: Array<number>},
|
||||
};
|
||||
|
||||
// deno-fmt-ignore
|
||||
export const font: Font = {
|
||||
height: 6,
|
||||
chars: {
|
||||
"A": [
|
||||
1, 1, 1,
|
||||
1, 0, 1,
|
||||
1, 1, 1,
|
||||
1, 0, 1,
|
||||
1, 0, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"B": [
|
||||
1, 1, 1,
|
||||
1, 0, 1,
|
||||
1, 1, 0,
|
||||
1, 0, 1,
|
||||
1, 1, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"C": [
|
||||
0, 1, 1,
|
||||
1, 0, 0,
|
||||
1, 0, 0,
|
||||
1, 0, 0,
|
||||
0, 1, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"D": [
|
||||
1, 1, 0,
|
||||
1, 0, 1,
|
||||
1, 0, 1,
|
||||
1, 0, 1,
|
||||
1, 1, 0,
|
||||
0, 0, 0,
|
||||
],
|
||||
"E": [
|
||||
1, 1, 1,
|
||||
1, 0, 0,
|
||||
1, 1, 0,
|
||||
1, 0, 0,
|
||||
1, 1, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"F": [
|
||||
1, 1, 1,
|
||||
1, 0, 0,
|
||||
1, 1, 0,
|
||||
1, 0, 0,
|
||||
1, 0, 0,
|
||||
0, 0, 0,
|
||||
],
|
||||
"G": [
|
||||
0, 1, 1,
|
||||
1, 0, 0,
|
||||
1, 0, 1,
|
||||
1, 0, 1,
|
||||
0, 1, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"H": [
|
||||
1, 0, 1,
|
||||
1, 0, 1,
|
||||
1, 1, 1,
|
||||
1, 0, 1,
|
||||
1, 0, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"I": [
|
||||
1, 1, 1,
|
||||
0, 1, 0,
|
||||
0, 1, 0,
|
||||
0, 1, 0,
|
||||
1, 1, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"J": [
|
||||
1, 1, 1,
|
||||
0, 1, 0,
|
||||
0, 1, 0,
|
||||
0, 1, 0,
|
||||
1, 1, 0,
|
||||
0, 0, 0,
|
||||
],
|
||||
"K": [
|
||||
1, 0, 1,
|
||||
1, 0, 1,
|
||||
1, 1, 0,
|
||||
1, 0, 1,
|
||||
1, 0, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"L": [
|
||||
1, 0, 0,
|
||||
1, 0, 0,
|
||||
1, 0, 0,
|
||||
1, 0, 0,
|
||||
1, 1, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"M": [
|
||||
1, 1, 1,
|
||||
1, 1, 1,
|
||||
1, 0, 1,
|
||||
1, 0, 1,
|
||||
1, 0, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"N": [
|
||||
1, 1, 0,
|
||||
1, 0, 1,
|
||||
1, 0, 1,
|
||||
1, 0, 1,
|
||||
1, 0, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"O": [
|
||||
0, 1, 1,
|
||||
1, 0, 1,
|
||||
1, 0, 1,
|
||||
1, 0, 1,
|
||||
1, 1, 0,
|
||||
0, 0, 0,
|
||||
],
|
||||
"P": [
|
||||
1, 1, 1,
|
||||
1, 0, 1,
|
||||
1, 1, 1,
|
||||
1, 0, 0,
|
||||
1, 0, 0,
|
||||
0, 0, 0,
|
||||
],
|
||||
"Q": [
|
||||
0, 1, 1,
|
||||
1, 0, 1,
|
||||
1, 0, 1,
|
||||
1, 1, 0,
|
||||
0, 1, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"R": [
|
||||
1, 1, 1,
|
||||
1, 0, 1,
|
||||
1, 1, 0,
|
||||
1, 0, 1,
|
||||
1, 0, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"S": [
|
||||
0, 1, 1,
|
||||
1, 0, 0,
|
||||
1, 1, 1,
|
||||
0, 0, 1,
|
||||
1, 1, 0,
|
||||
0, 0, 0,
|
||||
],
|
||||
"T": [
|
||||
1, 1, 1,
|
||||
0, 1, 0,
|
||||
0, 1, 0,
|
||||
0, 1, 0,
|
||||
0, 1, 0,
|
||||
0, 0, 0,
|
||||
],
|
||||
"U": [
|
||||
1, 0, 1,
|
||||
1, 0, 1,
|
||||
1, 0, 1,
|
||||
1, 0, 1,
|
||||
0, 1, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"V": [
|
||||
1, 0, 1,
|
||||
1, 0, 1,
|
||||
1, 0, 1,
|
||||
1, 1, 1,
|
||||
0, 1, 0,
|
||||
0, 0, 0,
|
||||
],
|
||||
"W": [
|
||||
1, 0, 1,
|
||||
1, 0, 1,
|
||||
1, 0, 1,
|
||||
1, 1, 1,
|
||||
1, 1, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"X": [
|
||||
1, 0, 1,
|
||||
1, 0, 1,
|
||||
0, 1, 0,
|
||||
1, 0, 1,
|
||||
1, 0, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"Y": [
|
||||
1, 0, 1,
|
||||
1, 0, 1,
|
||||
1, 1, 1,
|
||||
0, 1, 0,
|
||||
1, 0, 0,
|
||||
0, 0, 0,
|
||||
],
|
||||
"Z": [
|
||||
1, 1, 1,
|
||||
0, 0, 1,
|
||||
0, 1, 0,
|
||||
1, 0, 0,
|
||||
1, 1, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"a": [
|
||||
0, 0, 0,
|
||||
1, 1, 1,
|
||||
0, 1, 1,
|
||||
1, 0, 1,
|
||||
1, 1, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"b": [
|
||||
1, 0, 0,
|
||||
1, 0, 0,
|
||||
1, 1, 1,
|
||||
1, 0, 1,
|
||||
1, 1, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"c": [
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
1, 1, 1,
|
||||
1, 0, 0,
|
||||
1, 1, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"d": [
|
||||
0, 0, 1,
|
||||
0, 0, 1,
|
||||
1, 1, 1,
|
||||
1, 0, 1,
|
||||
1, 1, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"e": [
|
||||
0, 0, 0,
|
||||
0, 1, 1,
|
||||
1, 0, 1,
|
||||
1, 1, 0,
|
||||
0, 1, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"f": [
|
||||
0, 1, 1,
|
||||
1, 0, 0,
|
||||
1, 1, 0,
|
||||
1, 0, 0,
|
||||
1, 0, 0,
|
||||
0, 0, 0,
|
||||
],
|
||||
"g": [
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
1, 1, 1,
|
||||
1, 0, 1,
|
||||
0, 1, 1,
|
||||
1, 1, 0,
|
||||
],
|
||||
"h": [
|
||||
1, 0, 0,
|
||||
1, 0, 0,
|
||||
1, 1, 1,
|
||||
1, 0, 1,
|
||||
1, 0, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"i": [
|
||||
0, 1, 0,
|
||||
0, 0, 0,
|
||||
0, 1, 0,
|
||||
0, 1, 0,
|
||||
0, 1, 0,
|
||||
0, 0, 0,
|
||||
],
|
||||
"j": [
|
||||
0, 1, 0,
|
||||
0, 0, 0,
|
||||
0, 1, 0,
|
||||
0, 1, 0,
|
||||
0, 1, 0,
|
||||
1, 0, 0,
|
||||
],
|
||||
"k": [
|
||||
1, 0, 0,
|
||||
1, 0, 0,
|
||||
1, 0, 1,
|
||||
1, 1, 0,
|
||||
1, 0, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"l": [
|
||||
0, 1, 0,
|
||||
0, 1, 0,
|
||||
0, 1, 0,
|
||||
0, 1, 0,
|
||||
0, 0, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"m": [
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
1, 1, 1,
|
||||
1, 1, 1,
|
||||
1, 0, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"n": [
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
1, 1, 0,
|
||||
1, 0, 1,
|
||||
1, 0, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"o": [
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
0, 1, 1,
|
||||
1, 0, 1,
|
||||
1, 1, 0,
|
||||
0, 0, 0,
|
||||
],
|
||||
"p": [
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
1, 1, 1,
|
||||
1, 0, 1,
|
||||
1, 1, 1,
|
||||
1, 0, 0,
|
||||
],
|
||||
"q": [
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
1, 1, 1,
|
||||
1, 0, 1,
|
||||
1, 1, 1,
|
||||
0, 0, 1,
|
||||
],
|
||||
"r": [
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
1, 1, 1,
|
||||
1, 0, 0,
|
||||
1, 0, 0,
|
||||
0, 0, 0,
|
||||
],
|
||||
"s": [
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
0, 1, 1,
|
||||
0, 1, 0,
|
||||
1, 1, 0,
|
||||
0, 0, 0,
|
||||
],
|
||||
"t": [
|
||||
0, 1, 0,
|
||||
0, 1, 0,
|
||||
1, 1, 1,
|
||||
0, 1, 0,
|
||||
0, 1, 0,
|
||||
0, 0, 0,
|
||||
],
|
||||
"u": [
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
1, 0, 1,
|
||||
1, 0, 1,
|
||||
0, 1, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"v": [
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
1, 0, 1,
|
||||
1, 0, 1,
|
||||
0, 1, 0,
|
||||
0, 0, 0,
|
||||
],
|
||||
"w": [
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
1, 0, 1,
|
||||
1, 1, 1,
|
||||
1, 1, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"x": [
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
1, 0, 1,
|
||||
0, 1, 0,
|
||||
1, 0, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"y": [
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
1, 0, 1,
|
||||
1, 0, 1,
|
||||
0, 1, 0,
|
||||
1, 0, 0,
|
||||
],
|
||||
"z": [
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
1, 1, 0,
|
||||
0, 1, 0,
|
||||
0, 1, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
",": [
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
0, 1, 0,
|
||||
1, 0, 0,
|
||||
],
|
||||
".": [
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
0, 1, 0,
|
||||
0, 0, 0,
|
||||
],
|
||||
" ": [
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
],
|
||||
"\t": [
|
||||
0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0,
|
||||
],
|
||||
"\n": [
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
],
|
||||
"<": [
|
||||
0, 0, 1,
|
||||
0, 1, 0,
|
||||
1, 0, 0,
|
||||
0, 1, 0,
|
||||
0, 0, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
">": [
|
||||
1, 0, 0,
|
||||
0, 1, 0,
|
||||
0, 0, 1,
|
||||
0, 1, 0,
|
||||
1, 0, 0,
|
||||
0, 0, 0,
|
||||
],
|
||||
"=": [
|
||||
0, 0, 0,
|
||||
1, 1, 1,
|
||||
0, 0, 0,
|
||||
1, 1, 1,
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
],
|
||||
"(": [
|
||||
0, 0, 1,
|
||||
0, 1, 0,
|
||||
0, 1, 0,
|
||||
0, 1, 0,
|
||||
0, 0, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
")": [
|
||||
1, 0, 0,
|
||||
0, 1, 0,
|
||||
0, 1, 0,
|
||||
0, 1, 0,
|
||||
1, 0, 0,
|
||||
0, 0, 0,
|
||||
],
|
||||
"[": [
|
||||
0, 1, 1,
|
||||
0, 1, 0,
|
||||
0, 1, 0,
|
||||
0, 1, 0,
|
||||
0, 1, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"]": [
|
||||
1, 1, 0,
|
||||
0, 1, 0,
|
||||
0, 1, 0,
|
||||
0, 1, 0,
|
||||
1, 1, 0,
|
||||
0, 0, 0,
|
||||
],
|
||||
"{": [
|
||||
0, 1, 1,
|
||||
0, 1, 0,
|
||||
1, 1, 0,
|
||||
0, 1, 0,
|
||||
0, 1, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"}": [
|
||||
1, 1, 0,
|
||||
0, 1, 0,
|
||||
0, 1, 1,
|
||||
0, 1, 0,
|
||||
1, 1, 0,
|
||||
0, 0, 0,
|
||||
],
|
||||
":": [
|
||||
0, 0, 0,
|
||||
0, 1, 0,
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
0, 1, 0,
|
||||
0, 0, 0,
|
||||
],
|
||||
";": [
|
||||
0, 0, 0,
|
||||
0, 1, 0,
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
0, 1, 0,
|
||||
1, 0, 0,
|
||||
],
|
||||
"'": [
|
||||
0, 1, 0,
|
||||
0, 1, 0,
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
],
|
||||
'"': [
|
||||
1, 0, 1,
|
||||
1, 0, 1,
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
],
|
||||
"1": [
|
||||
0, 1, 0,
|
||||
1, 1, 0,
|
||||
0, 1, 0,
|
||||
0, 1, 0,
|
||||
1, 1, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"2": [
|
||||
0, 1, 0,
|
||||
1, 0, 1,
|
||||
0, 0, 1,
|
||||
0, 1, 0,
|
||||
1, 1, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"3": [
|
||||
1, 1, 1,
|
||||
0, 0, 1,
|
||||
0, 1, 0,
|
||||
0, 0, 1,
|
||||
1, 1, 0,
|
||||
0, 0, 0,
|
||||
],
|
||||
"4": [
|
||||
1, 0, 1,
|
||||
1, 0, 1,
|
||||
1, 1, 1,
|
||||
0, 0, 1,
|
||||
0, 0, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"5": [
|
||||
1, 1, 1,
|
||||
1, 0, 0,
|
||||
1, 1, 0,
|
||||
0, 0, 1,
|
||||
1, 1, 0,
|
||||
0, 0, 0,
|
||||
],
|
||||
"6": [
|
||||
0, 0, 1,
|
||||
0, 1, 0,
|
||||
1, 1, 1,
|
||||
1, 0, 1,
|
||||
1, 1, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"7": [
|
||||
1, 1, 1,
|
||||
0, 0, 1,
|
||||
0, 1, 0,
|
||||
0, 1, 0,
|
||||
0, 1, 0,
|
||||
0, 0, 0,
|
||||
],
|
||||
"8": [
|
||||
1, 1, 1,
|
||||
1, 0, 1,
|
||||
1, 1, 1,
|
||||
1, 0, 1,
|
||||
1, 1, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"9": [
|
||||
1, 1, 1,
|
||||
1, 0, 1,
|
||||
1, 1, 1,
|
||||
0, 1, 0,
|
||||
1, 0, 0,
|
||||
0, 0, 0,
|
||||
],
|
||||
"0": [
|
||||
1, 1, 1,
|
||||
1, 0, 1,
|
||||
1, 0, 1,
|
||||
1, 0, 1,
|
||||
1, 1, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"+": [
|
||||
0, 0, 0,
|
||||
0, 1, 0,
|
||||
1, 1, 1,
|
||||
0, 1, 0,
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
],
|
||||
"-": [
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
1, 1, 1,
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
],
|
||||
"_": [
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
1, 1, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"`": [
|
||||
1, 0, 0,
|
||||
0, 1, 0,
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
],
|
||||
"~": [
|
||||
0, 0, 0,
|
||||
0, 0, 1,
|
||||
1, 1, 1,
|
||||
1, 0, 0,
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
],
|
||||
"/": [
|
||||
0, 0, 1,
|
||||
0, 0, 1,
|
||||
0, 1, 0,
|
||||
1, 0, 0,
|
||||
1, 0, 0,
|
||||
0, 0, 0,
|
||||
],
|
||||
"?": [
|
||||
1, 1, 1,
|
||||
0, 0, 1,
|
||||
0, 1, 1,
|
||||
0, 0, 0,
|
||||
0, 1, 0,
|
||||
0, 0, 0,
|
||||
],
|
||||
"\\": [
|
||||
1, 0, 0,
|
||||
1, 0, 0,
|
||||
0, 1, 0,
|
||||
0, 0, 1,
|
||||
0, 0, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"|": [
|
||||
0, 1, 0,
|
||||
0, 1, 0,
|
||||
0, 1, 0,
|
||||
0, 1, 0,
|
||||
0, 1, 0,
|
||||
0, 0, 0,
|
||||
],
|
||||
"!": [
|
||||
0, 1, 0,
|
||||
0, 1, 0,
|
||||
0, 1, 0,
|
||||
0, 0, 0,
|
||||
0, 1, 0,
|
||||
0, 0, 0,
|
||||
],
|
||||
"@": [
|
||||
0, 1, 0,
|
||||
1, 0, 1,
|
||||
1, 0, 1,
|
||||
1, 0, 0,
|
||||
0, 1, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"#": [
|
||||
1, 0, 1,
|
||||
1, 1, 1,
|
||||
1, 0, 1,
|
||||
1, 1, 1,
|
||||
1, 0, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"$": [
|
||||
1, 1, 1,
|
||||
1, 1, 0,
|
||||
0, 1, 1,
|
||||
1, 1, 1,
|
||||
0, 1, 0,
|
||||
0, 0, 0,
|
||||
],
|
||||
"%": [
|
||||
1, 0, 1,
|
||||
0, 0, 1,
|
||||
0, 1, 0,
|
||||
1, 0, 0,
|
||||
1, 0, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"^": [
|
||||
0, 1, 0,
|
||||
1, 0, 1,
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
],
|
||||
"&": [
|
||||
1, 1, 0,
|
||||
1, 1, 0,
|
||||
0, 1, 1,
|
||||
1, 0, 1,
|
||||
1, 1, 1,
|
||||
0, 0, 0,
|
||||
],
|
||||
"*": [
|
||||
0, 1, 0,
|
||||
1, 1, 1,
|
||||
0, 1, 0,
|
||||
1, 0, 1,
|
||||
0, 0, 0,
|
||||
0, 0, 0,
|
||||
],
|
||||
[CHAR.UP]: [
|
||||
0, 1, 1, 1, 1, 1, 0,
|
||||
1, 1, 1, 0, 1, 1, 1,
|
||||
1, 1, 0, 0, 0, 1, 1,
|
||||
1, 1, 0, 0, 0, 1, 1,
|
||||
0, 1, 1, 1, 1, 1, 0,
|
||||
0, 0, 0, 0, 0, 0, 0,
|
||||
],
|
||||
[CHAR.LEFT]: [
|
||||
0, 1, 1, 1, 1, 1, 0,
|
||||
1, 1, 1, 0, 0, 1, 1,
|
||||
1, 1, 0, 0, 0, 1, 1,
|
||||
1, 1, 1, 0, 0, 1, 1,
|
||||
0, 1, 1, 1, 1, 1, 0,
|
||||
0, 0, 0, 0, 0, 0, 0,
|
||||
],
|
||||
[CHAR.DOWN]: [
|
||||
0, 1, 1, 1, 1, 1, 0,
|
||||
1, 1, 0, 0, 0, 1, 1,
|
||||
1, 1, 0, 0, 0, 1, 1,
|
||||
1, 1, 1, 0, 1, 1, 1,
|
||||
0, 1, 1, 1, 1, 1, 0,
|
||||
0, 0, 0, 0, 0, 0, 0,
|
||||
],
|
||||
[CHAR.RIGHT]: [
|
||||
0, 1, 1, 1, 1, 1, 0,
|
||||
1, 1, 0, 0, 1, 1, 1,
|
||||
1, 1, 0, 0, 0, 1, 1,
|
||||
1, 1, 0, 0, 1, 1, 1,
|
||||
0, 1, 1, 1, 1, 1, 0,
|
||||
0, 0, 0, 0, 0, 0, 0,
|
||||
],
|
||||
[CHAR.PI]: [
|
||||
0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0,
|
||||
1, 1, 1, 1, 1,
|
||||
0, 1, 0, 1, 0,
|
||||
0, 1, 0, 1, 0,
|
||||
0, 0, 0, 0, 0,
|
||||
],
|
||||
}
|
||||
};
|
54
icons.ts
Normal file
54
icons.ts
Normal file
@ -0,0 +1,54 @@
|
||||
export const codeIcon = [
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 1, 0, 0,
|
||||
0, 1, 1, 0, 0, 1, 1, 0,
|
||||
0, 1, 0, 0, 0, 0, 1, 0,
|
||||
0, 1, 0, 0, 0, 0, 1, 0,
|
||||
0, 1, 1, 0, 0, 1, 1, 0,
|
||||
0, 0, 1, 0, 0, 1, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
];
|
||||
|
||||
export const spriteIcon = [
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 1, 1, 1, 0, 0,
|
||||
0, 1, 1, 0, 1, 1, 1, 0,
|
||||
0, 1, 1, 1, 1, 0, 0, 0,
|
||||
0, 1, 1, 1, 0, 0, 0, 0,
|
||||
0, 1, 1, 1, 1, 1, 1, 0,
|
||||
0, 0, 1, 1, 1, 1, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
];
|
||||
|
||||
export const mapIcon = [
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 1, 1, 1, 1, 1, 1, 0,
|
||||
0, 1, 0, 1, 0, 0, 1, 0,
|
||||
0, 1, 0, 1, 1, 1, 1, 0,
|
||||
0, 1, 1, 1, 0, 0, 1, 0,
|
||||
0, 1, 0, 1, 0, 0, 1, 0,
|
||||
0, 1, 1, 1, 1, 1, 1, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
];
|
||||
|
||||
export const sheetsIcon = [
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 1, 1, 0, 0, 1, 1, 0,
|
||||
0, 1, 1, 0, 0, 1, 1, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 1, 1, 0, 0, 1, 1, 0,
|
||||
0, 1, 1, 0, 0, 1, 1, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
];
|
||||
|
||||
export const trashIcon = [
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 1, 1, 0, 0, 0,
|
||||
0, 1, 1, 1, 1, 1, 1, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 1, 1, 1, 0, 0,
|
||||
0, 0, 1, 1, 1, 1, 0, 0,
|
||||
0, 0, 1, 1, 1, 1, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
];
|
64
index.ts
Normal file
64
index.ts
Normal file
@ -0,0 +1,64 @@
|
||||
import {
|
||||
mainloop,
|
||||
frame,
|
||||
clearScreen,
|
||||
} from "./window.ts";
|
||||
import { runCode } from "./runcode.ts";
|
||||
import { getCodeSheet } from "./sheet.ts";
|
||||
import { refreshKeyboard, keyPressed, K } from "./keyboard.ts";
|
||||
import { repl, resetRepl } from "./repl.ts";
|
||||
import { addToContext } from "./runcode.ts";
|
||||
import { editmode } from "./editmode.ts";
|
||||
import { refreshMouse } from "./mouse.ts";
|
||||
import { camera } from "./builtins.ts";
|
||||
|
||||
// deno-lint-ignore no-explicit-any
|
||||
let game: any = null;
|
||||
|
||||
let mode: "play" | "edit" | "repl" = "repl";
|
||||
|
||||
addToContext("play", () => {
|
||||
mode = "play";
|
||||
game = runCode(getCodeSheet(0));
|
||||
game.init();
|
||||
});
|
||||
|
||||
clearScreen();
|
||||
|
||||
await mainloop(async (_t) => {
|
||||
// TODO: use t
|
||||
if (keyPressed(K.ESCAPE)) {
|
||||
const modeTo = ({
|
||||
play: "repl",
|
||||
edit: "repl",
|
||||
repl: "edit",
|
||||
} as const)[mode];
|
||||
if (mode === "play") {
|
||||
resetRepl();
|
||||
}
|
||||
if (mode === "edit") {
|
||||
clearScreen();
|
||||
}
|
||||
mode = modeTo;
|
||||
} else {
|
||||
if (mode === "play") {
|
||||
if (game) {
|
||||
game.update();
|
||||
game.draw();
|
||||
}
|
||||
frame();
|
||||
} else if (mode === "repl") {
|
||||
repl.update();
|
||||
camera(0, 0);
|
||||
repl.draw();
|
||||
frame();
|
||||
} else if (mode === "edit") {
|
||||
await editmode.update();
|
||||
camera(0, 0);
|
||||
editmode.draw();
|
||||
frame();
|
||||
}
|
||||
}
|
||||
refreshKeyboard();
|
||||
refreshMouse();
|
||||
}, false);
|
1
initialCart.json
Normal file
1
initialCart.json
Normal file
@ -0,0 +1 @@
|
||||
[{"sheet_type":"code","value":"// Sample\n\nreturn {\n\tinit() {},\n\tupdate() {},\n\tdraw() {\n\t\tcls();\n\t\ttxt(10,10,\"Hello, World!\");\n\t}\n}"},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null},{"sheet_type":"none","value":null}]
|
174
keyboard.ts
Normal file
174
keyboard.ts
Normal file
@ -0,0 +1,174 @@
|
||||
import { font, CHAR } from "./font.ts";
|
||||
|
||||
const keyboard = new Map<number, {first: boolean, repeat: boolean, held: boolean}>();
|
||||
|
||||
export const K = {
|
||||
ESCAPE: 256,
|
||||
ENTER: 257,
|
||||
TAB: 258,
|
||||
BACKSPACE: 259,
|
||||
INSERT: 260,
|
||||
DELETE: 261,
|
||||
ARROW_RIGHT: 262,
|
||||
ARROW_LEFT: 263,
|
||||
ARROW_DOWN: 264,
|
||||
ARROW_UP: 265,
|
||||
PAGE_UP: 266,
|
||||
PAGE_DOWN: 267,
|
||||
HOME: 268,
|
||||
END: 269,
|
||||
CAPS_LOCK: 280,
|
||||
F1: 290,
|
||||
F2: 291,
|
||||
F3: 292,
|
||||
F4: 293,
|
||||
F5: 294,
|
||||
F6: 295,
|
||||
F7: 296,
|
||||
F8: 297,
|
||||
F9: 298,
|
||||
F10: 299,
|
||||
F11: 300,
|
||||
F12: 301,
|
||||
SHIFT_LEFT: 340,
|
||||
CTRL_LEFT: 341,
|
||||
ALT_LEFT: 342,
|
||||
SHIFT_RIGHT: 344,
|
||||
CTRL_RIGHT: 345,
|
||||
ALT_RIGHT: 346,
|
||||
}
|
||||
|
||||
export const shiftMap = {
|
||||
"1": "!",
|
||||
"2": "@",
|
||||
"3": "#",
|
||||
"4": "$",
|
||||
"5": "%",
|
||||
"6": "^",
|
||||
"7": "&",
|
||||
"8": "*",
|
||||
"9": "(",
|
||||
"0": ")",
|
||||
"`": "~",
|
||||
"-": "_",
|
||||
"=": "+",
|
||||
"[": "{",
|
||||
"]": "}",
|
||||
"\\": "|",
|
||||
";": ":",
|
||||
"'": '"',
|
||||
",": "<",
|
||||
".": ">",
|
||||
"/": "?",
|
||||
}
|
||||
|
||||
export const altMap = {
|
||||
"w": CHAR.UP,
|
||||
"a": CHAR.LEFT,
|
||||
"s": CHAR.DOWN,
|
||||
"d": CHAR.RIGHT,
|
||||
"p": CHAR.PI,
|
||||
}
|
||||
|
||||
addEventListener("keydown", (evt) => {
|
||||
// console.log("keydown", evt.key, evt.key.charCodeAt(0));
|
||||
const key = evt.key.charCodeAt(0);
|
||||
const isRepeat = keyboard.has(key) && keyboard.get(key)?.held!;
|
||||
keyboard.set(key, {
|
||||
first: !isRepeat,
|
||||
repeat: isRepeat,
|
||||
held: true,
|
||||
});
|
||||
});
|
||||
|
||||
addEventListener("keyup", (evt) => {
|
||||
// console.log("keyup", evt.key, evt.key.charCodeAt(0));
|
||||
const key = evt.key.charCodeAt(0);
|
||||
keyboard.set(key, {
|
||||
first: false,
|
||||
repeat: false,
|
||||
held: false,
|
||||
});
|
||||
});
|
||||
|
||||
export const refreshKeyboard = () => {
|
||||
keyboard.forEach(({held}, key) => {
|
||||
if (!held) {
|
||||
keyboard.delete(key);
|
||||
} else {
|
||||
keyboard.set(key, {
|
||||
first: false,
|
||||
repeat: false,
|
||||
held: true,
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const keyPressed = (key: string | number) => {
|
||||
if (typeof key === "string") {
|
||||
key = key.toUpperCase().charCodeAt(0);
|
||||
}
|
||||
return keyboard.has(key) && (keyboard.get(key)?.first! || keyboard.get(key)?.repeat!);
|
||||
}
|
||||
|
||||
export const keyDown = (key: string | number) => {
|
||||
if (typeof key === "string") {
|
||||
key = key.toUpperCase().charCodeAt(0);
|
||||
}
|
||||
return keyboard.has(key) && keyboard.get(key)?.held!;
|
||||
}
|
||||
|
||||
export const shiftKeyDown = () => {
|
||||
return keyDown(K.SHIFT_LEFT) || keyDown(K.SHIFT_RIGHT);
|
||||
}
|
||||
|
||||
export const ctrlKeyDown = () => {
|
||||
return keyDown(K.CTRL_LEFT) || keyDown(K.CTRL_RIGHT);
|
||||
}
|
||||
|
||||
export const altKeyDown = () => {
|
||||
return keyDown(K.ALT_LEFT) || keyDown(K.ALT_RIGHT);
|
||||
}
|
||||
|
||||
export const keyReleased = (key: string | number) => {
|
||||
if (typeof key === "string") {
|
||||
key = key.toUpperCase().charCodeAt(0);
|
||||
}
|
||||
return keyboard.has(key) && !keyboard.get(key)?.held!;
|
||||
}
|
||||
|
||||
export const getKeysPressed = () => {
|
||||
const result = [...keyboard.entries()].filter(([_key, value]) => {
|
||||
return value.first || value.repeat;
|
||||
}).map(([key]) => key);
|
||||
return result;
|
||||
}
|
||||
|
||||
export const getKeyboardString = () => {
|
||||
let str = "";
|
||||
if (ctrlKeyDown()) {
|
||||
return str;
|
||||
}
|
||||
for (const key of getKeysPressed()) {
|
||||
let char = String.fromCharCode(key).toLowerCase();
|
||||
if (shiftKeyDown()) {
|
||||
if (char in shiftMap) {
|
||||
char = shiftMap[char as keyof typeof shiftMap];
|
||||
} else {
|
||||
char = char.toUpperCase();
|
||||
}
|
||||
}
|
||||
if (altKeyDown()) {
|
||||
if (char in altMap) {
|
||||
char = altMap[char as keyof typeof altMap];
|
||||
} else {
|
||||
char = char.toUpperCase();
|
||||
}
|
||||
}
|
||||
if (char in font.chars) {
|
||||
str += char;
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
215
maptab.ts
Normal file
215
maptab.ts
Normal file
@ -0,0 +1,215 @@
|
||||
import { clearScreen, fillRect } from "./window.ts";
|
||||
import { drawSprite, drawText } from "./builtins.ts";
|
||||
import { COLOR } from "./colors.ts";
|
||||
import { getMapSheet, getSheet, setSheet } from "./sheet.ts";
|
||||
import { M, mouseClick, mouseDown, mouseHeld, mousePos } from "./mouse.ts";
|
||||
import { drawTransparentRect, drawVoidRect, inRect, reGrid } from "./util.ts";
|
||||
import { page } from "./viewsheets.ts";
|
||||
import { useSpritesheet } from "./builtins.ts";
|
||||
import { keyPressed } from "./keyboard.ts";
|
||||
import { K } from "./keyboard.ts";
|
||||
|
||||
const state = {
|
||||
selectedSpriteSheet: 0,
|
||||
selectedSprite: 0,
|
||||
viewX: 0,
|
||||
viewY: 0,
|
||||
dragging: false,
|
||||
dragFromViewX: 0,
|
||||
dragFromViewY: 0,
|
||||
dragFromX: 0,
|
||||
dragFromY: 0,
|
||||
get spriteSheetPage() {
|
||||
return Math.floor(this.selectedSprite/64);
|
||||
},
|
||||
set spriteSheetPage(val) {
|
||||
this.selectedSprite = 64*val+this.spriteWithinPage;
|
||||
},
|
||||
get spriteWithinPage() {
|
||||
return this.selectedSprite%64;
|
||||
},
|
||||
set spriteWithinPage(val) {
|
||||
this.selectedSprite = 64*this.spriteSheetPage+val;
|
||||
},
|
||||
get map() {
|
||||
return getMapSheet(page.activeSheet);
|
||||
},
|
||||
set map(val) {
|
||||
setSheet(page.activeSheet, "map", val);
|
||||
},
|
||||
setInPatch(i: number, sprsheet: number, sprite: number) {
|
||||
const cellVal = this.map.subgrid(this.viewX, this.viewY, patchW, patchH).values[i];
|
||||
if (cellVal) {
|
||||
cellVal[0] = sprsheet
|
||||
cellVal[1] = sprite;
|
||||
}
|
||||
},
|
||||
get patch() {
|
||||
return this.map.subgrid(this.viewX, this.viewY, patchW, patchH);
|
||||
}
|
||||
}
|
||||
|
||||
const patchX = 0;
|
||||
const patchY = 8;
|
||||
const patchW = 16;
|
||||
const patchH = 9;
|
||||
|
||||
const spriteW = 8;
|
||||
const spriteH = 8;
|
||||
|
||||
const spriteSheetX = 0;
|
||||
const spriteSheetY = 88;
|
||||
const spriteSheetW = 16;
|
||||
const spriteSheetH = 4;
|
||||
|
||||
const spriteSheetPickerX = 0;
|
||||
const spriteSheetPickerY = 81;
|
||||
const spriteSheetPickerW = 16;
|
||||
const spriteSheetPickerH = 1;
|
||||
const spriteSheetPickerTabW = 7;
|
||||
const spriteSheetPickerTabH = 7;
|
||||
|
||||
const spriteSheetPageSwapX = 121;
|
||||
const spriteSheetPageSwapY = 81;
|
||||
const spriteSheetPageSwapW = 7;
|
||||
const spriteSheetPageSwapH = 7;
|
||||
|
||||
const update = () => {
|
||||
const {x: mouseX, y: mouseY} = mousePos();
|
||||
const inPatch = inRect(mouseX, mouseY, patchX, patchY, patchW*spriteW, patchH*spriteH - 2);
|
||||
const inSpriteSheetPicker = inRect(mouseX, mouseY, spriteSheetPickerX, spriteSheetPickerY, spriteSheetPickerW*spriteSheetPickerTabW, spriteSheetPickerH*spriteSheetPickerTabH);
|
||||
const inSpriteSheet = inRect(mouseX, mouseY, spriteSheetX, spriteSheetY, spriteSheetW*spriteW, spriteSheetH*spriteH);
|
||||
const inSpriteSheetPageSwap = inRect(mouseX, mouseY, spriteSheetPageSwapX, spriteSheetPageSwapY, spriteSheetPageSwapW, spriteSheetPageSwapH);
|
||||
if (mouseHeld()) {
|
||||
if (inPatch) {
|
||||
const {x, y} = reGrid(mouseX, mouseY, patchX, patchY, spriteW, spriteH);
|
||||
const cellNumber = patchW*y+x;
|
||||
state.setInPatch(cellNumber, state.selectedSpriteSheet, state.selectedSprite);
|
||||
}
|
||||
if (inSpriteSheetPicker) {
|
||||
const {x, y} = reGrid(mouseX, mouseY, spriteSheetPickerX, spriteSheetPickerY, spriteSheetPickerTabW, spriteSheetPickerTabH);
|
||||
state.selectedSpriteSheet = spriteSheetPickerW*y+x;
|
||||
}
|
||||
if (inSpriteSheet) {
|
||||
const {x, y} = reGrid(mouseX, mouseY, spriteSheetX, spriteSheetY, spriteW, spriteH);
|
||||
state.spriteWithinPage = spriteSheetW*y+x;
|
||||
}
|
||||
} else if (mouseDown(M.MIDDLE)) {
|
||||
if (inPatch) {
|
||||
const {x, y} = reGrid(mouseX, mouseY, patchX, patchY, spriteW, spriteH);
|
||||
state.dragging = true;
|
||||
state.dragFromX = x;
|
||||
state.dragFromY = y;
|
||||
state.dragFromViewX = state.viewX;
|
||||
state.dragFromViewY = state.viewY;
|
||||
}
|
||||
} else if (mouseHeld(M.MIDDLE)) {
|
||||
if (state.dragging) {
|
||||
const {x, y} = reGrid(mouseX, mouseY, patchX, patchY, spriteW, spriteH);
|
||||
state.viewX = state.dragFromViewX - x + state.dragFromX;
|
||||
state.viewY = state.dragFromViewY - y + state.dragFromY;
|
||||
}
|
||||
} else if (mouseClick(M.MIDDLE)) {
|
||||
state.dragging = false;
|
||||
} else if (mouseClick()) {
|
||||
if (inSpriteSheetPageSwap) {
|
||||
state.spriteSheetPage = (1+state.spriteSheetPage)%2;
|
||||
}
|
||||
}
|
||||
if (keyPressed(K.ARROW_RIGHT)) {
|
||||
state.viewX += 1;
|
||||
}
|
||||
if (keyPressed(K.ARROW_LEFT)) {
|
||||
state.viewX -= 1;
|
||||
}
|
||||
if (keyPressed(K.ARROW_UP)) {
|
||||
state.viewY -= 1;
|
||||
}
|
||||
if (keyPressed(K.ARROW_DOWN)) {
|
||||
state.viewY += 1;
|
||||
}
|
||||
}
|
||||
|
||||
const outlineRect = (x: number, y: number, w: number, h: number, color: number) => {
|
||||
fillRect(x, y, w, 1, color);
|
||||
fillRect(x, y, 1, h, color);
|
||||
fillRect(x+w-1, y, 1, h, color);
|
||||
fillRect(x, y+h-1, w, 1, color);
|
||||
}
|
||||
|
||||
const draw = () => {
|
||||
const {
|
||||
selectedSpriteSheet,
|
||||
spriteWithinPage,
|
||||
spriteSheetPage,
|
||||
} = state;
|
||||
clearScreen();
|
||||
fillRect(0, 8, 128, 112, COLOR.DARKGRAY);
|
||||
|
||||
// Draw the current patch
|
||||
drawVoidRect(patchX-1, patchY-1, (patchW*spriteW)+2, (patchH*spriteH)+2);
|
||||
state.patch.values.forEach((val, i) => {
|
||||
const spriteX = patchX+spriteW*(i%patchW);
|
||||
const spriteY = patchY+spriteH*Math.floor(i/patchW);
|
||||
if (!val) {
|
||||
return;
|
||||
}
|
||||
const [sprsheet, sprite] = val;
|
||||
drawTransparentRect(spriteX, spriteY, 8, 8);
|
||||
if (getSheet(sprsheet).sheet_type === "spritesheet") {
|
||||
useSpritesheet(sprsheet);
|
||||
drawSprite(spriteX, spriteY, sprite);
|
||||
}
|
||||
});
|
||||
|
||||
// Draw the bar
|
||||
fillRect(spriteSheetPickerX, spriteSheetPickerY-1, 128, 1, COLOR.BLACK);
|
||||
fillRect(spriteSheetPickerX, spriteSheetPickerY, 128, 7, COLOR.DARKGRAY);
|
||||
|
||||
// Draw the spritesheet picker
|
||||
fillRect(spriteSheetPickerX, spriteSheetPickerY, spriteSheetPickerTabW*spriteSheetPickerW, spriteSheetPickerTabW, COLOR.BLACK);
|
||||
Array(spriteSheetPickerW*spriteSheetPickerH).fill(0).forEach((_, i) => {
|
||||
const tabX = spriteSheetPickerX+spriteSheetPickerTabW*(i%spriteSheetPickerW);
|
||||
const tabY = spriteSheetPickerY+spriteSheetPickerTabH*Math.floor(i/spriteSheetPickerW);
|
||||
let color = COLOR.DARKGREEN;
|
||||
if (getSheet(i).sheet_type !== "spritesheet") {
|
||||
color = COLOR.BROWN;
|
||||
}
|
||||
if (i === page.activeSheet) {
|
||||
color = COLOR.PURPLE;
|
||||
}
|
||||
if (i === selectedSpriteSheet) {
|
||||
color = {
|
||||
[COLOR.BROWN]: COLOR.TAN,
|
||||
[COLOR.DARKGREEN]: COLOR.GREEN,
|
||||
[COLOR.PURPLE]: COLOR.PINK,
|
||||
}[color];
|
||||
}
|
||||
fillRect(tabX, tabY, spriteSheetPickerTabW, spriteSheetPickerTabH, color);
|
||||
drawText(tabX+2, tabY+1, ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"][i]);
|
||||
});
|
||||
|
||||
// Draw the spritesheet page swap button
|
||||
fillRect(spriteSheetPageSwapX, spriteSheetPageSwapY, spriteSheetPageSwapW, spriteSheetPageSwapH, COLOR.BLUE);
|
||||
drawText(spriteSheetPageSwapX+2, spriteSheetPageSwapY+1, state.spriteSheetPage.toString());
|
||||
|
||||
// Draw the spritesheet
|
||||
fillRect(spriteSheetX, spriteSheetY, (spriteSheetW*spriteW), (spriteSheetH*spriteH), COLOR.BLACK);
|
||||
if (getSheet(selectedSpriteSheet).sheet_type === "spritesheet") {
|
||||
useSpritesheet(selectedSpriteSheet);
|
||||
Array(64).fill(0).forEach((_, i) => {
|
||||
const sprI = i+64*spriteSheetPage;
|
||||
const sprX = spriteSheetX+spriteW*(i%spriteSheetW);
|
||||
const sprY = spriteSheetY+spriteH*Math.floor(i/spriteSheetW);
|
||||
drawSprite(sprX, sprY, sprI);
|
||||
if (i === spriteWithinPage) {
|
||||
outlineRect(sprX, sprY, spriteW, spriteH, COLOR.WHITE);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export const maptab = {
|
||||
update,
|
||||
draw,
|
||||
}
|
96
mouse.ts
Normal file
96
mouse.ts
Normal file
@ -0,0 +1,96 @@
|
||||
import { WindowMouseEvent } from "https://deno.land/x/dwm@0.3.3/mod.ts";
|
||||
import { gameWindow } from "./window.ts";
|
||||
|
||||
export const M = {
|
||||
NONE: -1,
|
||||
LEFT: 0,
|
||||
RIGHT: 1,
|
||||
MIDDLE: 2,
|
||||
}
|
||||
|
||||
const mouseButtonsDown = {
|
||||
[M.LEFT]: false,
|
||||
[M.RIGHT]: false,
|
||||
[M.MIDDLE]: false,
|
||||
};
|
||||
const mouseEvents: Array<{
|
||||
type: "click" | "down" | "up" | "move" | "dblclick",
|
||||
button: typeof M[keyof typeof M],
|
||||
x: number,
|
||||
y: number,
|
||||
prevX?: number,
|
||||
prevY?: number
|
||||
}> = [];
|
||||
|
||||
let mouseX = 0;
|
||||
let mouseY = 0;
|
||||
|
||||
const eventPixelCoords = (evt: WindowMouseEvent) => {
|
||||
const {width, height} = gameWindow.size;
|
||||
const pixX = Math.floor(128*evt.clientX/width);
|
||||
const pixY = Math.floor(128*evt.clientY/height);
|
||||
return {
|
||||
x: pixX,
|
||||
y: pixY,
|
||||
}
|
||||
}
|
||||
|
||||
addEventListener("dblclick", (evt) => {
|
||||
mouseEvents.push({type: "dblclick", button: evt.button, ...eventPixelCoords(evt)});
|
||||
});
|
||||
|
||||
addEventListener("click", (evt) => {
|
||||
mouseEvents.push({type: "click", button: evt.button, ...eventPixelCoords(evt)});
|
||||
});
|
||||
|
||||
addEventListener("mousedown", (evt) => {
|
||||
mouseButtonsDown[evt.button] = true;
|
||||
mouseEvents.push({type: "down", button: evt.button, ...eventPixelCoords(evt)});
|
||||
});
|
||||
|
||||
addEventListener("mouseup", (evt) => {
|
||||
mouseButtonsDown[evt.button] = false;
|
||||
mouseEvents.push({type: "up", button: evt.button, ...eventPixelCoords(evt)});
|
||||
});
|
||||
|
||||
addEventListener("mousemove", (evt) => {
|
||||
const coords = eventPixelCoords(evt);
|
||||
mouseEvents.push({type: "move", button: evt.button, ...eventPixelCoords(evt), prevX: mouseX, prevY: mouseY});
|
||||
mouseX = coords.x;
|
||||
mouseY = coords.y;
|
||||
});
|
||||
|
||||
export const mousePos = () => {
|
||||
return {
|
||||
x: mouseX,
|
||||
y: mouseY,
|
||||
}
|
||||
}
|
||||
|
||||
export const getMouseX = () => {
|
||||
return mouseX;
|
||||
}
|
||||
|
||||
export const getMouseY = () => {
|
||||
return mouseY;
|
||||
}
|
||||
|
||||
export const refreshMouse = () => {
|
||||
mouseEvents.length = 0;
|
||||
}
|
||||
|
||||
export const mouseDown = (button: number = M.LEFT) => {
|
||||
return mouseEvents.some(ev => ev.button === button && ev.type === "down");
|
||||
}
|
||||
|
||||
export const mouseClick = (button: number = M.LEFT) => {
|
||||
return mouseEvents.some(ev => ev.button === button && ev.type === "click");
|
||||
}
|
||||
|
||||
export const mouseDoubleClick = (button: number = M.LEFT) => {
|
||||
return mouseEvents.some(ev => ev.button === button && ev.type === "dblclick");
|
||||
}
|
||||
|
||||
export const mouseHeld = (button: number = M.LEFT) => {
|
||||
return mouseButtonsDown[button];
|
||||
}
|
63
nonetab.ts
Normal file
63
nonetab.ts
Normal file
@ -0,0 +1,63 @@
|
||||
import { clearScreen, fillRect } from "./window.ts";
|
||||
import { drawIcon, drawText } from "./builtins.ts";
|
||||
import { COLOR } from "./colors.ts";
|
||||
import { getSheet, setSheet } from "./sheet.ts";
|
||||
import { mouseClick, mousePos } from "./mouse.ts";
|
||||
import { reGridWithGap } from "./util.ts";
|
||||
import { page } from "./viewsheets.ts";
|
||||
import { useSpritesheet } from "./builtins.ts";
|
||||
import { codeIcon, mapIcon, spriteIcon } from "./icons.ts";
|
||||
|
||||
const gridX = 8;
|
||||
const gridY = 40;
|
||||
const cellW = 8;
|
||||
const cellH = 8;
|
||||
const gapX = 8;
|
||||
const gapY = 8;
|
||||
|
||||
const sheetTypes = ["code", "spritesheet", "map"] as const;
|
||||
const defaultSheetVal = {
|
||||
code: () => "",
|
||||
spritesheet: () => Array(128).fill(0).map(() => Array(64).fill(0)),
|
||||
map: () => Array(64*64).fill(0).map(() => [0, 0]),
|
||||
none: () =>null,
|
||||
}
|
||||
|
||||
const update = () => {
|
||||
if (mouseClick()) {
|
||||
const {x: mouseX, y: mouseY} = mousePos();
|
||||
const g = reGridWithGap(mouseX, mouseY, gridX, gridY, cellW, cellH, gapX, gapY);
|
||||
if (g) {
|
||||
const {x, y: _y} = g;
|
||||
const sheetType = sheetTypes[x];
|
||||
setSheet(page.activeSheet, sheetType, defaultSheetVal[sheetType]());
|
||||
page.tab = getSheet(page.activeSheet).sheet_type;
|
||||
}
|
||||
}
|
||||
}
|
||||
const draw = () => {
|
||||
clearScreen();
|
||||
useSpritesheet(page.activeSheet);
|
||||
fillRect(0, 8, 128, 112, COLOR.BLACK);
|
||||
|
||||
drawText(4, 16, "Click an icon below to choose");
|
||||
drawText(4, 16+7, "this sheet's type...");
|
||||
|
||||
// Draw the spritesheet
|
||||
sheetTypes.forEach((sheetType, i) => {
|
||||
const sx = gridX+(cellW+gapX)*(i%6);
|
||||
const sy = gridY+(cellH+gapY)*Math.floor(i/6);
|
||||
const icon = {
|
||||
code: codeIcon,
|
||||
spritesheet: spriteIcon,
|
||||
map: mapIcon,
|
||||
none: null,
|
||||
}[sheetType];
|
||||
drawIcon(sx, sy, icon, COLOR.BLUE);
|
||||
});
|
||||
}
|
||||
|
||||
export const nonetab = {
|
||||
update,
|
||||
draw,
|
||||
}
|
130
pico8_builtins.txt
Normal file
130
pico8_builtins.txt
Normal file
@ -0,0 +1,130 @@
|
||||
- [x] load
|
||||
- [x] save
|
||||
- [ ] folder
|
||||
- [ ] ls
|
||||
- [x] run
|
||||
- [ ] stop
|
||||
- [ ] resume
|
||||
- [ ] assert
|
||||
- [ ] reboot
|
||||
- [ ] reset
|
||||
- [ ] info
|
||||
- [ ] flip
|
||||
- [x] printh (as `log`)
|
||||
- [ ] time/t
|
||||
- [ ] stat
|
||||
- [ ] extcmd
|
||||
|
||||
- [ ] clip
|
||||
- [x] pset
|
||||
- [ ] pget
|
||||
- [ ] sget
|
||||
- [ ] sset
|
||||
- [ ] fget
|
||||
- [ ] fset
|
||||
- [?] print
|
||||
- [ ] cursor
|
||||
- [ ] color
|
||||
- [x] cls
|
||||
- [x] camera
|
||||
- [x] circ
|
||||
- [x] circfill
|
||||
- [x] oval
|
||||
- [x] ovalfill
|
||||
- [ ] line
|
||||
- [x] rect
|
||||
- [x] rectfill
|
||||
- [ ] pal
|
||||
- [ ] palt
|
||||
- [x] spr
|
||||
- [ ] sspr
|
||||
- [ ] fillp
|
||||
|
||||
- [x] btn
|
||||
- [x] btnp
|
||||
|
||||
- [ ] sfx
|
||||
- [ ] music
|
||||
|
||||
- [x] mget
|
||||
- [x] mset
|
||||
- [x] map
|
||||
- [ ] tline
|
||||
|
||||
- [ ] peek
|
||||
- [ ] poke
|
||||
- [ ] peek2
|
||||
- [ ] poke2
|
||||
- [ ] peek4
|
||||
- [ ] poke4
|
||||
- [ ] memcpy
|
||||
- [ ] reload
|
||||
- [ ] cstore
|
||||
- [ ] memset
|
||||
|
||||
- [ ] menuitem
|
||||
|
||||
- [ ] cartdata
|
||||
- [ ] dget
|
||||
- [ ] dset
|
||||
|
||||
- [ ] serial
|
||||
|
||||
- [ ] setmetatable
|
||||
- [ ] getmetatable
|
||||
- [ ] rawset
|
||||
- [ ] rawget
|
||||
- [ ] rawequal
|
||||
- [ ] rawlen
|
||||
|
||||
|
||||
== most things below here handled by js or easily included.
|
||||
|
||||
-- js Array has most things we want here
|
||||
- [ ] add
|
||||
- [ ] del
|
||||
- [ ] deli
|
||||
- [ ] count
|
||||
- [ ] all
|
||||
- [ ] foreach
|
||||
- [ ] pairs
|
||||
|
||||
- [x] max
|
||||
- [x] min
|
||||
- [ ] mid
|
||||
- [x] flr
|
||||
- [x] ceil
|
||||
- [x] cos
|
||||
- [x] sin
|
||||
- [x] atan2
|
||||
- [x] sqrt
|
||||
- [x] abs
|
||||
- [x] rnd
|
||||
- [ ] srand
|
||||
|
||||
-- skipping these in favor of bitwise operations if needed
|
||||
- [ ] band
|
||||
- [ ] bor
|
||||
- [ ] bxor
|
||||
- [ ] bnot
|
||||
- [ ] shl
|
||||
- [ ] shr
|
||||
- [ ] lshr
|
||||
- [ ] rotl
|
||||
- [ ] rotr
|
||||
|
||||
-- js comes with stuff here (String, Number, typeof, etc.)
|
||||
- [ ] tostr
|
||||
- [ ] tonum
|
||||
- [ ] chr
|
||||
- [ ] ord
|
||||
- [ ] sub
|
||||
- [ ] split
|
||||
- [ ] type
|
||||
|
||||
-- js comes with stuff here
|
||||
- [ ] cocreate
|
||||
- [ ] coresume
|
||||
- [ ] assert
|
||||
- [ ] costatus
|
||||
- [ ] yield
|
130
repl.ts
Normal file
130
repl.ts
Normal file
@ -0,0 +1,130 @@
|
||||
import { drawText} from "./builtins.ts";
|
||||
import { getKeysPressed, shiftKeyDown, shiftMap, K } from "./keyboard.ts";
|
||||
import { font } from "./font.ts";
|
||||
import { addToContext, evalCode } from "./runcode.ts";
|
||||
import { clearScreen, fillRect } from "./window.ts";
|
||||
import { COLOR } from "./colors.ts";
|
||||
|
||||
const lineHeight = 6;
|
||||
|
||||
const history: Array<string> = [];
|
||||
let historyIndex = history.length;
|
||||
let textLinesAbove: Array<string> = [];
|
||||
let maxLineLen = 0;
|
||||
let currentLine = "";
|
||||
let index = 0;
|
||||
|
||||
export const resetRepl = () => {
|
||||
historyIndex = history.length;
|
||||
textLinesAbove.length = 0;
|
||||
maxLineLen = 0;
|
||||
currentLine = "";
|
||||
index = 0;
|
||||
}
|
||||
|
||||
const print = (arg: unknown) => {
|
||||
textLinesAbove.push(...String(arg).split("\n").flatMap((line)=>{
|
||||
const wrap = [];
|
||||
while (line.length) {
|
||||
wrap.push(line.slice(0,32));
|
||||
line = line.slice(32);
|
||||
}
|
||||
return wrap;
|
||||
}));
|
||||
textLinesAbove = textLinesAbove.slice(-20);
|
||||
}
|
||||
|
||||
const printVal = (arg: unknown) => {
|
||||
print(JSON.stringify(arg));
|
||||
}
|
||||
|
||||
addToContext("print", print);
|
||||
addToContext("printVal", printVal);
|
||||
|
||||
const update = () => {
|
||||
// TODO: model this after the newer editmode.ts version using getKeyboardString
|
||||
for (const key of getKeysPressed()) {
|
||||
let char = String.fromCharCode(key).toLowerCase();
|
||||
if (shiftKeyDown()) {
|
||||
if (char in shiftMap) {
|
||||
char = shiftMap[char as keyof typeof shiftMap];
|
||||
} else {
|
||||
char = char.toUpperCase();
|
||||
}
|
||||
}
|
||||
if (char in font.chars) {
|
||||
currentLine = currentLine.slice(0, index)+char+currentLine.slice(index);
|
||||
index += 1;
|
||||
} else if (key === K.BACKSPACE) {
|
||||
if (index > 0) {
|
||||
currentLine = currentLine.slice(0, index-1)+currentLine.slice(index);
|
||||
index -= 1;
|
||||
}
|
||||
} else if (key === K.ARROW_LEFT) {
|
||||
index -= 1;
|
||||
if (index < 0) {
|
||||
index = 0;
|
||||
}
|
||||
} else if (key === K.ARROW_RIGHT) {
|
||||
index += 1;
|
||||
if (index > currentLine.length) {
|
||||
index = currentLine.length;
|
||||
}
|
||||
} else if (key === K.ARROW_UP) {
|
||||
historyIndex -= 1;
|
||||
if (historyIndex < 0) {
|
||||
historyIndex = -1;
|
||||
}
|
||||
const lineAtHistory = history[historyIndex] ?? "";
|
||||
currentLine = lineAtHistory;
|
||||
index = currentLine.length;
|
||||
} else if (key === K.ARROW_DOWN) {
|
||||
historyIndex += 1;
|
||||
if (historyIndex > history.length) {
|
||||
historyIndex = history.length;
|
||||
}
|
||||
const lineAtHistory = history[historyIndex] ?? "";
|
||||
currentLine = lineAtHistory;
|
||||
index = currentLine.length;
|
||||
} else if (key === K.ENTER) {
|
||||
if (currentLine) {
|
||||
history.push(currentLine);
|
||||
historyIndex = history.length;
|
||||
}
|
||||
print("> "+currentLine);
|
||||
try {
|
||||
const ran = evalCode(currentLine);
|
||||
if (ran !== undefined) {
|
||||
printVal(ran);
|
||||
}
|
||||
} catch (err) {
|
||||
print(err.name+":\n"+err.message);
|
||||
}
|
||||
maxLineLen = 0;
|
||||
currentLine = "";
|
||||
index = 0;
|
||||
}
|
||||
}
|
||||
maxLineLen = Math.max(maxLineLen, currentLine.length);
|
||||
}
|
||||
|
||||
const drawTextAbove = () => {
|
||||
textLinesAbove.forEach((line, i) => {
|
||||
fillRect(0, 1+i*lineHeight, 4*(line.length+1)+1, lineHeight+1, COLOR.BLACK);
|
||||
drawText(0, 1+i*lineHeight, line);
|
||||
});
|
||||
}
|
||||
|
||||
const draw = () => {
|
||||
clearScreen();
|
||||
|
||||
drawTextAbove();
|
||||
|
||||
fillRect(0, 1+textLinesAbove.length*lineHeight, 4*(2+maxLineLen+1)+1, lineHeight+1, COLOR.BLACK);
|
||||
fillRect((2+index)*4, textLinesAbove.length*lineHeight+1, 4, lineHeight-1, COLOR.RED);
|
||||
drawText(0, 1+textLinesAbove.length*lineHeight, "> "+currentLine);
|
||||
}
|
||||
|
||||
export const repl = {
|
||||
update, draw
|
||||
}
|
56
runcode.ts
Normal file
56
runcode.ts
Normal file
@ -0,0 +1,56 @@
|
||||
// deno-lint-ignore no-explicit-any
|
||||
const G: any = {
|
||||
eval: eval,
|
||||
};
|
||||
// deno-lint-ignore no-explicit-any
|
||||
const builtins: any = {};
|
||||
const context = new Proxy(G, {
|
||||
get: (target, prop) => {
|
||||
if (prop in builtins) {
|
||||
return builtins[prop as keyof typeof builtins];
|
||||
}
|
||||
return target[prop];
|
||||
},
|
||||
set: (target, prop, value) => {
|
||||
target[prop] = value;
|
||||
return true;
|
||||
},
|
||||
has: () => {
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
export const runCode = (code: string) => {
|
||||
try {
|
||||
new Function(code);
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
const fn = new Function("context", `
|
||||
with (context) {
|
||||
${code}
|
||||
}
|
||||
`);
|
||||
return fn(context);
|
||||
}
|
||||
|
||||
export const evalCode = (code: string) => {
|
||||
try {
|
||||
return runCode(`return eval("(${code.replaceAll('"', '\\"')})");`);
|
||||
} catch (err) {
|
||||
if (err.name === "SyntaxError") {
|
||||
return runCode(`return eval("${code.replaceAll('"', '\\"')}");`);
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// deno-lint-ignore no-explicit-any
|
||||
export const addToContext = (name: string, value: any) => {
|
||||
builtins[name] = value;
|
||||
}
|
||||
|
||||
export const getBuiltins = () => {
|
||||
return builtins;
|
||||
}
|
55
sheet.ts
Normal file
55
sheet.ts
Normal file
@ -0,0 +1,55 @@
|
||||
import { getCart } from "./cart.ts";
|
||||
import { LinearGrid } from "./util.ts";
|
||||
// import { runCode, addToContext } from "./runcode.ts";
|
||||
|
||||
// "code" | "spritesheet" | "map" | "sfx" | "patterns" | "fonts"
|
||||
export type Sheet = {
|
||||
sheet_type: "code",
|
||||
value: string,
|
||||
} | {
|
||||
sheet_type: "spritesheet",
|
||||
value: Array<Array<number>>,
|
||||
} | {
|
||||
sheet_type: "map",
|
||||
value: Array<[number, number]>,
|
||||
} | {
|
||||
sheet_type: "none",
|
||||
value: null,
|
||||
}
|
||||
export type SheetType = Sheet["sheet_type"];
|
||||
|
||||
export const getSheet = (n: number) => {
|
||||
return getCart()[n];
|
||||
}
|
||||
|
||||
// deno-lint-ignore no-explicit-any
|
||||
export const setSheet = (n: number, type: SheetType, value: any) => {
|
||||
return getCart()[n] = {sheet_type: type, value};
|
||||
}
|
||||
|
||||
export const getCodeSheet = (sheet: number) => {
|
||||
const {sheet_type, value} = getSheet(sheet);
|
||||
if (sheet_type !== "code") {
|
||||
throw "Trying to use a non-code sheet as code."
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
export const getSpriteSheet = (sheet: number) => {
|
||||
const {sheet_type, value} = getSheet(sheet);
|
||||
if (sheet_type !== "spritesheet") {
|
||||
throw Error("Trying to use a non-sprite sheet as a spritesheet.");
|
||||
}
|
||||
while (value.length < 128) {
|
||||
value.push(Array(64).fill(0));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
export const getMapSheet = (sheet: number) => {
|
||||
const {sheet_type, value} = getSheet(sheet);
|
||||
if (sheet_type !== "map") {
|
||||
throw "Trying to use a non-map sheet as a map."
|
||||
}
|
||||
return LinearGrid(value, 64);
|
||||
}
|
134
spritetab.ts
Normal file
134
spritetab.ts
Normal file
@ -0,0 +1,134 @@
|
||||
import { clearScreen, fillRect } from "./window.ts";
|
||||
import { drawSprite, drawText } from "./builtins.ts";
|
||||
import { COLOR } from "./colors.ts";
|
||||
import { getSpriteSheet, setSheet } from "./sheet.ts";
|
||||
import { mouseClick, mouseHeld, mousePos } from "./mouse.ts";
|
||||
import { drawTransparentRect, inRect, outlineRect, reGrid } from "./util.ts";
|
||||
import { page } from "./viewsheets.ts";
|
||||
import { useSpritesheet } from "./builtins.ts";
|
||||
|
||||
const state = {
|
||||
selectedSprite: 0,
|
||||
selectedColor: 0,
|
||||
get spriteSheetPage() {
|
||||
return Math.floor(this.selectedSprite/64);
|
||||
},
|
||||
set spriteSheetPage(val) {
|
||||
this.selectedSprite = 64*val+this.spriteWithinPage;
|
||||
},
|
||||
get spriteWithinPage() {
|
||||
return this.selectedSprite%64;
|
||||
},
|
||||
set spriteWithinPage(val) {
|
||||
this.selectedSprite = 64*this.spriteSheetPage+val;
|
||||
},
|
||||
get sprites() {
|
||||
return getSpriteSheet(page.activeSheet);
|
||||
},
|
||||
set sprites(val) {
|
||||
setSheet(page.activeSheet, "spritesheet", val);
|
||||
}
|
||||
}
|
||||
|
||||
const paletteX = 88;
|
||||
const paletteY = 16;
|
||||
const swatchW = 8;
|
||||
const swatchH = 8;
|
||||
const paletteW = 4;
|
||||
const paletteH = 6;
|
||||
|
||||
const spriteX = 8;
|
||||
const spriteY = 16;
|
||||
const pixelW = 8;
|
||||
const pixelH = 8;
|
||||
|
||||
const spriteW = 8;
|
||||
const spriteH = 8;
|
||||
|
||||
const sheetX = 0;
|
||||
const sheetY = 88;
|
||||
const sheetW = 16;
|
||||
const sheetH = 4;
|
||||
|
||||
const spriteSheetPageSwapX = 121;
|
||||
const spriteSheetPageSwapY = 80;
|
||||
const spriteSheetPageSwapW = 7;
|
||||
const spriteSheetPageSwapH = 7;
|
||||
|
||||
const update = () => {
|
||||
if (mouseHeld()) {
|
||||
const {x: mouseX, y: mouseY} = mousePos();
|
||||
const inPalette = inRect(mouseX, mouseY, paletteX, paletteY, paletteW*swatchW, paletteH*swatchH);
|
||||
const inSprite = inRect(mouseX, mouseY, spriteX, spriteY, spriteW*pixelW, spriteH*pixelH);
|
||||
const inSheet = inRect(mouseX, mouseY, sheetX, sheetY, sheetW*spriteW, sheetH*spriteH);
|
||||
if (inPalette) {
|
||||
const {x, y} = reGrid(mouseX, mouseY, paletteX, paletteY, swatchW, swatchH);
|
||||
state.selectedColor = paletteW*y+x;
|
||||
}
|
||||
if (inSprite) {
|
||||
const {x, y} = reGrid(mouseX, mouseY, spriteX, spriteY, pixelW, pixelH);
|
||||
const pixelNumber = spriteW*y+x;
|
||||
state.sprites[state.selectedSprite][pixelNumber] = state.selectedColor;
|
||||
}
|
||||
if (inSheet) {
|
||||
const {x, y} = reGrid(mouseX, mouseY, sheetX, sheetY, spriteW, spriteH);
|
||||
state.spriteWithinPage = sheetW*y+x;
|
||||
}
|
||||
} else if (mouseClick()) {
|
||||
const {x: mouseX, y: mouseY} = mousePos();
|
||||
const inSpriteSheetPageSwap = inRect(mouseX, mouseY, spriteSheetPageSwapX, spriteSheetPageSwapY, spriteSheetPageSwapW, spriteSheetPageSwapH);
|
||||
if (inSpriteSheetPageSwap) {
|
||||
state.spriteSheetPage = (1+state.spriteSheetPage)%2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const draw = () => {
|
||||
const {sprites, selectedSprite, selectedColor} = state;
|
||||
clearScreen();
|
||||
useSpritesheet(page.activeSheet);
|
||||
fillRect(0, 8, 128, 112, COLOR.DARKGRAY);
|
||||
|
||||
// Draw the palette
|
||||
fillRect(paletteX-1, paletteY-1, (paletteW*swatchW)+2, (paletteH*swatchH)+2, COLOR.BLACK);
|
||||
Object.keys(COLOR).forEach((name, i) => {
|
||||
const swatchX = paletteX+swatchW*(i%paletteW);
|
||||
const swatchY = paletteY+swatchH*Math.floor(i/paletteW);
|
||||
fillRect(swatchX, swatchY, swatchW, swatchH, COLOR[name as keyof typeof COLOR]);
|
||||
if (name == "TRANSPARENT") {
|
||||
// transparent
|
||||
drawTransparentRect(swatchX, swatchY, swatchW, swatchH);
|
||||
}
|
||||
if (i === selectedColor) {
|
||||
outlineRect(swatchX, swatchY, swatchW, swatchH, name === "WHITE" ? COLOR.BLACK : COLOR.WHITE);
|
||||
}
|
||||
});
|
||||
|
||||
// Draw the current sprite
|
||||
fillRect(spriteX-1, spriteY-1, (spriteW*pixelW)+2, (spriteH*pixelH)+2, COLOR.BLACK);
|
||||
drawTransparentRect(spriteX, spriteY, (spriteW*pixelW), (spriteH*pixelH));
|
||||
sprites[selectedSprite].forEach((pix, i) => {
|
||||
fillRect(spriteX+pixelW*(i%spriteW), spriteY+pixelH*Math.floor(i/spriteW), pixelW, pixelH, pix);
|
||||
});
|
||||
|
||||
// Draw the spritesheet page swap button
|
||||
fillRect(spriteSheetPageSwapX, spriteSheetPageSwapY, spriteSheetPageSwapW, spriteSheetPageSwapH, COLOR.BLUE);
|
||||
drawText(spriteSheetPageSwapX+2, spriteSheetPageSwapY+1, state.spriteSheetPage.toString());
|
||||
|
||||
// Draw the spritesheet
|
||||
fillRect(sheetX, sheetY-1, (sheetW*spriteW), (sheetH*spriteH)+1, COLOR.BLACK);
|
||||
Array(64).fill(0).forEach((_, i) => {
|
||||
const sprI = i+64*state.spriteSheetPage;
|
||||
const sprX = sheetX+spriteW*(i%sheetW);
|
||||
const sprY = sheetY+spriteH*Math.floor(i/sheetW);
|
||||
drawSprite(sprX, sprY, sprI);
|
||||
if (i === state.spriteWithinPage) {
|
||||
outlineRect(sprX, sprY, spriteW, spriteH, COLOR.WHITE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export const spritetab = {
|
||||
update,
|
||||
draw,
|
||||
}
|
98
util.ts
Normal file
98
util.ts
Normal file
@ -0,0 +1,98 @@
|
||||
import { COLOR } from "./colors.ts";
|
||||
import { fillRect, setPixelColor } from "./window.ts";
|
||||
|
||||
export const inRect = (x: number, y: number, rectX: number, rectY: number, rectW: number, rectH: number) => {
|
||||
return (
|
||||
x >= rectX &&
|
||||
x < rectX+rectW &&
|
||||
y >= rectY &&
|
||||
y < rectY+rectH
|
||||
)
|
||||
}
|
||||
|
||||
export function reGridWithGap (x: number, y: number, gridX: number, gridY: number, cellW: number, cellH: number, gapX: number, gapY: number): {x: number, y: number} | null {
|
||||
const gx = Math.floor((x-gridX)/(cellW+gapX));
|
||||
const gy = Math.floor((y-gridY)/(cellH+gapY));
|
||||
if (x >= gridX+(cellW+gapX)*gx+cellW || y >= gridY+(cellH+gapY)*gy+cellH) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
x: Math.floor((x-gridX)/(cellW+gapX)),
|
||||
y: Math.floor((y-gridY)/(cellH+gapY)),
|
||||
}
|
||||
}
|
||||
|
||||
export function reGrid (x: number, y: number, gridX: number, gridY: number, cellW: number, cellH: number): {x: number, y: number} {
|
||||
const gx = Math.floor((x-gridX)/(cellW));
|
||||
const gy = Math.floor((y-gridY)/(cellH));
|
||||
return {
|
||||
x: gx,
|
||||
y: gy,
|
||||
}
|
||||
}
|
||||
|
||||
export const outlineRect = (x: number, y: number, w: number, h: number, color: number) => {
|
||||
fillRect(x, y, w, 1, color);
|
||||
fillRect(x, y, 1, h, color);
|
||||
fillRect(x+w-1, y, 1, h, color);
|
||||
fillRect(x, y+h-1, w, 1, color);
|
||||
}
|
||||
|
||||
export const drawTransparentRect = (x: number, y: number, w: number, h: number) => {
|
||||
Array(w*h).fill(0).map((_z, j) => {
|
||||
const jx = j%w;
|
||||
const jy = Math.floor(j/w);
|
||||
setPixelColor(x+jx, y+jy, (jx+jy)%2 ? COLOR.BLACK : COLOR.DARKGRAY);
|
||||
})
|
||||
}
|
||||
|
||||
export const drawVoidRect = (x: number, y: number, w: number, h: number) => {
|
||||
Array(w*h).fill(0).map((_z, j) => {
|
||||
const jx = j%w;
|
||||
const jy = Math.floor(j/w);
|
||||
setPixelColor(x+jx, y+jy, (jx+jy)%2 ? COLOR.BLACK : COLOR.DARKERBLUE);
|
||||
})
|
||||
}
|
||||
|
||||
export const subgrid = <T>(array: Array<T>, gridW: number, x: number, y: number, w: number, h: number): Array<T|undefined> => {
|
||||
return Array(h).fill(0).flatMap((_, i) => {
|
||||
if (y+i < 0 || y+i > array.length/gridW) {
|
||||
return Array(w).fill(undefined);
|
||||
}
|
||||
const x0 = Math.max(0, x);
|
||||
const x1 = Math.min(x+w, gridW);
|
||||
const start = (y+i)*gridW+x0;
|
||||
const end = (y+i)*gridW+x1;
|
||||
const before = Array(x0 - x).fill(undefined);
|
||||
const after = Array((x+w) - x1).fill(undefined);
|
||||
const middle = array.slice(start, end);
|
||||
return [...before, ...middle, ...after];
|
||||
})
|
||||
}
|
||||
|
||||
export const LinearGrid = <T>(array: Array<T>, gridW: number) => {
|
||||
return {
|
||||
get(x: number, y: number) {
|
||||
return array[this.coordsToIndex(x, y)]
|
||||
},
|
||||
getIndex(i: number) {
|
||||
return array[i];
|
||||
},
|
||||
set(x: number, y: number, value: T) {
|
||||
array[this.coordsToIndex(x, y)] = value;
|
||||
},
|
||||
setIndex(i: number, value: T) {
|
||||
array[i] = value;
|
||||
},
|
||||
values: array,
|
||||
indexToCoords: (i: number) => {
|
||||
return [i%gridW, Math.floor(i/gridW)];
|
||||
},
|
||||
coordsToIndex: (x: number, y: number) => {
|
||||
return y*gridW+x;
|
||||
},
|
||||
// TODO: make alterations to subgrid affect parent grid
|
||||
subgrid: (x: number, y: number, w: number, h: number) => LinearGrid(subgrid(array, gridW, x, y, w, h), w),
|
||||
}
|
||||
}
|
||||
|
63
viewsheets.ts
Normal file
63
viewsheets.ts
Normal file
@ -0,0 +1,63 @@
|
||||
import { clearScreen, fillRect } from "./window.ts";
|
||||
import { drawIcon, drawText } from "./builtins.ts";
|
||||
import { COLOR } from "./colors.ts";
|
||||
import { getSheet } from "./sheet.ts";
|
||||
import { mouseClick, mousePos } from "./mouse.ts";
|
||||
import { getCart } from "./cart.ts";
|
||||
import { font } from "./font.ts";
|
||||
import { codeIcon, spriteIcon, mapIcon } from "./icons.ts";
|
||||
import { reGridWithGap } from "./util.ts";
|
||||
|
||||
const fontHeight = font.height;
|
||||
|
||||
export const page = {activeSheet: 0, tab: "sheet"};
|
||||
|
||||
const gridX = 8;
|
||||
const gridY = 20;
|
||||
const cellW = 22;
|
||||
const cellH = 16;
|
||||
const gapX = 8;
|
||||
const gapY = 8;
|
||||
|
||||
const update = () => {
|
||||
if (mouseClick()) {
|
||||
const {x: mouseX, y: mouseY} = mousePos();
|
||||
const g = reGridWithGap(mouseX, mouseY, gridX, gridY, cellW, cellH, gapX, gapY);
|
||||
if (g) {
|
||||
const {x, y} = g;
|
||||
page.activeSheet = 4*y+x;
|
||||
const sheet = getSheet(page.activeSheet);
|
||||
if (!sheet) {
|
||||
console.log(x, y, g);
|
||||
}
|
||||
page.tab = getSheet(page.activeSheet).sheet_type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const draw = () => {
|
||||
clearScreen();
|
||||
fillRect(0, 8, 128, 112, COLOR.DARKGRAY);
|
||||
|
||||
// Draw the sheet grid
|
||||
getCart().forEach((sheet, i) => {
|
||||
const x = gridX+(cellW+gapX)*(i%4);
|
||||
const y = gridY+(cellH+gapY)*Math.floor(i/4);
|
||||
fillRect(x, y, cellW, cellH, i===page.activeSheet ? COLOR.PURPLE : COLOR.BLACK);
|
||||
drawText(x+(cellW)/2, y+(cellH-fontHeight)/2, i.toString().padStart(2,"0"));
|
||||
const icon = {
|
||||
code: codeIcon,
|
||||
spritesheet: spriteIcon,
|
||||
map: mapIcon,
|
||||
none: null,
|
||||
}[sheet.sheet_type];
|
||||
if (icon) {
|
||||
drawIcon(x+2, y+4, icon, COLOR.WHITE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export const viewsheets = {
|
||||
update,
|
||||
draw,
|
||||
}
|
253
window.ts
Normal file
253
window.ts
Normal file
@ -0,0 +1,253 @@
|
||||
import {
|
||||
createWindow,
|
||||
getProcAddress,
|
||||
gl,
|
||||
} from "./deps.ts";
|
||||
export {mainloop} from "./deps.ts";
|
||||
import { COLOR, palette } from "./colors.ts";
|
||||
|
||||
export const gameWindow = createWindow({
|
||||
title: "Faux",
|
||||
width: 1024,
|
||||
height: 1024,
|
||||
resizable: false,
|
||||
glVersion: [3, 2],
|
||||
gles: true,
|
||||
});
|
||||
|
||||
gl.load(getProcAddress);
|
||||
|
||||
function loadShader(type: number, src: string) {
|
||||
const shader = gl.CreateShader(type);
|
||||
gl.ShaderSource(
|
||||
shader,
|
||||
1,
|
||||
new Uint8Array(
|
||||
new BigUint64Array([
|
||||
BigInt(
|
||||
Deno.UnsafePointer.value(
|
||||
Deno.UnsafePointer.of(new TextEncoder().encode(src)),
|
||||
),
|
||||
),
|
||||
]).buffer,
|
||||
),
|
||||
new Int32Array([src.length]),
|
||||
);
|
||||
gl.CompileShader(shader);
|
||||
const status = new Int32Array(1);
|
||||
gl.GetShaderiv(shader, gl.COMPILE_STATUS, status);
|
||||
if (status[0] === gl.FALSE) {
|
||||
const logLength = new Int32Array(1);
|
||||
gl.GetShaderiv(shader, gl.INFO_LOG_LENGTH, logLength);
|
||||
const log = new Uint8Array(logLength[0]);
|
||||
gl.GetShaderInfoLog(shader, logLength[0], logLength, log);
|
||||
console.log(new TextDecoder().decode(log));
|
||||
gl.DeleteShader(shader);
|
||||
return 0;
|
||||
}
|
||||
return shader;
|
||||
}
|
||||
|
||||
const vShaderSrc = `
|
||||
attribute vec4 vPosition;
|
||||
attribute vec4 vCol;
|
||||
varying vec4 color;
|
||||
void main() {
|
||||
gl_Position = vPosition;
|
||||
color = vCol;
|
||||
}
|
||||
`;
|
||||
|
||||
const fShaderSrc = `
|
||||
precision mediump float;
|
||||
varying vec4 color;
|
||||
void main() {
|
||||
gl_FragColor = color;
|
||||
}
|
||||
`;
|
||||
|
||||
const vShader = loadShader(gl.VERTEX_SHADER, vShaderSrc);
|
||||
const fShader = loadShader(gl.FRAGMENT_SHADER, fShaderSrc);
|
||||
|
||||
const program = gl.CreateProgram();
|
||||
gl.AttachShader(program, vShader);
|
||||
gl.AttachShader(program, fShader);
|
||||
|
||||
gl.BindAttribLocation(program, 0, new TextEncoder().encode("vPosition\0"));
|
||||
gl.BindAttribLocation(program, 1, new TextEncoder().encode("vCol\0"));
|
||||
|
||||
gl.LinkProgram(program);
|
||||
|
||||
const status = new Int32Array(1);
|
||||
gl.GetProgramiv(program, gl.LINK_STATUS, status);
|
||||
if (status[0] === gl.FALSE) {
|
||||
const logLength = new Int32Array(1);
|
||||
gl.GetProgramiv(program, gl.INFO_LOG_LENGTH, logLength);
|
||||
const log = new Uint8Array(logLength[0]);
|
||||
gl.GetProgramInfoLog(program, logLength[0], logLength, log);
|
||||
console.log(new TextDecoder().decode(log));
|
||||
gl.DeleteProgram(program);
|
||||
Deno.exit(1);
|
||||
}
|
||||
|
||||
gl.ClearColor(0.0, 0.0, 0.0, 1.0);
|
||||
|
||||
addEventListener("resize", (event) => {
|
||||
gl.Viewport(0, 0, event.width, event.height);
|
||||
});
|
||||
|
||||
const pixelsPerRow = 128;
|
||||
|
||||
const top = 1;
|
||||
const left = -1;
|
||||
const cell = 2/pixelsPerRow;
|
||||
|
||||
const px = (x: number, y: number) => {
|
||||
// deno-fmt-ignore
|
||||
return [
|
||||
left + x*cell, top - y*cell, 0,
|
||||
left + (x+1)*cell, top - y*cell, 0,
|
||||
left + x*cell, top - (y+1)*cell, 0,
|
||||
left + (x+1)*cell, top - y*cell, 0,
|
||||
left + x*cell, top - (y+1)*cell, 0,
|
||||
left + (x+1)*cell, top - (y+1)*cell, 0,
|
||||
];
|
||||
}
|
||||
|
||||
const paletteX6 = palette.map(rgba => [...rgba, ...rgba, ...rgba, ...rgba, ...rgba, ...rgba]);
|
||||
|
||||
const c = (n: number) => {
|
||||
return paletteX6[n];
|
||||
}
|
||||
|
||||
const allPixelTriangles = new Float32Array(
|
||||
Array(pixelsPerRow*pixelsPerRow).fill(null).flatMap((_, i) => px(i%pixelsPerRow,Math.floor(i/pixelsPerRow)))
|
||||
)
|
||||
|
||||
const allPixelColors = new Float32Array(
|
||||
Array(pixelsPerRow*pixelsPerRow).fill(null).flatMap(() => c(1))
|
||||
)
|
||||
|
||||
export const cameraPos = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
}
|
||||
|
||||
export const setPixelColorRaw = (x: number, y: number, color: number) => {
|
||||
if (x < 0 || y < 0 || x > 127 || y > 127) {
|
||||
return;
|
||||
}
|
||||
if (color !== 0) {
|
||||
const col = c(color);
|
||||
allPixelColors.set(col, 4*6*(128*y+x));
|
||||
}
|
||||
}
|
||||
|
||||
export const setPixelColor = (x: number, y: number, color: number) => {
|
||||
return setPixelColorRaw(Math.floor(x - cameraPos.x), Math.floor(y - cameraPos.y), color);
|
||||
}
|
||||
|
||||
export const setPixelsInRect = (x: number, y: number, w: number, pixels: Array<number>) => {
|
||||
for (let i = 0; i < pixels.length; i++) {
|
||||
setPixelColor(x+i%w, y+Math.floor(i/w), pixels[i]);
|
||||
}
|
||||
}
|
||||
|
||||
export const setPixelsInRectRaw = (x: number, y: number, w: number, pixels: Array<number>) => {
|
||||
for (let i = 0; i < pixels.length; i++) {
|
||||
setPixelColorRaw(x+i%w, y+Math.floor(i/w), pixels[i]);
|
||||
}
|
||||
}
|
||||
|
||||
export const fillRect = (x: number, y: number, w: number, h: number, color: number) => {
|
||||
setPixelsInRect(x, y, w, Array(w*h).fill(color));
|
||||
}
|
||||
|
||||
export const fillCircle = (x: number, y: number, r: number, color: number) => {
|
||||
const left = Math.floor(x-r-1);
|
||||
const top = Math.floor(y-r-1);
|
||||
for (let i = left; i <= Math.ceil(x+r+1); i ++) {
|
||||
for (let j = top; j <= Math.ceil(y+r+1); j ++) {
|
||||
if (Math.sqrt((x-i)**2 + (y-j)**2) <= r+0.5) {
|
||||
setPixelColor(i, j, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const outlineCircle = (x: number, y: number, r: number, color: number) => {
|
||||
const left = Math.floor(x-r-1);
|
||||
const top = Math.floor(y-r-1);
|
||||
const inR = (d: number) => d <= r+0.5 && d > r-0.5;
|
||||
for (let i = left; i <= Math.ceil(x+r+1); i ++) {
|
||||
for (let j = top; j <= Math.ceil(y+r+1); j ++) {
|
||||
const d = Math.sqrt((x-i)**2 + (y-j)**2);
|
||||
if (inR(d)) {
|
||||
const dh = Math.sqrt((x-(i+Math.sign(i-x)))**2 + (y-j)**2);
|
||||
const dv = Math.sqrt((x-i)**2 + (y-(j+Math.sign(j-y)))**2);
|
||||
const h = Math.abs(x-i) > Math.abs(y-j);
|
||||
if (!inR(h ? dh : dv)) {
|
||||
setPixelColor(i, j, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const fillEllipse = (x0: number, y0: number, x1: number, y1: number, color: number) => {
|
||||
const x = 0.5*(x0 + x1);
|
||||
const y = 0.5*(y0 + y1);
|
||||
const rx = Math.abs(x0-x1)/2;
|
||||
const ry = Math.abs(y0-y1)/2;
|
||||
const left = Math.floor(x-rx-1);
|
||||
const top = Math.floor(y-ry-1);
|
||||
for (let i = left; i <= Math.ceil(x+rx+1); i ++) {
|
||||
for (let j = top; j <= Math.ceil(y+ry+1); j ++) {
|
||||
if (Math.sqrt(((x-i)/rx)**2 + ((y-j)/ry)**2) <= 1+(1/(rx+ry))) {
|
||||
setPixelColor(i, j, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const outlineEllipse = (x0: number, y0: number, x1: number, y1: number, color: number) => {
|
||||
const x = 0.5*(x0 + x1);
|
||||
const y = 0.5*(y0 + y1);
|
||||
const rx = Math.abs(x0-x1)/2;
|
||||
const ry = Math.abs(y0-y1)/2;
|
||||
const left = Math.floor(x-rx-1);
|
||||
const top = Math.floor(y-ry-1);
|
||||
const inR = (d: number) => d <= 1+1/(rx+ry);
|
||||
for (let i = left; i <= Math.ceil(x+rx+1); i ++) {
|
||||
for (let j = top; j <= Math.ceil(y+ry+1); j ++) {
|
||||
const d = Math.sqrt(((x-i)/rx)**2 + ((y-j)/ry)**2);
|
||||
if (inR(d)) {
|
||||
const dh = Math.sqrt(((x-(i+Math.sign(i-x)))/rx)**2 + ((y-j)/ry)**2);
|
||||
const dv = Math.sqrt(((x-i)/rx)**2 + ((y-(j+Math.sign(j-y)))/ry)**2);
|
||||
if (!inR(dh) || !inR(dv)) {
|
||||
setPixelColor(i, j, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const fillRectRaw = (x: number, y: number, w: number, h: number, color: number) => {
|
||||
setPixelsInRectRaw(x, y, w, Array(w*h).fill(color));
|
||||
}
|
||||
|
||||
export const clearScreen = (color?: number) => {
|
||||
fillRectRaw(0, 0, 128, 128, color ?? COLOR.BLACK);
|
||||
// allPixelColors.fill(0);
|
||||
}
|
||||
|
||||
export const frame = () => {
|
||||
gl.Clear(gl.COLOR_BUFFER_BIT);
|
||||
gl.UseProgram(program);
|
||||
gl.VertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 0, allPixelTriangles);
|
||||
gl.VertexAttribPointer(1, 4, gl.FLOAT, gl.FALSE, 0, allPixelColors);
|
||||
gl.EnableVertexAttribArray(0);
|
||||
gl.EnableVertexAttribArray(1);
|
||||
gl.DrawArrays(gl.TRIANGLES, 0, 6*pixelsPerRow*pixelsPerRow);
|
||||
gameWindow.swapBuffers();
|
||||
}
|
Reference in New Issue
Block a user