Mirai's Miscellaneous Misadventures

M23 / 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_rotating_image_pixel(struct mimimi_rotating_image *rotating_image, unsigned char slant, int x, int y)
14{
15	y += rotating_image->oy;
16	
17	int h = rotating_image->count;
18	if (y < 0) return 0;
19	if (y >= h) return 0;
20	
21	int w = rotating_image->rows[y].size;
22	if (x < -w / 2) return 0;
23	if (x >= w / 2) return 0;
24	
25	x += w / 2;
26	
27	int count = rotating_image->rows[y].count;
28	
29	int a = slant;
30	a *= count;
31	a += 128;
32	a /= 256;
33	a += x;
34	a %= count;
35	
36	return rotating_image->rows[y].colors[a];
37}
38
39static void mimimi_rotating_image_stamp(struct mimimi_image *image, struct mimimi_rotating_image *rotating_image, int x0, int y0, struct mimimi_pose_layer *layer, int behind)
40{
41	int width = image->width;
42	int height = image->height;
43	
44	unsigned char y_angle = layer->y_angle;
45	unsigned char z_angle = layer->z_angle;
46	unsigned char slant = layer->slant;
47	z_angle %= 4;
48	
49	x0 += rotating_image->oz * mimimi_cosine[y_angle] / 256;
50	
51	if (behind != 0) y_angle += 128;
52	
53	for (int y = 0 ; y < height ; y++)
54	for (int x = 0 ; x < width ; x++)
55	{
56		if (behind != 0 && image->colors[x + y * width] != 0) continue;
57		
58		int x1 = x - x0;
59		int y1 = y - y0;
60		
61		if (z_angle == 1)
62		{
63			int x0 = x1;
64			x1 = -y1;
65			y1 = x0;
66		}
67		if (z_angle == 2)
68		{
69			x1 = -x1;
70			y1 = -y1;
71		}
72		if (z_angle == 3)
73		{
74			int x0 = x1;
75			x1 = y1;
76			y1 = -x0;
77		}
78		
79		int x2 = x1 + y1 * mimimi_sine[slant] / 128;
80		
81		if (behind != 0) x2 = -x2 - 1;
82		
83		unsigned char color = mimimi_rotating_image_pixel(rotating_image, y_angle, x2, y1);
84		if (color == 0) continue;
85		
86		image->colors[x + y * width] = color;
87	}
88}
89
90static void mimimi_animation_layer(struct mimimi_image *image, struct mimimi_model_layer *layer, int x0, int y0, struct mimimi_pose_layer *pose_layer, unsigned char z_angle)
91{
92	z_angle %= 4;
93	
94	if (z_angle == 1)
95	{
96		int x = x0;
97		x0 = y0 + image->width/2 - image->height;
98		y0 = image->width/2 + image->height - x;
99	}
100	if (z_angle == 2)
101	{
102		x0 = image->width - x0;
103		y0 = image->height * 2 - y0;
104	}
105	if (z_angle == 3)
106	{
107		int x = x0;
108		x0 = image->width/2 + image->height - y0;
109		y0 = x - image->width/2 + image->height;
110	}
111	
112	for (int i = 0 ; i < layer->count ; i++)
113		mimimi_rotating_image_stamp(image, layer->images[i], x0, y0, pose_layer, 0),
114		mimimi_rotating_image_stamp(image, layer->images[i], x0, y0, pose_layer, 1);
115}
116
117static void mimimi_join_pose_layer(struct mimimi_pose_layer *a, struct mimimi_pose_layer *b)
118{
119	a->slant += b->slant;
120	a->y_angle += b->y_angle;
121	a->z_angle += b->z_angle;
122}
123
124void mimimi_pose(struct mimimi_image *image, struct mimimi_model *model, struct mimimi_pose *pose)
125{
126	struct mimimi_pose_layer *torso = &pose->torso;
127	struct mimimi_pose_layer head = pose->head;
128	struct mimimi_pose_layer left_arm = pose->left_arm;
129	struct mimimi_pose_layer right_arm = pose->right_arm;
130	struct mimimi_pose_layer left_leg = pose->left_leg;
131	struct mimimi_pose_layer right_leg = pose->right_leg;
132	
133	mimimi_join_pose_layer(&head, torso);
134	mimimi_join_pose_layer(&left_arm, torso);
135	mimimi_join_pose_layer(&right_arm, torso);
136	mimimi_join_pose_layer(&left_leg, torso);
137	mimimi_join_pose_layer(&right_leg, torso);
138	
139	for (int y = 0 ; y < image->height ; y++)
140	for (int x = 0 ; x < image->width ; x++)
141		image->colors[x + y * image->width] = 0;
142	
143	int x = pose->x + image->width / 2;
144	int y = pose->y + image->height;
145	
146	unsigned char slant = torso->slant;
147	unsigned char y_angle = torso->y_angle;
148	
149	int leg_y = y - 12;
150	int leg_x = x + mimimi_sine[slant] * (image->height - leg_y) / 128;
151	int left_leg_x = leg_x + 6 * mimimi_sine[y_angle] / 256;
152	int right_leg_x = leg_x - 6 * mimimi_sine[y_angle] / 256;
153	
154	int torso_y = y - 12;
155	int torso_x = x + mimimi_sine[slant] * (image->height - torso_y) / 128;
156	
157	int arm_y = y - 20;
158	int arm_x = x + mimimi_sine[slant] * (image->height - arm_y) / 128;
159	int left_arm_x = arm_x + 10 * mimimi_sine[y_angle] / 256;
160	int right_arm_x = arm_x - 10 * mimimi_sine[y_angle] / 256;
161	
162	int head_y = y - 23;
163	int head_x = x + mimimi_sine[slant] * (image->height - head_y) / 128;
164	
165	int z_angle = torso->z_angle;
166	
167	unsigned char y_angle2 = y_angle + 64;
168	if (y_angle2 < 128 + 8 && y_angle2 > 128 - 8)
169	{
170		mimimi_animation_layer(image, model->left_leg, left_leg_x, leg_y, &left_leg, z_angle);
171		mimimi_animation_layer(image, model->right_leg, right_leg_x, leg_y, &right_leg, z_angle);
172		
173		mimimi_animation_layer(image, model->left_arm, left_arm_x, arm_y, &left_arm, z_angle);
174		mimimi_animation_layer(image, model->right_arm, right_arm_x, arm_y, &right_arm, z_angle);
175		mimimi_animation_layer(image, model->torso, torso_x, torso_y, torso, z_angle);
176	}
177	else if (y_angle2 < 128)
178	{
179		mimimi_animation_layer(image, model->left_leg, left_leg_x, leg_y, &left_leg, z_angle);
180		mimimi_animation_layer(image, model->right_leg, right_leg_x, leg_y, &right_leg, z_angle);
181		
182		mimimi_animation_layer(image, model->left_arm, left_arm_x, arm_y, &left_arm, z_angle);
183		mimimi_animation_layer(image, model->torso, torso_x, torso_y, torso, z_angle);
184		mimimi_animation_layer(image, model->right_arm, right_arm_x, arm_y, &right_arm, z_angle);
185	}
186	else
187	{
188		mimimi_animation_layer(image, model->right_leg, right_leg_x, leg_y, &right_leg, z_angle);
189		mimimi_animation_layer(image, model->left_leg, left_leg_x, leg_y, &left_leg, z_angle);
190		
191		mimimi_animation_layer(image, model->right_arm, right_arm_x, arm_y, &right_arm, z_angle);
192		mimimi_animation_layer(image, model->torso, torso_x, torso_y, torso, z_angle);
193		mimimi_animation_layer(image, model->left_arm, left_arm_x, arm_y, &left_arm, z_angle);
194	}
195	mimimi_animation_layer(image, model->head, head_x, head_y, &head, z_angle);
196}
197
198static void mimimi_interpolate_pose_layer(struct mimimi_pose_layer *a, struct mimimi_pose_layer *b, int i, int count)
199{
200	int slant = a->slant * (count - i) / count;
201	slant += mimimi_div(b->slant * i, count);
202	
203	int y_angle = a->y_angle * (count - i) / count;
204	y_angle += mimimi_div(b->y_angle * i, count);
205	
206	int z_angle = a->z_angle * (count - i) / count;
207	z_angle += mimimi_div(b->z_angle * i, count);
208	
209	a->slant = slant;
210	a->y_angle = y_angle;
211	a->z_angle = z_angle;
212}
213
214static void mimimi_interpolate_pose(struct mimimi_pose *a, struct mimimi_pose *b, int i, int count)
215{
216	if (count == 0) return;
217	
218	int x = a->x * (count - i) / count;
219	x += mimimi_div(b->x * i, count);
220	
221	int y = a->y * (count - i) / count;
222	y += mimimi_div(b->y * i, count);
223	
224	a->x = x;
225	a->y = y;
226	
227	mimimi_interpolate_pose_layer(&a->torso, &b->torso, i, count);
228	mimimi_interpolate_pose_layer(&a->head, &b->head, i, count);
229	mimimi_interpolate_pose_layer(&a->left_arm, &b->left_arm, i, count);
230	mimimi_interpolate_pose_layer(&a->right_arm, &b->right_arm, i, count);
231	mimimi_interpolate_pose_layer(&a->left_leg, &b->left_leg, i, count);
232	mimimi_interpolate_pose_layer(&a->right_leg, &b->right_leg, i, count);
233}
234
235void mimimi_movement(struct mimimi_animation *animation, struct mimimi_model *model, struct mimimi_movement *movement)
236{
237	if (movement->pose_count == 1)
238	{
239		for (int i = 0 ; i < animation->image_count ; i++)
240			mimimi_pose(animation->images + i, model, movement->poses);
241		return;
242	}
243	
244	for (int i = 0 ; i < animation->image_count ; i++)
245	{
246		int j = i * (movement->pose_count - 1) / animation->image_count;
247		int k = i - j * animation->image_count / (movement->pose_count - 1);
248		
249		struct mimimi_pose pose = movement->poses[j];
250		mimimi_interpolate_pose(&pose, movement->poses + j + 1, k, animation->image_count / (movement->pose_count - 1));
251		mimimi_pose(animation->images + i, model, &pose);
252	}
253}
254
255static void mimimi_appearance_animations(struct mimimi_animation_set *animations, struct mimimi_model *model, int coefficient)
256{
257	int count = animations->standing_animation_count;
258	for (int i = 0 ; i < count ; i++)
259	{
260		struct mimimi_pose poses[3] = {};
261		struct mimimi_movement movement = {3, poses};
262		
263		unsigned char slant = -8 * i / count * coefficient;
264		unsigned char y_angle = 64 + (12 + 24 * i / count) * coefficient;
265		unsigned char arm_slant = 16 * i / count;
266		
267		poses[0].torso.slant = slant;
268		poses[0].torso.y_angle = y_angle;
269		poses[0].left_arm.slant = -arm_slant;
270		poses[0].right_arm.slant = arm_slant;
271		poses[0].left_leg.slant = arm_slant;
272		poses[0].right_leg.slant = -arm_slant;
273		poses[0].head.slant = -slant;
274		
275		poses[1].torso.slant = slant;
276		poses[1].torso.y_angle = y_angle;
277		poses[1].left_arm.slant = arm_slant;
278		poses[1].right_arm.slant = -arm_slant;
279		poses[1].left_leg.slant = -arm_slant;
280		poses[1].right_leg.slant = arm_slant;
281		poses[1].head.slant = -slant;
282		
283		poses[2] = poses[0];
284		
285		mimimi_movement(animations->standing + i, model, &movement);
286		
287		struct mimimi_pose falling_poses[1] = {};
288		struct mimimi_movement falling_movement = {1, falling_poses};
289		
290		falling_poses[0].torso.z_angle = -coefficient;
291		falling_poses[0].torso.y_angle = 64 + 32 * coefficient;
292		falling_poses[0].left_arm.z_angle = -coefficient;
293		falling_poses[0].right_arm.z_angle = -coefficient;
294		falling_poses[0].left_leg.slant = -12 * coefficient;
295		falling_poses[0].right_leg.slant = -12 * coefficient;
296		falling_poses[0].left_arm.slant = 12 * coefficient;
297		falling_poses[0].right_arm.slant = -12 * coefficient;
298		falling_poses[0].x = -10 * coefficient;
299		falling_poses[0].y = 16;
300		
301		mimimi_movement(animations->falling, model, &falling_movement);
302		
303		struct mimimi_pose knocked_poses[1] = {};
304		struct mimimi_movement knocked_movement = {1, knocked_poses};
305		
306		knocked_poses[0].torso.z_angle = -coefficient;
307		knocked_poses[0].torso.y_angle = 64 + 32 * coefficient;
308		knocked_poses[0].x = -20 * coefficient;
309		knocked_poses[0].y = 16;
310		
311		mimimi_movement(animations->knocked, model, &knocked_movement);
312	}
313}
314
315void mimimi_appearance(struct mimimi_appearance *appearance, struct mimimi_model *model)
316{
317	mimimi_appearance_animations(&appearance->left, model, 1);
318	mimimi_appearance_animations(&appearance->right, model, -1);
319}