Mirai's Miscellaneous Misadventures
M18 / core / appearances.c
1
2
3
4#include <mimimi/models.h>
5#include <mimimi/appearances.h>
6#include <mimimi/allocators.h>
7
8#include "appearances.h"
9
10#include "math.c"
11
12static unsigned char mimimi_rotating_image_pixel(struct mimimi_rotating_image *rotating_image, unsigned char angle, int x, int y)
13{
14 y += rotating_image->oy;
15
16 int h = rotating_image->count;
17 if (y < 0) return 0;
18 if (y >= h) return 0;
19
20 int w = rotating_image->rows[y].size;
21 if (x < -w / 2) return 0;
22 if (x >= w / 2) return 0;
23
24 x += w / 2;
25
26 int count = rotating_image->rows[y].count;
27
28 int a = angle;
29 a *= count;
30 a += 128;
31 a /= 256;
32 a += x;
33 a %= count;
34
35 return rotating_image->rows[y].colors[a];
36}
37
38static void mimimi_rotating_image_stamp(struct mimimi_image *image, struct mimimi_rotating_image *rotating_image, unsigned char y_angle, unsigned char z_angle, int x0, int y0, int behind)
39{
40 int width = image->width;
41 int height = image->height;
42
43 x0 += rotating_image->oz * mimimi_cosine[y_angle] / 256;
44
45 if (behind != 0) y_angle += 128;
46
47 for (int x = 0 ; x < width ; x++)
48 for (int y = 0 ; y < height ; y++)
49 {
50 if (behind != 0 && image->colors[x + y * width] != 0) continue;
51
52 int x1 = x - x0;
53 int y1 = y - y0;
54
55 int x2 = x1 + y1 * mimimi_sine[z_angle] / 127;
56
57 if (behind != 0) x2 = -x2 - 1;
58
59 unsigned char color = mimimi_rotating_image_pixel(rotating_image, y_angle, x2, y1);
60 if (color == 0) continue;
61
62 image->colors[x + y * width] = color;
63 }
64}
65
66static void mimimi_animation_layer(struct mimimi_image *image, struct mimimi_model_layer *layer, unsigned char y_angle, unsigned char z_angle, int x0, int y0)
67{
68 for (int i = 0 ; i < layer->count ; i++)
69 {
70 mimimi_rotating_image_stamp(image, layer->images[i], y_angle, z_angle, x0, y0, 0);
71 mimimi_rotating_image_stamp(image, layer->images[i], y_angle, z_angle, x0, y0, 1);
72 }
73}
74
75static void mimimi_animation_frame(struct mimimi_sprite_image *sprite_image, struct mimimi_model *model, unsigned char y_angle, unsigned char z_angle, unsigned char arm_angle)
76{
77 struct mimimi_image *image = &sprite_image->image;
78
79 image->colors = sprite_image->colors;
80 image->width = 26;
81 image->height = 36;
82
83 for (int x = 0 ; x < image->width ; x++)
84 for (int y = 0 ; y < image->height ; y++)
85 image->colors[x + y * image->width] = 0;
86
87 int x = image->width / 2;
88
89 int head_y = 13;
90 int head_x = x + mimimi_sine[z_angle] * (image->height - head_y) / 127;
91
92 int arm_y = 16;
93 int arm_x = x + mimimi_sine[z_angle] * (image->height - arm_y) / 127;
94 int left_arm_x = arm_x + 10 * mimimi_sine[y_angle] / 256;
95 int right_arm_x = arm_x - 10 * mimimi_sine[y_angle] / 256;
96
97 int leg_y = 24;
98 int leg_x = x + mimimi_sine[z_angle] * (image->height - leg_y) / 127;
99 int left_leg_x = leg_x + 6 * mimimi_sine[y_angle] / 256;
100 int right_leg_x = leg_x - 6 * mimimi_sine[y_angle] / 256;
101
102 int torso_y = 24;
103 int torso_x = x + mimimi_sine[z_angle] * (image->height - torso_y) / 127;
104
105 mimimi_animation_layer(image, model->left_leg, y_angle, -arm_angle, left_leg_x, leg_y);
106 mimimi_animation_layer(image, model->right_leg, y_angle, arm_angle, right_leg_x, leg_y);
107 if ((y_angle + 64) % 256 < 128)
108 {
109 mimimi_animation_layer(image, model->left_arm, y_angle, arm_angle, left_arm_x, arm_y);
110 mimimi_animation_layer(image, model->torso, y_angle, z_angle, torso_x, torso_y);
111 mimimi_animation_layer(image, model->right_arm, y_angle, -arm_angle, right_arm_x, arm_y);
112 }
113 else
114 {
115 mimimi_animation_layer(image, model->right_arm, y_angle, -arm_angle, right_arm_x, arm_y);
116 mimimi_animation_layer(image, model->torso, y_angle, z_angle, torso_x, torso_y);
117 mimimi_animation_layer(image, model->left_arm, y_angle, arm_angle, left_arm_x, arm_y);
118 }
119 mimimi_animation_layer(image, model->head, y_angle, 0, head_x, head_y);
120}
121
122static void mimimi_animation(struct mimimi_animation *animation, struct mimimi_model *model, unsigned char y_angle, unsigned char z_angle, unsigned char arm_angle)
123{
124 int count = mimimi_image_count;
125 for (int i = 0 ; i < count ; i++)
126 mimimi_animation_frame(animation->images + i, model, y_angle, z_angle, arm_angle * mimimi_sine[i * 255 / count] / 127);
127}
128
129static void mimimi_animation_set(struct mimimi_animation *animations, struct mimimi_model *model, int coefficient, unsigned char z_angle, unsigned char arm_angle)
130{
131 int count = mimimi_animation_count;
132 for (int i = 0 ; i < count ; i++)
133 mimimi_animation(animations + i, model, 64 + (12 + 34 * i / count) * coefficient, -z_angle * i / count * coefficient, arm_angle * i / count);
134}
135
136
137static void mimimi_transpose_image(struct mimimi_image *image)
138{
139 int width = image->width;
140 int height = image->height;
141 image->width = height;
142 image->height = width;
143
144 for (int start = 0 ; start < width * height ; start++)
145 {
146 int next = start;
147 int i = 0;
148 for (;;)
149 {
150 i++;
151 next = (next % height) * width + next / height;
152 if (next <= start) break;
153 }
154
155 if (i == 1) continue;
156 if (next < start) continue;
157
158 char tmp = image->colors[next = start];
159 for (;;)
160 {
161 int i = (next % height) * width + next / height;
162 image->colors[next] = (i == start) ? tmp : image->colors[i];
163 next = i;
164 if (next <= start) break;
165 }
166 }
167}
168
169static void mimimi_flip_image(struct mimimi_image *image)
170{
171 for (int x = 0 ; x < image->width / 2 ; x++)
172 for (int y = 0 ; y < image->height ; y++)
173 {
174 unsigned char color = image->colors[image->width - x - 1 + y * image->width];
175 image->colors[image->width - x - 1 + y * image->width] = image->colors[x + y * image->width];
176 image->colors[x + y * image->width] = color;
177 }
178}
179
180static void mimimi_rotate_image_cw(struct mimimi_image *image)
181{
182 mimimi_transpose_image(image);
183 mimimi_flip_image(image);
184}
185
186static void mimimi_rotate_image_ccw(struct mimimi_image *image)
187{
188 mimimi_flip_image(image);
189 mimimi_transpose_image(image);
190}
191
192struct mimimi_appearance *mimimi_appearance(struct mimimi_model *model, struct mimimi_allocator *allocator)
193{
194 struct mimimi_appearance *appearance = (*allocator->allocate)(sizeof *appearance);
195
196 unsigned char z_angle = 9;
197 unsigned char arm_angle = 16;
198 unsigned char arm_flail_angle = 32;
199
200 mimimi_animation_set(appearance->left.standing, model, 1, z_angle, arm_angle);
201 mimimi_animation_set(appearance->right.standing, model, -1, z_angle, arm_angle);
202
203 mimimi_animation(&appearance->left.knocked, model, 64 + 16, 0, arm_flail_angle);
204 mimimi_animation(&appearance->right.knocked, model, 64 - 16, 0, arm_flail_angle);
205
206 for (int i = 0 ; i < mimimi_image_count ; i++)
207 {
208 mimimi_rotate_image_cw(&appearance->left.knocked.images[i].image);
209 mimimi_rotate_image_ccw(&appearance->right.knocked.images[i].image);
210 }
211
212 return appearance;
213}
214
215static struct mimimi_appearance mimimi_empty_appearance_value = {};
216struct mimimi_appearance *mimimi_empty_appearance = &mimimi_empty_appearance_value;