createWasmCanvas protocol
This commit is contained in:
parent
f2fa4d7918
commit
691d698ba9
|
|
@ -56,8 +56,10 @@ export async function buildHTML(game: string, { production = false, portable = f
|
||||||
if (!await pwaIconFile.exists()) {
|
if (!await pwaIconFile.exists()) {
|
||||||
pwaIconFile = Bun.file(path.resolve(import.meta.dir, 'assets', 'pwa_icon.png'));
|
pwaIconFile = Bun.file(path.resolve(import.meta.dir, 'assets', 'pwa_icon.png'));
|
||||||
}
|
}
|
||||||
|
let manifest = '';
|
||||||
|
if (production) {
|
||||||
const pwaIcon = `data:;base64,${Buffer.from(await pwaIconFile.arrayBuffer()).toString('base64')}`;
|
const pwaIcon = `data:;base64,${Buffer.from(await pwaIconFile.arrayBuffer()).toString('base64')}`;
|
||||||
const publishURL = process.env.PUBLISH_URL ? `${process.env.PUBLISH_URL}${game}`: '.';
|
const publishURL = process.env.PUBLISH_URL ? `${process.env.PUBLISH_URL}${game}` : '.';
|
||||||
const manifestJSON = JSON.stringify({
|
const manifestJSON = JSON.stringify({
|
||||||
name: title,
|
name: title,
|
||||||
short_name: title,
|
short_name: title,
|
||||||
|
|
@ -73,7 +75,8 @@ export async function buildHTML(game: string, { production = false, portable = f
|
||||||
type: 'image/png'
|
type: 'image/png'
|
||||||
}]
|
}]
|
||||||
});
|
});
|
||||||
const manifest = `<link rel="manifest" href="data:;base64,${Buffer.from(manifestJSON).toString('base64')}" />`;
|
manifest = `<link rel="manifest" href="data:;base64,${Buffer.from(manifestJSON).toString('base64')}" />`;
|
||||||
|
}
|
||||||
let script = await scriptFile.text();
|
let script = await scriptFile.text();
|
||||||
const inits = new Set<string>();
|
const inits = new Set<string>();
|
||||||
script = script.replace(/var (init_[^ ]+) = __esm\(\(\)/g, (_, $1) => {
|
script = script.replace(/var (init_[^ ]+) = __esm\(\(\)/g, (_, $1) => {
|
||||||
|
|
|
||||||
|
|
@ -14,32 +14,46 @@ export function createCanvas(width: number, height: number) {
|
||||||
|
|
||||||
canvas.width = width;
|
canvas.width = width;
|
||||||
canvas.height = height;
|
canvas.height = height;
|
||||||
canvas.style.height = '100%';
|
canvas.style.width = '100dvw';
|
||||||
|
canvas.style.height = '100dvh';
|
||||||
|
canvas.style.objectFit = 'contain';
|
||||||
canvas.style.imageRendering = 'pixelated';
|
canvas.style.imageRendering = 'pixelated';
|
||||||
|
|
||||||
document.body.style.display = 'flex';
|
document.body.style.display = 'flex';
|
||||||
document.body.style.justifyContent = 'center';
|
document.body.style.justifyContent = 'center';
|
||||||
|
document.body.style.alignItems = 'center';
|
||||||
document.body.append(canvas);
|
document.body.append(canvas);
|
||||||
|
|
||||||
return canvas;
|
return canvas;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createWasmCanvas(dataView: DataView, pointer: number, onFrame?: () => void) {
|
interface WasmModule {
|
||||||
const imageData = loadImageData(dataView, pointer);
|
data: DataView;
|
||||||
|
init?: (width: number, height: number) => number;
|
||||||
|
frame?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 canvas = createCanvas(imageData.width, imageData.height);
|
||||||
const context = canvas.getContext('bitmaprenderer');
|
const context = canvas.getContext('2d');
|
||||||
|
|
||||||
if (context) {
|
if (context) {
|
||||||
const frame = async () => {
|
const frame = () => {
|
||||||
onFrame?.();
|
module.frame?.();
|
||||||
const imageBitmap = await createImageBitmap(imageData);
|
context.putImageData(imageData, 0, 0);
|
||||||
context.transferFromImageBitmap(imageBitmap);
|
|
||||||
requestAnimationFrame(frame);
|
requestAnimationFrame(frame);
|
||||||
};
|
};
|
||||||
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 {
|
export function getImageData(image: HTMLImageElement): ImageData {
|
||||||
|
|
|
||||||
|
|
@ -1,209 +1,7 @@
|
||||||
#include <graphics.h>
|
|
||||||
#include <math.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
static image_data_t image;
|
EXPORT(main) void init() {
|
||||||
|
uint32_t result = 42;
|
||||||
|
|
||||||
// D E F I N E S ///////////////////////////////////////////////////////////
|
printf("%d\n", result);
|
||||||
|
|
||||||
#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);
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,8 +1,5 @@
|
||||||
import { createWasmCanvas } from "@common/display/canvas";
|
|
||||||
import awoo from "./awoo.cpp";
|
import awoo from "./awoo.cpp";
|
||||||
|
|
||||||
export default function main() {
|
export default function main() {
|
||||||
const data = awoo.cpptest(window.innerWidth >> 2, window.innerHeight >> 2);
|
console.log(awoo, awoo.main());
|
||||||
const canvas = createWasmCanvas(awoo.data, data, awoo.step);
|
|
||||||
console.log(awoo, canvas.width, canvas.height);
|
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue