Mirai's Miscellaneous Misadventures

M54 / core / animations.c

1/* license: AGPLv3 or later */
2/* copyright 2024 zamfofex */
3
4#include "../mimimi.h"
5
6static unsigned char mimimi_layer_pixel(struct mimimi_layer *layer, unsigned char y_angle, int x, int y)
7{
8	int w, h;
9	int w0, w1;
10	int s;
11	int count;
12	int a;
13	
14	h = layer->count;
15	
16	if (y < 0 || y >= h) return 0;
17	
18	w0 = layer->rows[y].width;
19	w1 = layer->rows[y].height;
20	
21	s = 128 - mimimi_cosine[y_angle * 16 % 2048];
22	w = s * w0 + (256 - s) * w1;
23	w /= 512;
24	
25	if (x < -w || x >= w) return 0;
26	
27	count = layer->rows[y].count;
28	
29	a = y_angle + 64;
30	a *= count;
31	a += 128;
32	a /= 256;
33	a += x;
34	a = mimimi_mod(a, count);
35	
36	return layer->rows[y].colors[a];
37}
38
39static void mimimi_swap(int *a, int *b)
40{
41	int c;
42	c = *a;
43	*a = *b;
44	*b = c;
45}
46
47static void mimimi_layer(struct mimimi_image *image, struct mimimi_layer *layer, int x0, int y0, struct mimimi_pose_layer *pose_layer, int behind)
48{
49	int width, height;
50	unsigned char y_angle;
51	int z_angle;
52	int x, y;
53	int x1, y1;
54	unsigned char color;
55	
56	width = image->width;
57	height = image->height;
58	
59	y_angle = pose_layer->y_angle;
60	z_angle = mimimi_mod(pose_layer->z_angle, 4);
61	
62	if (behind != 0) y_angle += 128;
63	
64	if (z_angle == 0) {
65		
66		for (y = 0 ; y < height ; y++) {
67			
68			for (x = 0 ; x < width ; x++) {
69				
70				x1 = x + layer->x - x0;
71				y1 = y + layer->y - y0;
72				
73				x1 += pose_layer->slant * (y - y0) / 256;
74				
75				if (behind != 0) x1 = -x1 - 1;
76				
77				color = mimimi_layer_pixel(layer, y_angle, x1, y1);
78				if (color != 0) image->colors[x + y * width] = color;
79			}
80		}
81	}
82	
83	if (z_angle == 1) {
84		
85		for (y = 0 ; y < height ; y++) {
86			
87			for (x = 0 ; x < width ; x++) {
88				
89				x1 = x - layer->y - x0;
90				y1 = y + layer->x - y0;
91				
92				y1 -= pose_layer->slant * (x - x0) / 256;
93				
94				if (behind != 0) y1 = -y1 - 1;
95				
96				color = mimimi_layer_pixel(layer, y_angle, y1, -x1);
97				if (color != 0) image->colors[x + y * width] = color;
98			}
99		}
100	}
101	
102	if (z_angle == 2) {
103		
104		for (y = 0 ; y < height ; y++) {
105			
106			for (x = 0 ; x < width ; x++) {
107				
108				x1 = x - layer->x - x0;
109				y1 = y - layer->y - y0;
110				
111				x1 += pose_layer->slant * (y - y0) / 256;
112				
113				if (behind != 0) x1 = -x1 + 1;
114				
115				color = mimimi_layer_pixel(layer, y_angle, -x1, -y1);
116				if (color != 0) image->colors[x + y * width] = color;
117			}
118		}
119	}
120	
121	if (z_angle == 3) {
122		
123		for (y = 0 ; y < height ; y++) {
124			
125			for (x = 0 ; x < width ; x++) {
126				
127				x1 = x + layer->y - x0;
128				y1 = y - layer->x - y0;
129				
130				y1 -= pose_layer->slant * (x - x0) / 256;
131				
132				if (behind != 0) y1 = -y1 + 1;
133				
134				color = mimimi_layer_pixel(layer, y_angle, -y1, x1);
135				if (color != 0) image->colors[x + y * width] = color;
136			}
137		}
138	}
139}
140
141static void mimimi_apply_y_angle(struct mimimi_model *model, struct mimimi_layer *layers, struct mimimi_pose_layer *pose_layers)
142{
143	int i, parent_index;
144	struct mimimi_layer *layer;
145	struct mimimi_pose_layer *pose_layer;
146	int parent_y_angle;
147	unsigned char y_angle;
148	int sin, cos;
149	int x, z;
150	
151	for (i = 0 ; i < model->count ; i++) {
152		
153		layer = layers + i;
154		pose_layer = pose_layers + i;
155		parent_index = model->layers[i].parent_index;
156		
157		if (i == parent_index) continue;
158		
159		parent_y_angle = pose_layers[parent_index].y_angle;
160		pose_layer->y_angle += parent_y_angle;
161		
162		y_angle = parent_y_angle;
163		
164		sin = mimimi_sine[y_angle * 8];
165		cos = mimimi_cosine[y_angle * 8];
166		
167		x = layer->x;
168		z = layer->z;
169		
170		layer->x = cos * x / 128 + sin * z / 128;
171		layer->z = cos * z / 128 - sin * x / 128;
172	}
173}
174
175static void mimimi_apply_z_angle(struct mimimi_model *model, struct mimimi_layer *layers, struct mimimi_pose_layer *pose_layers)
176{
177	static int xs[0x80], ys[0x80];
178	
179	int i;
180	struct mimimi_layer *layer;
181	struct mimimi_pose_layer *pose_layer;
182	int parent_index;
183	int z_angle;
184	int x, y;
185	
186	for (i = 0 ; i < model->count ; i++) {
187		
188		layer = layers + i;
189		pose_layer = pose_layers + i;
190		parent_index = model->layers[i].parent_index;
191		
192		xs[i] = layer->x;
193		ys[i] = layer->y;
194		if (i == parent_index) continue;
195		xs[i] += xs[parent_index];
196		ys[i] += ys[parent_index];
197		
198		z_angle = mimimi_mod(pose_layer->z_angle, 4);
199		
200		x = xs[i];
201		y = ys[i];
202		if (z_angle == 1) {
203			x = -x;
204			mimimi_swap(&x, &y);
205		}
206		if (z_angle == 2) {
207			x = -x;
208			y = -y;
209		}
210		if (z_angle == 3) {
211			y = -y;
212			mimimi_swap(&x, &y);
213		}
214		layer->x = x - xs[parent_index];
215		layer->y = y - ys[parent_index];
216		
217		if (z_angle == 1) {
218			xs[i] = -xs[i];
219			mimimi_swap(xs + i, ys + i);
220		}
221		if (z_angle == 2) {
222			xs[i] = -xs[i];
223			ys[i] = -ys[i];
224		}
225		if (z_angle == 3) {
226			ys[i] = -ys[i];
227			mimimi_swap(xs + i, ys + i);
228		}
229	}
230}
231
232static void mimimi_apply_slant(struct mimimi_model *model, struct mimimi_layer *layers, struct mimimi_pose_layer *pose_layers)
233{
234	static int ys[0x80];
235	
236	int i;
237	struct mimimi_layer *layer;
238	struct mimimi_pose_layer *pose_layer;
239	int parent_index;
240	
241	for (i = 0 ; i < model->count ; i++) {
242		
243		layer = layers + i;
244		pose_layer = pose_layers + i;
245		parent_index = model->layers[i].parent_index;
246		
247		ys[i] = layer->y + pose_layer->y;
248		if (i == parent_index) continue;
249		ys[i] += ys[parent_index];
250		
251		layer->x += pose_layer->slant * ys[i] / 256;
252	}
253}
254
255static void mimimi_absolutise(struct mimimi_model *model, struct mimimi_layer *layers, struct mimimi_pose_layer *pose_layers)
256{
257	int i;
258	struct mimimi_layer *layer;
259	struct mimimi_pose_layer *pose_layer;
260	int parent_index;
261	
262	for (i = 0 ; i < model->count ; i++) {
263		
264		layer = layers + i;
265		pose_layer = pose_layers + i;
266		parent_index = model->layers[i].parent_index;
267		
268		layer->y += pose_layer->y;
269		
270		if (i == parent_index) continue;
271		
272		layer->x += layers[parent_index].x;
273		layer->y += layers[parent_index].y;
274		layer->z += layers[parent_index].z;
275		layer->amplifier = layer->amplifier * layers[parent_index].amplifier / 32;
276		
277		pose_layer->slant += pose_layers[parent_index].slant;
278		pose_layer->z_angle += pose_layers[parent_index].z_angle;
279		pose_layer->z_angle = mimimi_mod(pose_layer->z_angle, 4);
280	}
281}
282
283struct mimimi_half_layer {
284	int behind;
285	int z;
286	struct mimimi_layer *layer;
287	struct mimimi_pose_layer *pose_layer;
288};
289
290void mimimi_pose(struct mimimi_image *image, struct mimimi_model *model, struct mimimi_pose *pose)
291{
292	static struct mimimi_layer layers[0x80];
293	static struct mimimi_pose_layer pose_layers[0x80];
294	static struct mimimi_half_layer half_layers[0x100];
295	
296	struct mimimi_layer *layer;
297	struct mimimi_pose_layer *pose_layer;
298	struct mimimi_half_layer *half_layer, half_layer0;
299	int i, j, k;
300	int a, b;
301	
302	for (i = 0 ; i < model->count ; i++) {
303		layers[i] = *model->layers[i].layer;
304		pose_layers[i] = pose->layers[i];
305	}
306	
307	mimimi_apply_y_angle(model, layers, pose_layers);
308	mimimi_apply_z_angle(model, layers, pose_layers);
309	mimimi_apply_slant(model, layers, pose_layers);
310	mimimi_absolutise(model, layers, pose_layers);
311	
312	for (i = 0 ; i < model->count ; i++) {
313		
314		layer = layers + i;
315		pose_layer = pose_layers + i;
316		
317		half_layers[i * 2 + 0].behind = 0;
318		half_layers[i * 2 + 0].z = layer->z * layer->amplifier + layer->width * 32;
319		half_layers[i * 2 + 0].layer = layer;
320		half_layers[i * 2 + 0].pose_layer = pose_layer;
321		
322		half_layers[i * 2 + 1].behind = 1;
323		half_layers[i * 2 + 1].z = layer->z * layer->amplifier - layer->width * 32;
324		half_layers[i * 2 + 1].layer = layer;
325		half_layers[i * 2 + 1].pose_layer = pose_layer;
326	}
327	
328	/* z ordering */
329	for (i = 0 ; i < model->count * 2 ; i++) {
330		
331		a = half_layers[i].z;
332		
333		k = i;
334		for (j = i - 1 ; j >= 0 ; j--) {
335			
336			b = half_layers[j].z;
337			if (a >= b) break;
338			
339			half_layer0 = half_layers[k];
340			half_layers[k] = half_layers[j];
341			half_layers[j] = half_layer0;
342			
343			k = j;
344		}
345	}
346	
347	for (i = 0 ; i < model->count * 2 ; i++) {
348		half_layer = half_layers + i;
349		mimimi_layer(image, half_layer->layer, pose->x, pose->y, half_layer->pose_layer, half_layer->behind);
350	}
351}
352
353static void mimimi_interpolate_layer(struct mimimi_pose_layer *a, struct mimimi_pose_layer *b, int i, int count)
354{
355	int y, slant, y_angle, z_angle;
356	
357	y = a->y * (count - i);
358	y += b->y * i;
359	
360	slant = a->slant * (count - i);
361	slant += b->slant * i;
362	
363	y_angle = a->y_angle * (count - i);
364	y_angle += b->y_angle * i;
365	
366	z_angle = a->z_angle * (count - i);
367	z_angle += b->z_angle * i;
368	
369	a->y = mimimi_div(y, count);
370	a->slant = mimimi_div(slant, count);
371	a->y_angle = mimimi_div(y_angle, count);
372	a->z_angle = mimimi_div(z_angle, count);
373}
374
375void mimimi_interpolate(struct mimimi_pose *a, struct mimimi_pose *b, int i, int count)
376{
377	int x, y;
378	int j;
379	
380	i = 128 - mimimi_cosine[i * 1024 / count];
381	count = 256;
382	
383	x = a->x * (count - i);
384	x += b->x * i;
385	
386	y = a->y * (count - i);
387	y += b->y * i;
388	
389	a->x = mimimi_div(x, count);
390	a->y = mimimi_div(y, count);
391	
392	for (j = 0 ; j < (int) (sizeof a->layers / sizeof *a->layers) ; j++) mimimi_interpolate_layer(a->layers + j, b->layers + j, i, count);
393}