Mirai's Miscellaneous Misadventures

M24 / core / animations.c

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