diff --git a/builtins.ts b/builtins.ts index c9e709c..1259105 100644 --- a/builtins.ts +++ b/builtins.ts @@ -8,42 +8,13 @@ import { font } from "./font.ts"; import { addToContext } from "./runcode.ts"; import { resetRepl } from "./repl.ts"; import { COLOR } from "./colors.ts"; - -// deno-fmt-ignore -const sprites = [ - [ - 2, 2, 2, 2, 2, 2, 2, 2, - 2, 1, 1, 1, 1, 1, 1, 2, - 2, 1, 1, 1, 1, 1, 1, 2, - 2, 1, 1, 1, 1, 1, 1, 2, - 2, 1, 1, 1, 1, 1, 1, 2, - 2, 1, 1, 1, 1, 1, 1, 2, - 2, 1, 1, 1, 1, 1, 1, 2, - 2, 2, 2, 2, 2, 2, 2, 2, - ], - [ - 2, 2, 2, 2, 2, 2, 2, 2, - 2, 3, 3, 1, 1, 3, 3, 2, - 2, 3, 3, 1, 1, 3, 3, 2, - 2, 1, 1, 1, 1, 1, 1, 2, - 2, 1, 1, 1, 1, 1, 1, 2, - 2, 3, 3, 1, 1, 3, 3, 2, - 2, 3, 3, 1, 1, 3, 3, 2, - 2, 2, 2, 2, 2, 2, 2, 2, - ], - [ - 2, 2, 2, 2, 2, 2, 2, 2, - 2, 4, 4, 4, 4, 5, 5, 2, - 2, 4, 4, 4, 5, 5, 5, 2, - 2, 4, 4, 5, 5, 5, 6, 2, - 2, 4, 5, 5, 5, 6, 6, 2, - 2, 5, 5, 5, 6, 6, 6, 2, - 2, 5, 5, 6, 6, 6, 6, 2, - 2, 2, 2, 2, 2, 2, 2, 2, - ], -] +import { getSheet } from "./sheet.ts"; export const drawSprite = (x: number, y: number, spr: number) => { + const {sheet_type, value: sprites} = getSheet(2); + if (sheet_type !== "spritesheet") { + throw "Trying to run a non-code sheet as code." + } setPixelsInRect(x, y, 8, sprites[spr]); } diff --git a/index.ts b/index.ts index 071267c..eb8084a 100644 --- a/index.ts +++ b/index.ts @@ -8,6 +8,7 @@ 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"; // deno-lint-ignore no-explicit-any let game: any = null; @@ -56,4 +57,5 @@ await mainloop((_t) => { } } refreshKeyboard(); + refreshMouse(); }); diff --git a/mouse.ts b/mouse.ts new file mode 100644 index 0000000..77a368d --- /dev/null +++ b/mouse.ts @@ -0,0 +1,88 @@ +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", + 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) => { +// console.log("dblclick", evt.button, evt.clientX, evt.clientY); +// }); + +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 mouseClick = (button: number = M.LEFT) => { + return mouseEvents.some(ev => ev.button === button && ev.type === "click"); +} + +export const mouseHeld = (button: number = M.LEFT) => { + return mouseButtonsDown[button]; +} \ No newline at end of file diff --git a/spritetab.ts b/spritetab.ts index 77365e5..27f7cd2 100644 --- a/spritetab.ts +++ b/spritetab.ts @@ -3,9 +3,11 @@ import { fontWidth, fontHeight } from "./font.ts"; import { drawText, drawSprite } from "./builtins.ts"; import { COLOR } from "./colors.ts"; import {getSheet, setSheet} from "./sheet.ts"; +import { mouseClick, mouseHeld, mousePos } from "./mouse.ts"; const state = { - selectedIndex: 0, + selectedSprite: 0, + selectedColor: 0, get sprites() { const {sheet_type, value} = getSheet(2); if (sheet_type !== "spritesheet") { @@ -18,43 +20,101 @@ const state = { } } +const paletteX = 88; +const paletteY = 12; +const swatchW = 8; +const swatchH = 8; +const paletteW = 4; +const paletteH = 4; + +const spriteX = 8; +const spriteY = 12; +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 inRect = (x: number, y: number, rectX: number, rectY: number, rectW: number, rectH: number) => { + return ( + x >= rectX && + x < rectX+rectW && + y >= rectY && + y < rectY+rectH + ) +} + +const reGrid = (x: number, y: number, gridX: number, gridY: number, cellW: number, cellH: number) => { + return { + x: Math.floor((x-gridX)/cellW), + y: Math.floor((y-gridY)/cellH), + } +} + 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.selectedSprite = sheetW*y+x; + } + } } const draw = () => { - const {sprites, selectedIndex} = state; + const {sprites, selectedSprite, selectedColor} = state; clearScreen(); fillRect(0, 8, 128, 112, COLOR.BROWN); + // Draw the palette - const paletteX = 88; - const paletteY = 12; - fillRect(paletteX-1, paletteY-1, 32+2, 32+2, COLOR.BLACK); + fillRect(paletteX-1, paletteY-1, (paletteW*swatchW)+2, (paletteH*swatchH)+2, COLOR.BLACK); Object.keys(COLOR).forEach((name, i) => { - const swatchX = paletteX+8*(i%4); - const swatchY = paletteY+8*Math.floor(i/4); - fillRect(swatchX, swatchY, 8, 8, COLOR[name as keyof typeof COLOR]); + 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 (i === 0) { // transparent - Array(64).fill(0).map((_z, j) => { - const jx = j%8; - const jy = Math.floor(j/8); + Array(swatchW*swatchH).fill(0).map((_z, j) => { + const jx = j%swatchW; + const jy = Math.floor(j/swatchW); setPixelColor(swatchX+jx, swatchY+jy, (jx+jy)%2 ? COLOR.BLACK : COLOR.WHITE); }) } + if (i === selectedColor) { + fillRect(swatchX, swatchY, swatchW, 1, COLOR.WHITE); + fillRect(swatchX, swatchY, 1, swatchH, COLOR.WHITE); + fillRect(swatchX+swatchW-1, swatchY, 1, swatchH, COLOR.WHITE); + fillRect(swatchX, swatchY+swatchH-1, swatchW, 1, COLOR.WHITE); + } }); + // Draw the current sprite - const spriteX = 8; - const spriteY = 12; - fillRect(spriteX-1, spriteY-1, 64+2, 64+2, COLOR.BLACK); - sprites[selectedIndex].forEach((pix, i) => { - fillRect(spriteX+8*(i%8), spriteY+8*Math.floor(i/8), 8, 8, pix); + fillRect(spriteX-1, spriteY-1, (spriteW*pixelW)+2, (spriteH*pixelH)+2, COLOR.BLACK); + sprites[selectedSprite].forEach((pix, i) => { + fillRect(spriteX+pixelW*(i%spriteW), spriteY+pixelH*Math.floor(i/spriteW), pixelW, pixelH, pix); }); + // Draw the spritesheet - const sheetX = 0; - const sheetY = 88; - fillRect(sheetX, sheetY-1, 128, 64+1, COLOR.BLACK); + fillRect(sheetX, sheetY-1, (sheetW*spriteW), (sheetH*spriteH)+1, COLOR.BLACK); sprites.forEach((_sprite, i) => { - drawSprite(sheetX+8*(i%16), sheetY+8*Math.floor(i/16), i); + drawSprite(sheetX+spriteW*(i%sheetW), sheetY+spriteH*Math.floor(i/sheetW), i); }); } diff --git a/window.ts b/window.ts index 28da5d8..7a13b55 100644 --- a/window.ts +++ b/window.ts @@ -6,7 +6,7 @@ import { export {mainloop} from "./deps.ts"; import { palette } from "./colors.ts"; -const window = createWindow({ +export const gameWindow = createWindow({ title: "Faux", width: 1024, height: 1024, @@ -160,5 +160,5 @@ export const frame = () => { gl.EnableVertexAttribArray(0); gl.EnableVertexAttribArray(1); gl.DrawArrays(gl.TRIANGLES, 0, 6*pixelsPerRow*pixelsPerRow); - window.swapBuffers(); + gameWindow.swapBuffers(); }