Mirai's Miscellaneous Misadventures

M39 / core / animations.c

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