Mirai's Miscellaneous Misadventures

M40 / engines / wasm.c

1// copyright 2023 zamfofex
2// license: AGPLv3 or later
3
4#include <stdlib.h>
5
6#include <mimimi/assets.h>
7#include <mimimi/engines.h>
8#include <mimimi/behaviors.h>
9#include <mimimi/geometry.h>
10#include <mimimi/chapters.h>
11#include <mimimi/malloc.h>
12#include <mimimi/coroutine-providers.h>
13
14// textures
15
16static void *mimimi_wasm_texture(void *data, struct mimimi_image *image)
17{
18	(void) data;
19	return image;
20}
21
22static void mimimi_wasm_invalidate(void *data, void *texture)
23{
24	(void) data;
25	(void) texture;
26}
27
28static void mimimi_wasm_stamp(void *data, int x1, int y1, void *texture)
29{
30	static unsigned char rch[] = {0x11, 0x44, 0x77, 0x99, 0xCC, 0xFF};
31	static unsigned char gch[] = {0x11, 0x33, 0x55, 0x77, 0x99, 0xBB, 0xDD, 0xFF};
32	static unsigned char bch[] = {0x22, 0x55, 0x88, 0xBB, 0xEE};
33	
34	struct mimimi_image *image = texture;
35	
36	unsigned char (*buffer)[4] = data;
37	
38	int x0 = 0;
39	int y0 = 0;
40	
41	if (x1 < 0) x0 = -x1;
42	if (y1 < 0) y0 = -y1;
43	
44	int width = image->width;
45	int height = image->height;
46	
47	if (width + x1 > 512) width = 512 - x1;
48	if (height + y1 > 256) height = 256 - y1;
49	
50	for (int y = y0 ; y < height ; y++)
51	for (int x = x0 ; x < width ; x++)
52	{
53		unsigned char color = image->colors[x + y * image->width];
54		if (color == 0) continue;
55		
56		int x2 = x + x1;
57		int y2 = y + y1;
58		
59		int offset = x2 + y2 * 512;
60		
61		if (color < 0x10)
62		{
63			unsigned char ch = color * 0x11;
64			buffer[offset][0] = ch;
65			buffer[offset][1] = ch;
66			buffer[offset][2] = ch;
67			buffer[offset][3] = 0xFF;
68		}
69		else
70		{
71			color -= 0x10;
72			unsigned char r, g, b;
73			r = rch[(color / 40) % 6];
74			g = gch[(color / 5) % 8];
75			b = bch[(color / 1) % 5];
76			
77			buffer[offset][0] = r;
78			buffer[offset][1] = g;
79			buffer[offset][2] = b;
80			buffer[offset][3] = 0xFF;
81		}
82	}
83}
84
85// coroutines
86
87struct mimimi_wasm_asyncify_buffer
88{
89	void *begin;
90	void *end;
91};
92
93struct mimimi_wasm_coroutine_data
94{
95	unsigned int state;
96	struct mimimi_wasm_asyncify_buffer buffer;
97	void (*start)(struct mimimi_behavior *behavior, void *data);
98	void (*finish)(void *data);
99	void *data;
100	struct mimimi_behavior *behavior;
101	struct mimimi_behavior *coroutine;
102};
103
104void mimimi_wasm_yield(void *data);
105
106void mimimi_wasm_continue(void *data);
107
108void mimimi_wasm_start_coroutine(void *data)
109{
110	struct mimimi_wasm_coroutine_data *coroutine_data = data;
111	(*coroutine_data->start)(coroutine_data->behavior, coroutine_data->data);
112}
113
114void mimimi_wasm_finish_coroutine(void *data)
115{
116	struct mimimi_wasm_coroutine_data *coroutine_data = data;
117	
118	coroutine_data->state = 2;
119	
120	(*coroutine_data->finish)(coroutine_data->data);
121	free(coroutine_data->buffer.begin);
122	free(coroutine_data->behavior);
123}
124
125static void mimimi_wasm_finish_coroutine2(void *data)
126{
127	struct mimimi_wasm_coroutine_data *coroutine_data = data;
128	
129	if (coroutine_data->state != 2) mimimi_wasm_finish_coroutine(coroutine_data);
130	
131	free(coroutine_data->coroutine);
132	free(coroutine_data);
133}
134
135static struct mimimi_behavior *mimimi_wasm_create_coroutine(void (*start)(struct mimimi_behavior *behavior, void *data), void (*finish)(void *data), void *data, void *self)
136{
137	(void) self;
138	
139	unsigned char *begin = mimimi_allocate(mimimi_malloc, 8192);
140	
141	struct mimimi_wasm_coroutine_data *coroutine_data = mimimi_allocate(mimimi_malloc, sizeof *coroutine_data);
142	coroutine_data->start = start;
143	coroutine_data->finish = finish;
144	coroutine_data->data = data;
145	coroutine_data->buffer.begin = begin;
146	coroutine_data->buffer.end = begin + 8192;
147	coroutine_data->state = 0;
148	
149	struct mimimi_behavior *behavior = mimimi_allocate(mimimi_malloc, sizeof *behavior);
150	behavior->behave = &mimimi_wasm_yield;
151	behavior->finish = &mimimi_wasm_finish_coroutine;
152	behavior->data = coroutine_data;
153	coroutine_data->behavior = behavior;
154	
155	struct mimimi_behavior *coroutine = mimimi_allocate(mimimi_malloc, sizeof *coroutine);
156	coroutine->behave = &mimimi_wasm_continue;
157	coroutine->finish = &mimimi_wasm_finish_coroutine2;
158	coroutine->data = coroutine_data;
159	coroutine_data->coroutine = coroutine;
160	
161	return coroutine;
162}
163
164static struct mimimi_coroutine_provider mimimi_wasm_coroutines = {&mimimi_wasm_create_coroutine, 0};
165
166// engine
167
168static struct mimimi_chapter *mimimi_wasm_chapter;
169static unsigned char (*mimimi_wasm_buffer)[4];
170
171void *mimimi_wasm_behave(unsigned char left, unsigned char right)
172{
173	mimimi_wasm_chapter->left = left;
174	mimimi_wasm_chapter->right = right;
175	struct mimimi_behavior *behavior = mimimi_wasm_chapter->behavior;
176	(*behavior->behave)(behavior->data);
177	return mimimi_wasm_buffer;
178}
179
180void mimimi_wasm(struct mimimi_chapter *(*start)(struct mimimi_engine *engine))
181{
182	static struct mimimi_size size = {512, 256};
183	mimimi_wasm_buffer = mimimi_allocate(mimimi_malloc, size.width * size.height * 4);
184	
185	static struct mimimi_engine engine;
186	engine.data = mimimi_wasm_buffer;
187	engine.texture = &mimimi_wasm_texture;
188	engine.invalidate = &mimimi_wasm_invalidate;
189	engine.stamp = &mimimi_wasm_stamp;
190	engine.size = &size;
191	engine.allocator = mimimi_malloc;
192	engine.coroutines = &mimimi_wasm_coroutines;
193	mimimi_wasm_chapter = (*start)(&engine);
194}