Mirai's Miscellaneous Misadventures
M39 / engines / wasm.c
#include <stdlib.h>
#include <mimimi/assets.h>
#include <mimimi/engines.h>
#include <mimimi/behaviors.h>
#include <mimimi/geometry.h>
#include <mimimi/chapters.h>
#include <mimimi/malloc.h>
#include <mimimi/coroutine-providers.h>
static void *mimimi_wasm_texture(void *data, struct mimimi_image *image)
{
(void) data;
return image;
}
static void mimimi_wasm_invalidate(void *data, void *texture)
{
(void) data;
(void) texture;
}
static void mimimi_wasm_stamp(void *data, int x1, int y1, void *texture)
{
static unsigned char rch[] = {0x11, 0x44, 0x77, 0x99, 0xCC, 0xFF};
static unsigned char gch[] = {0x11, 0x33, 0x55, 0x77, 0x99, 0xBB, 0xDD, 0xFF};
static unsigned char bch[] = {0x22, 0x55, 0x88, 0xBB, 0xEE};
struct mimimi_image *image = texture;
unsigned char (*buffer)[4] = data;
int x0 = 0;
int y0 = 0;
if (x1 < 0) x0 = -x1;
if (y1 < 0) y0 = -y1;
int width = image->width;
int height = image->height;
if (width + x1 > 512) width = 512 - x1;
if (height + y1 > 256) height = 256 - y1;
for (int y = y0 ; y < height ; y++)
for (int x = x0 ; x < width ; x++)
{
unsigned char color = image->colors[x + y * image->width];
if (color == 0) continue;
int x2 = x + x1;
int y2 = y + y1;
int offset = x2 + y2 * 512;
if (color < 0x10)
{
unsigned char ch = color * 0x11;
buffer[offset][0] = ch;
buffer[offset][1] = ch;
buffer[offset][2] = ch;
buffer[offset][3] = 0xFF;
}
else
{
color -= 0x10;
unsigned char r, g, b;
r = rch[(color / 40) % 6];
g = gch[(color / 5) % 8];
b = bch[(color / 1) % 5];
buffer[offset][0] = r;
buffer[offset][1] = g;
buffer[offset][2] = b;
buffer[offset][3] = 0xFF;
}
}
}
struct mimimi_wasm_asyncify_buffer
{
void *begin;
void *end;
};
struct mimimi_wasm_coroutine_data
{
unsigned int state;
struct mimimi_wasm_asyncify_buffer buffer;
void (*start)(struct mimimi_behavior *behavior, void *data);
void (*finish)(void *data);
void *data;
struct mimimi_behavior *behavior;
struct mimimi_behavior *coroutine;
};
void mimimi_wasm_yield(void *data);
void mimimi_wasm_continue(void *data);
void mimimi_wasm_start_coroutine(void *data)
{
struct mimimi_wasm_coroutine_data *coroutine_data = data;
(*coroutine_data->start)(coroutine_data->behavior, coroutine_data->data);
}
void mimimi_wasm_finish_coroutine(void *data)
{
struct mimimi_wasm_coroutine_data *coroutine_data = data;
coroutine_data->state = 2;
(*coroutine_data->finish)(coroutine_data->data);
free(coroutine_data->buffer.begin);
free(coroutine_data->behavior);
}
static void mimimi_wasm_finish_coroutine2(void *data)
{
struct mimimi_wasm_coroutine_data *coroutine_data = data;
if (coroutine_data->state != 2) mimimi_wasm_finish_coroutine(coroutine_data);
free(coroutine_data->coroutine);
free(coroutine_data);
}
static struct mimimi_behavior *mimimi_wasm_create_coroutine(void (*start)(struct mimimi_behavior *behavior, void *data), void (*finish)(void *data), void *data, void *self)
{
(void) self;
unsigned char *begin = mimimi_allocate(mimimi_malloc, 8192);
struct mimimi_wasm_coroutine_data *coroutine_data = mimimi_allocate(mimimi_malloc, sizeof *coroutine_data);
coroutine_data->start = start;
coroutine_data->finish = finish;
coroutine_data->data = data;
coroutine_data->buffer.begin = begin;
coroutine_data->buffer.end = begin + 8192;
coroutine_data->state = 0;
struct mimimi_behavior *behavior = mimimi_allocate(mimimi_malloc, sizeof *behavior);
behavior->behave = &mimimi_wasm_yield;
behavior->finish = &mimimi_wasm_finish_coroutine;
behavior->data = coroutine_data;
coroutine_data->behavior = behavior;
struct mimimi_behavior *coroutine = mimimi_allocate(mimimi_malloc, sizeof *coroutine);
coroutine->behave = &mimimi_wasm_continue;
coroutine->finish = &mimimi_wasm_finish_coroutine2;
coroutine->data = coroutine_data;
coroutine_data->coroutine = coroutine;
return coroutine;
}
static struct mimimi_coroutine_provider mimimi_wasm_coroutines = {&mimimi_wasm_create_coroutine, 0};
static struct mimimi_chapter *mimimi_wasm_chapter;
static unsigned char (*mimimi_wasm_buffer)[4];
void *mimimi_wasm_behave(unsigned char left, unsigned char right)
{
mimimi_wasm_chapter->left = left;
mimimi_wasm_chapter->right = right;
struct mimimi_behavior *behavior = mimimi_wasm_chapter->behavior;
(*behavior->behave)(behavior->data);
return mimimi_wasm_buffer;
}
void mimimi_wasm(struct mimimi_chapter *(*start)(struct mimimi_engine *engine))
{
static struct mimimi_size size = {512, 256};
mimimi_wasm_buffer = mimimi_allocate(mimimi_malloc, size.width * size.height * 4);
static struct mimimi_engine engine;
engine.data = mimimi_wasm_buffer;
engine.texture = &mimimi_wasm_texture;
engine.invalidate = &mimimi_wasm_invalidate;
engine.stamp = &mimimi_wasm_stamp;
engine.size = &size;
engine.allocator = mimimi_malloc;
engine.coroutines = &mimimi_wasm_coroutines;
mimimi_wasm_chapter = (*start)(&engine);
}