Mirai's Miscellaneous Misadventures
M39 / core / animations.c
1
2
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
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}