Mirai's Miscellaneous Misadventures

M23 / engines / x86.c

1// copyright 2022 zamfofex
2// license: AGPLv3 or later
3
4#include <mimimi/allocators.h>
5#include <mimimi/test.h>
6#include <mimimi/engines.h>
7#include <mimimi/geometry.h>
8#include <mimimi/assets.h>
9#include <mimimi/chapters.h>
10#include <mimimi/behaviors.h>
11
12struct mimimi_vbe_screen
13{
14	unsigned int *buffer;
15	unsigned short int width;
16	unsigned short int height;
17	unsigned short int bytes_per_line;
18	unsigned short int bytes_per_pixel;
19};
20
21extern struct mimimi_vbe_screen mimimi_vbe_screen;
22
23void mimimi_x86_exit(void);
24
25extern unsigned char mimimi_x86_heap_start;
26static unsigned char *mimimi_x86_heap = &mimimi_x86_heap_start;
27
28static unsigned char mimimi_x86_blocks[8192] = {};
29
30static void *mimimi_x86_allocate(unsigned int size)
31{
32	int blocks = (size - 1) / 1024 + 1;
33	
34	for (int i = 0 ; i < 8192 ; i++)
35	{
36		for (int j = 0 ; j < blocks ; j++)
37		{
38			if (mimimi_x86_blocks[i + j] != 0)
39				goto next;
40		}
41		
42		mimimi_x86_blocks[i] = 1;
43		for (int j = 1 ; j < blocks ; j++)
44			mimimi_x86_blocks[i + j] = 2;
45		
46		unsigned char *data = mimimi_x86_heap + i * 1024;
47		return data;
48		
49		next:;
50	}
51	
52	mimimi_x86_exit();
53}
54
55static void mimimi_x86_deallocate(void *data0)
56{
57	unsigned char *data = data0;
58	int block = (data - mimimi_x86_heap) / 1024;
59	
60	mimimi_x86_blocks[block] = 0;
61	for (int i = 1 ; mimimi_x86_blocks[block + i] == 2 ; i++)
62		mimimi_x86_blocks[block + i] = 0;
63}
64
65static void *mimimi_x86_reallocate(void *data0, unsigned int size)
66{
67	if (data0 == 0) return mimimi_x86_allocate(size);
68	
69	unsigned char *data = data0;
70	int block = (data - mimimi_x86_heap) / 1024;
71	
72	int current_count = 1;
73	while (mimimi_x86_blocks[block + current_count] == 2) current_count++;
74	
75	int target_count = (size - 1) / 1024 + 1;
76	
77	if (target_count <= current_count)
78	{
79		for (int i = target_count ; i < current_count ; i++)
80			mimimi_x86_blocks[block + i] = 0;
81		return data;
82	}
83	
84	for (int i = current_count ; i < target_count ; i++)
85	{
86		if (mimimi_x86_blocks[block + i] != 0)
87		{
88			unsigned char *new = mimimi_x86_allocate(size);
89			for (unsigned int i = 0 ; i < current_count * 1024 ; i++)
90				new[i] = data[i];
91			mimimi_x86_deallocate(data);
92			return new;
93		}
94	}
95	
96	for (int i = current_count ; i < target_count ; i++)
97		mimimi_x86_blocks[block + i] = 2;
98	return data;
99}
100
101static struct mimimi_allocator mimimi_x86_allocator_value = {&mimimi_x86_allocate, &mimimi_x86_reallocate, &mimimi_x86_deallocate, 0};
102static struct mimimi_allocator *mimimi_x86_allocator = &mimimi_x86_allocator_value;
103
104static unsigned char *mimimi_x86_buffer;
105static unsigned char *mimimi_x86_out_buffer;
106
107static void mimimi_x86_stamp(void *data, int x1, int y1, struct mimimi_image *image)
108{
109	int x0 = 0;
110	int y0 = 0;
111	
112	if (x1 < 0) x0 = -x1;
113	if (y1 < 0) y0 = -y1;
114	
115	int width = image->width;
116	int height = image->height;
117	
118	if (width + x1 > 512) width = 512 - x1;
119	if (height + y1 > 256) height = 256 - y1;
120	
121	for (int y = y0 ; y < height ; y++)
122	for (int x = x0 ; x < width ; x++)
123	{
124		unsigned char color = image->colors[x + y * image->width];
125		if (color == 0) continue;
126		
127		int x2 = x + x1;
128		int y2 = y + y1;
129		
130		mimimi_x86_buffer[x2 + y2 * 512] = color;
131	}
132}
133
134static struct mimimi_chapter *chapter;
135
136void mimimi_x86_start(void)
137{
138	mimimi_x86_buffer = mimimi_x86_allocate(512 * 256);
139	mimimi_x86_out_buffer = mimimi_x86_allocate(512 * 256 * 4);
140	
141	static struct mimimi_size size = {512, 256};
142	chapter = mimimi_test(mimimi_x86_allocator);
143	chapter->engine->size = &size;
144	chapter->engine->stamp = &mimimi_x86_stamp;
145}
146
147void mimimi_x86_step(void)
148{
149	extern unsigned char mimimi_x86_left;
150	extern unsigned char mimimi_x86_right;
151	
152	chapter->left = mimimi_x86_left;
153	chapter->right = mimimi_x86_right;
154	
155	(*chapter->behavior->behave)(chapter->behavior->data);
156	
157	static unsigned char rch[] = {0x11, 0x44, 0x77, 0x99, 0xCC, 0xFF};
158	static unsigned char gch[] = {0x11, 0x33, 0x55, 0x77, 0x99, 0xBB, 0xDD, 0xFF};
159	static unsigned char bch[] = {0x22, 0x55, 0x88, 0xBB, 0xEE};
160	
161	unsigned int width = 512;
162	unsigned int height = 256;
163	
164	unsigned int x0 = (mimimi_vbe_screen.width - width) / 2;
165	unsigned int y0 = (mimimi_vbe_screen.height - height) / 2;
166	
167	if (mimimi_vbe_screen.width < width) x0 = 0, width = mimimi_vbe_screen.width;
168	if (mimimi_vbe_screen.height < height) y0 = 0, height = mimimi_vbe_screen.height;
169	
170	for (unsigned int y = 0 ; y < height ; y++)
171	for (unsigned int x = 0 ; x < width ; x++)
172	{
173		unsigned char color = mimimi_x86_buffer[x + y * 512];
174		unsigned int i = (x + y * 512) * 4;
175		
176		if (color < 0x10)
177		{
178			unsigned char ch = color * 0x11;
179			mimimi_x86_out_buffer[i + 0] = ch;
180			mimimi_x86_out_buffer[i + 1] = ch;
181			mimimi_x86_out_buffer[i + 2] = ch;
182		}
183		else
184		{
185			color -= 0x10;
186			unsigned char r, g, b;
187			r = rch[(color / 40) % 6];
188			g = gch[(color / 5) % 8];
189			b = bch[(color / 1) % 5];
190			
191			mimimi_x86_out_buffer[i + 0] = b;
192			mimimi_x86_out_buffer[i + 1] = g;
193			mimimi_x86_out_buffer[i + 2] = r;
194		}
195	}
196	
197	unsigned int *buffer = (void *)mimimi_x86_out_buffer;
198	
199	unsigned int o = x0 + y0 * mimimi_vbe_screen.bytes_per_line / 4;
200	for (unsigned int y = 0 ; y < height ; y++)
201	for (unsigned int x = 0 ; x < width ; x++)
202	{
203		unsigned int i = x + y * 512;
204		unsigned int j = x + y * mimimi_vbe_screen.bytes_per_line / 4;
205		mimimi_vbe_screen.buffer[j + o] = buffer[i];
206	}
207}