Mirai's Miscellaneous Misadventures

M53 / core / animations.c

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