Mirai's Miscellaneous Misadventures
M23 / 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_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}