From 691d698ba90c849efc8f3f10498489d8b808e070 Mon Sep 17 00:00:00 2001 From: Pabloader Date: Mon, 26 May 2025 15:47:16 +0000 Subject: [PATCH] createWasmCanvas protocol --- build/html.ts | 39 ++++--- src/common/display/canvas.ts | 44 ++++--- src/games/playground/awoo.cpp | 208 +-------------------------------- src/games/playground/index.tsx | 5 +- 4 files changed, 54 insertions(+), 242 deletions(-) diff --git a/build/html.ts b/build/html.ts index e06727c..5bc4851 100644 --- a/build/html.ts +++ b/build/html.ts @@ -56,24 +56,27 @@ export async function buildHTML(game: string, { production = false, portable = f if (!await pwaIconFile.exists()) { pwaIconFile = Bun.file(path.resolve(import.meta.dir, 'assets', 'pwa_icon.png')); } - const pwaIcon = `data:;base64,${Buffer.from(await pwaIconFile.arrayBuffer()).toString('base64')}`; - const publishURL = process.env.PUBLISH_URL ? `${process.env.PUBLISH_URL}${game}`: '.'; - const manifestJSON = JSON.stringify({ - name: title, - short_name: title, - start_url: publishURL, - id: `/${game}`, - display_override: ["window-controls-overlay"], - display: "fullscreen", - background_color: "#ffffff", - theme_color: "#000000", - icons: [{ - src: pwaIcon, - sizes: '192x192', - type: 'image/png' - }] - }); - const manifest = ``; + let manifest = ''; + if (production) { + const pwaIcon = `data:;base64,${Buffer.from(await pwaIconFile.arrayBuffer()).toString('base64')}`; + const publishURL = process.env.PUBLISH_URL ? `${process.env.PUBLISH_URL}${game}` : '.'; + const manifestJSON = JSON.stringify({ + name: title, + short_name: title, + start_url: publishURL, + id: `/${game}`, + display_override: ["window-controls-overlay"], + display: "fullscreen", + background_color: "#ffffff", + theme_color: "#000000", + icons: [{ + src: pwaIcon, + sizes: '192x192', + type: 'image/png' + }] + }); + manifest = ``; + } let script = await scriptFile.text(); const inits = new Set(); script = script.replace(/var (init_[^ ]+) = __esm\(\(\)/g, (_, $1) => { diff --git a/src/common/display/canvas.ts b/src/common/display/canvas.ts index f4bda24..61197e1 100644 --- a/src/common/display/canvas.ts +++ b/src/common/display/canvas.ts @@ -14,32 +14,46 @@ export function createCanvas(width: number, height: number) { canvas.width = width; canvas.height = height; - canvas.style.height = '100%'; + canvas.style.width = '100dvw'; + canvas.style.height = '100dvh'; + canvas.style.objectFit = 'contain'; canvas.style.imageRendering = 'pixelated'; document.body.style.display = 'flex'; document.body.style.justifyContent = 'center'; + document.body.style.alignItems = 'center'; document.body.append(canvas); return canvas; } -export function createWasmCanvas(dataView: DataView, pointer: number, onFrame?: () => void) { - const imageData = loadImageData(dataView, pointer); - const canvas = createCanvas(imageData.width, imageData.height); - const context = canvas.getContext('bitmaprenderer'); +interface WasmModule { + data: DataView; + init?: (width: number, height: number) => number; + frame?: () => void; +} - if (context) { - const frame = async () => { - onFrame?.(); - const imageBitmap = await createImageBitmap(imageData); - context.transferFromImageBitmap(imageBitmap); - requestAnimationFrame(frame); - }; - frame(); +export function createWasmCanvas(module: WasmModule, width: number, height: number) { + const pointer = module.init?.(width, height); + + if (pointer) { + const imageData = loadImageData(module.data, pointer); + const canvas = createCanvas(imageData.width, imageData.height); + const context = canvas.getContext('2d'); + + if (context) { + const frame = () => { + module.frame?.(); + context.putImageData(imageData, 0, 0); + requestAnimationFrame(frame); + }; + frame(); + } + + return canvas; } - - return canvas; + console.error(`[createWasmCanvas] WASM init's function should return pointer to image data`); + return createCanvas(width, height); } export function getImageData(image: HTMLImageElement): ImageData { diff --git a/src/games/playground/awoo.cpp b/src/games/playground/awoo.cpp index 301b233..a332479 100644 --- a/src/games/playground/awoo.cpp +++ b/src/games/playground/awoo.cpp @@ -1,209 +1,7 @@ -#include -#include #include -static image_data_t image; +EXPORT(main) void init() { + uint32_t result = 42; -// D E F I N E S /////////////////////////////////////////////////////////// - -#define NUM_ASTEROIDS 10 -#define ERASE 0 -#define DRAW 1 - -// T Y P E D E F S /////////////////////////////////////////////////////////// - -// the structure for a vertex - -typedef struct vertex_typ { - float x, y; // a single point in the 2-D plane. -} vertex, *vertex_ptr; - -// the structure for an object - -typedef struct object_typ { - int num_vertices; // number of vertices in this object - uint32_t color; // color of object - float xo, yo; // position of object - float x_velocity; // x velocity of object - float y_velocity; // y velocity of object - float scale; // scale factor - float angle; // rotation rate - vertex vertices[16]; // 16 vertices -} object, *object_ptr; - -object asteroids[NUM_ASTEROIDS]; - -void Scale_Object(object_ptr object, float scale) { - int index; - - // for all vertices scale the x and y component - - for (index = 0; index < object->num_vertices; index++) { - object->vertices[index].x *= scale; - object->vertices[index].y *= scale; - } // end for index - -} // end Scale_Object - -////////////////////////////////////////////////////////////////////////////// - -void Rotate_Object(object_ptr object, float angle) { - int index; - float x_new, y_new, cs, sn; - - // pre-compute sin and cos - cs = cos(angle); - sn = sin(angle); - - // for each vertex rotate it by angle - for (index = 0; index < object->num_vertices; index++) { - // rotate the vertex - x_new = object->vertices[index].x * cs - object->vertices[index].y * sn; - y_new = object->vertices[index].y * cs + object->vertices[index].x * sn; - - // store the rotated vertex back into structure - object->vertices[index].x = x_new; - object->vertices[index].y = y_new; - - } // end for index - -} // end Rotate_Object - -////////////////////////////////////////////////////////////////////////////// - -void Create_Field(void) { - - int index; - - for (index = 0; index < NUM_ASTEROIDS; index++) { - - // fill in the fields - - asteroids[index].num_vertices = 6; - asteroids[index].color = 0xFF000000 | (rand()); - asteroids[index].xo = 21 + rand() % (image.width - 42); - asteroids[index].yo = 21 + rand() % (image.height - 42); - - asteroids[index].x_velocity = -3 + rand() % 6; - asteroids[index].y_velocity = -3 + rand() % 6; - asteroids[index].scale = (float)(rand() % 30) / 10; - asteroids[index].angle = (float)(-5 + (float)(rand() % 10)) / 100; - - asteroids[index].vertices[0].x = 4.0; - asteroids[index].vertices[0].y = 3.5; - asteroids[index].vertices[1].x = 8.5; - asteroids[index].vertices[1].y = -3.0; - asteroids[index].vertices[2].x = 6; - asteroids[index].vertices[2].y = -5; - asteroids[index].vertices[3].x = 2; - asteroids[index].vertices[3].y = -3; - asteroids[index].vertices[4].x = -4; - asteroids[index].vertices[4].y = -6; - asteroids[index].vertices[5].x = -3.5; - asteroids[index].vertices[5].y = 5.5; - - // now scale the asteroid to proper size - - Scale_Object((object_ptr)&asteroids[index], asteroids[index].scale); - - } // end for index - -} // end Create_Field - -////////////////////////////////////////////////////////////////////////////// - -void Draw_Asteroids(int erase) { - image_color_t color = {0xFF000000}; - - for (int index = 0; index < NUM_ASTEROIDS; index++) { - - // draw the asteroid - - if (erase == DRAW) { - color.color = asteroids[index].color; - } - - // get position of object - float xo = asteroids[index].xo; - float yo = asteroids[index].yo; - - // moveto first vertex - - for (int startVertex = 0; startVertex < asteroids[index].num_vertices; startVertex++) { - int endVertex = (startVertex + 1) % asteroids[index].num_vertices; - int x1 = (int)(xo + asteroids[index].vertices[startVertex].x); - int y1 = (int)(yo + asteroids[index].vertices[startVertex].y); - int x2 = (int)(xo + asteroids[index].vertices[endVertex].x); - int y2 = (int)(yo + asteroids[index].vertices[endVertex].y); - image_draw_line(image, x1, y1, x2, y2, color); - - } // end for vertex - - } // end for index - -} // end Draw_Asteroids - -////////////////////////////////////////////////////////////////////////////// - -void Translate_Asteroids() { - - int index; - - for (index = 0; index < NUM_ASTEROIDS; index++) { - // translate current asteroid - - asteroids[index].xo += asteroids[index].x_velocity; - asteroids[index].yo += asteroids[index].y_velocity; - // collision detection i.e. bounds check - - if (asteroids[index].xo > image.width - 20 || asteroids[index].xo < 20) { - asteroids[index].x_velocity = -asteroids[index].x_velocity; - asteroids[index].xo += asteroids[index].x_velocity; - } - - if (asteroids[index].yo > image.height - 20 || asteroids[index].yo < 20) { - asteroids[index].y_velocity = -asteroids[index].y_velocity; - asteroids[index].yo += asteroids[index].y_velocity; - } - - } // end for index - -} // end Translate_Asteroids - -////////////////////////////////////////////////////////////////////////////// - -void Rotate_Asteroids(void) { - - int index; - - for (index = 0; index < NUM_ASTEROIDS; index++) { - // rotate current asteroid - Rotate_Object((object_ptr)&asteroids[index], asteroids[index].angle); - - } // end for index - -} // end Rotate_Asteroids - -EXPORT(cpptest) image_data_t* cpptest(uint16_t w, uint16_t h) { - image = image_create(w, h); - - image_fill_rect(image, 0, 0, w, h, {0xFF000000}); - - Create_Field(); - - return ℑ -} - -EXPORT(step) void step() { - Draw_Asteroids(ERASE); - - // transform field - - Rotate_Asteroids(); - - Translate_Asteroids(); - - // draw field - - Draw_Asteroids(DRAW); + printf("%d\n", result); } \ No newline at end of file diff --git a/src/games/playground/index.tsx b/src/games/playground/index.tsx index 46f5084..4267bd1 100644 --- a/src/games/playground/index.tsx +++ b/src/games/playground/index.tsx @@ -1,8 +1,5 @@ -import { createWasmCanvas } from "@common/display/canvas"; import awoo from "./awoo.cpp"; export default function main() { - const data = awoo.cpptest(window.innerWidth >> 2, window.innerHeight >> 2); - const canvas = createWasmCanvas(awoo.data, data, awoo.step); - console.log(awoo, canvas.width, canvas.height); + console.log(awoo, awoo.main()); } \ No newline at end of file