Mirai's Miscellaneous Misadventures
M46 / core / animations.c
#include <mimimi.h>
static unsigned char mimimi_layer_pixel(struct mimimi_layer *layer, unsigned char y_angle, int x, int y)
{
int w, h;
int w0, w1;
int s;
int count;
int a;
h = layer->count;
if (y < 0) return 0;
if (y >= h) return 0;
w0 = layer->rows[y].width;
w1 = layer->rows[y].height;
s = 128 - mimimi_cosine[y_angle * 2 % 256];
w = s * w0 + (256 - s) * w1;
w /= 512;
if (x < -w) return 0;
if (x >= w) return 0;
count = layer->rows[y].count;
a = y_angle + 64;
a *= count;
a += 128;
a /= 256;
a += x;
a = mimimi_mod(a, count);
return layer->rows[y].colors[a];
}
static void mimimi_swap(int *x, int *y)
{
int z;
z = *x;
*x = *y;
*y = z;
}
static void mimimi_layer(struct mimimi_image *image, struct mimimi_layer *layer, int x0, int y0, struct mimimi_pose_layer *pose_layer, int behind)
{
int width, height;
unsigned char y_angle;
int z_angle;
int x, y;
int x1, y1;
unsigned char color;
width = image->width;
height = image->height;
y_angle = pose_layer->y_angle;
z_angle = mimimi_mod(pose_layer->z_angle, 4);
if (behind != 0) y_angle += 128;
if (z_angle == 0)
{
for (y = 0 ; y < height ; y++)
for (x = 0 ; x < width ; x++)
{
x1 = x + layer->x - x0;
y1 = y + layer->y - y0;
x1 += pose_layer->slant * (y - y0) / 256;
if (behind != 0) x1 = -x1 - 1;
color = mimimi_layer_pixel(layer, y_angle, x1, y1);
if (color != 0) image->colors[x + y * width] = color;
}
}
if (z_angle == 1)
{
for (y = 0 ; y < height ; y++)
for (x = 0 ; x < width ; x++)
{
x1 = x - layer->y - x0;
y1 = y + layer->x - y0;
y1 -= pose_layer->slant * (x - x0) / 256;
if (behind != 0) y1 = -y1 - 1;
color = mimimi_layer_pixel(layer, y_angle, y1, -x1);
if (color != 0) image->colors[x + y * width] = color;
}
return;
}
if (z_angle == 2)
{
for (y = 0 ; y < height ; y++)
for (x = 0 ; x < width ; x++)
{
x1 = x - layer->x - x0;
y1 = y - layer->y - y0;
x1 += pose_layer->slant * (y - y0) / 256;
if (behind != 0) x1 = -x1 + 1;
color = mimimi_layer_pixel(layer, y_angle, -x1, -y1);
if (color != 0) image->colors[x + y * width] = color;
}
return;
}
if (z_angle == 3)
{
for (y = 0 ; y < height ; y++)
for (x = 0 ; x < width ; x++)
{
x1 = x + layer->y - x0;
y1 = y - layer->x - y0;
y1 -= pose_layer->slant * (x - x0) / 256;
if (behind != 0) y1 = -y1 + 1;
color = mimimi_layer_pixel(layer, y_angle, -y1, x1);
if (color != 0) image->colors[x + y * width] = color;
}
return;
}
}
static void mimimi_apply_y_angle(struct mimimi_model *model, struct mimimi_layer *layers, struct mimimi_pose_layer *pose_layers)
{
int i, parent_index;
struct mimimi_layer *layer;
struct mimimi_pose_layer *pose_layer;
int parent_y_angle;
unsigned char y_angle;
int sin, cos;
int x, z;
for (i = 0 ; i < model->count ; i++)
{
layer = layers + i;
pose_layer = pose_layers + i;
parent_index = model->layers[i].parent_index;
if (i == parent_index) continue;
parent_y_angle = pose_layers[parent_index].y_angle;
pose_layer->y_angle += parent_y_angle;
y_angle = parent_y_angle;
sin = mimimi_sine[y_angle];
cos = mimimi_cosine[y_angle];
x = layer->x;
z = layer->z;
layer->x = cos*x / 128 + sin*z / 128;
layer->z = cos*z / 128 - sin*x / 128;
}
}
static void mimimi_apply_z_angle(struct mimimi_model *model, struct mimimi_layer *layers, struct mimimi_pose_layer *pose_layers)
{
int xs[0x80], ys[0x80];
int i;
struct mimimi_layer *layer;
struct mimimi_pose_layer *pose_layer;
int parent_index;
int z_angle;
int x, y;
for (i = 0 ; i < model->count ; i++)
{
layer = layers + i;
pose_layer = pose_layers + i;
parent_index = model->layers[i].parent_index;
xs[i] = layer->x;
ys[i] = layer->y;
if (i == parent_index) continue;
xs[i] += xs[parent_index];
ys[i] += ys[parent_index];
z_angle = mimimi_mod(pose_layer->z_angle, 4);
x = xs[i];
y = ys[i];
if (z_angle == 1) x = -x, mimimi_swap(&x, &y);
if (z_angle == 2) x = -x, y = -y;
if (z_angle == 3) y = -y, mimimi_swap(&x, &y);
layer->x = x - xs[parent_index];
layer->y = y - ys[parent_index];
if (z_angle == 1) xs[i] = -xs[i], mimimi_swap(xs + i, ys + i);
if (z_angle == 2) xs[i] = -xs[i], ys[i] = -ys[i];
if (z_angle == 3) ys[i] = -ys[i], mimimi_swap(xs + i, ys + i);
}
}
static void mimimi_apply_slant(struct mimimi_model *model, struct mimimi_layer *layers, struct mimimi_pose_layer *pose_layers)
{
int ys[0x80];
int i;
struct mimimi_layer *layer;
struct mimimi_pose_layer *pose_layer;
int parent_index;
for (i = 0 ; i < model->count ; i++)
{
layer = layers + i;
pose_layer = pose_layers + i;
parent_index = model->layers[i].parent_index;
ys[i] = layer->y;
if (i == parent_index) continue;
ys[i] += ys[parent_index];
layer->x += pose_layer->slant * ys[i] / 256;
}
}
static void mimimi_absolutise(struct mimimi_model *model, struct mimimi_layer *layers, struct mimimi_pose_layer *pose_layers)
{
int i;
struct mimimi_layer *layer;
struct mimimi_pose_layer *pose_layer;
int parent_index;
for (i = 0 ; i < model->count ; i++)
{
layer = layers + i;
pose_layer = pose_layers + i;
parent_index = model->layers[i].parent_index;
if (i == parent_index) continue;
layer->x += layers[parent_index].x;
layer->y += layers[parent_index].y;
layer->z += layers[parent_index].z;
layer->amplifier = layer->amplifier * layers[parent_index].amplifier / 32;
pose_layer->slant += pose_layers[parent_index].slant;
pose_layer->z_angle += pose_layers[parent_index].z_angle;
pose_layer->z_angle = mimimi_mod(pose_layer->z_angle, 4);
}
}
struct mimimi_half_layer
{
int behind;
int z;
struct mimimi_layer *layer;
struct mimimi_pose_layer *pose_layer;
};
void mimimi_pose(struct mimimi_image *image, struct mimimi_model *model, struct mimimi_pose *pose)
{
struct mimimi_layer layers[0x20], *layer;
struct mimimi_pose_layer pose_layers[0x20], *pose_layer;
struct mimimi_half_layer half_layers[0x40], *half_layer, half_layer0;
int i, j, k;
int x, y;
int a, b;
for (i = 0 ; i < model->count ; i++)
{
layer = layers + i;
*layer = *model->layers[i].layer;
pose_layer = pose_layers + i;
if (i < pose->count)
{
*pose_layer = pose->layers[i];
}
else
{
pose_layer->slant = 0;
pose_layer->y_angle = 0;
pose_layer->z_angle = 0;
}
}
mimimi_apply_y_angle(model, layers, pose_layers);
mimimi_apply_z_angle(model, layers, pose_layers);
mimimi_apply_slant(model, layers, pose_layers);
mimimi_absolutise(model, layers, pose_layers);
for (i = 0 ; i < model->count ; i++)
{
layer = layers + i;
pose_layer = pose_layers + i;
half_layers[i * 2 + 0].behind = 0;
half_layers[i * 2 + 0].z = layer->z * layer->amplifier + layer->width * 32;
half_layers[i * 2 + 0].layer = layer;
half_layers[i * 2 + 0].pose_layer = pose_layer;
half_layers[i * 2 + 1].behind = 1;
half_layers[i * 2 + 1].z = layer->z * layer->amplifier - layer->width * 32;
half_layers[i * 2 + 1].layer = layer;
half_layers[i * 2 + 1].pose_layer = pose_layer;
}
for (i = 0 ; i < model->count * 2 ; i++)
{
a = half_layers[i].z;
k = i;
for (j = i - 1 ; j >= 0 ; j--)
{
b = half_layers[j].z;
if (a >= b) break;
half_layer0 = half_layers[k];
half_layers[k] = half_layers[j];
half_layers[j] = half_layer0;
k = j;
}
}
for (y = 0 ; y < image->height ; y++)
for (x = 0 ; x < image->width ; x++)
image->colors[x + y * image->width] = 0;
for (i = 0 ; i < model->count * 2 ; i++)
{
half_layer = half_layers + i;
mimimi_layer(image, half_layer->layer, pose->x, pose->y, half_layer->pose_layer, half_layer->behind);
}
}
static void mimimi_interpolate_pose_layer(struct mimimi_pose_layer *a, struct mimimi_pose_layer *b, int i, int count)
{
int slant, y_angle, z_angle;
slant = a->slant * (count - i) / count;
slant += mimimi_div(b->slant * i, count);
y_angle = a->y_angle * (count - i) / count;
y_angle += mimimi_div(b->y_angle * i, count);
z_angle = a->z_angle * (count - i) / count;
z_angle += mimimi_div(b->z_angle * i, count);
a->slant = slant;
a->y_angle = y_angle;
a->z_angle = z_angle;
}
static void mimimi_interpolate_pose(struct mimimi_pose *a, struct mimimi_pose *b, int i, int count)
{
int x, y;
int j;
if (count == 0) return;
x = a->x * (count - i) / count;
x += mimimi_div(b->x * i, count);
y = a->y * (count - i) / count;
y += mimimi_div(b->y * i, count);
a->x = x;
a->y = y;
for (j = 0 ; j < a->count ; j++)
mimimi_interpolate_pose_layer(a->layers + j, b->layers + j, i, count);
}
void mimimi_movement(struct mimimi_video *video, struct mimimi_model *model, struct mimimi_movement *movement)
{
int h, i, j, k;
struct mimimi_pose pose;
if (movement->count == 1)
{
for (i = 0 ; i < video->count ; i++)
mimimi_pose(video->images + i, model, movement->poses);
return;
}
for (i = 0 ; i < video->count ; i++)
{
j = i * (movement->count - 1) / video->count;
k = i - j * video->count / (movement->count - 1);
pose = movement->poses[j];
for (h = 0 ; h < pose.count ; h++) pose.layers[h] = movement->poses[j].layers[h];
mimimi_interpolate_pose(&pose, movement->poses + j + 1, k, video->count / (movement->count - 1));
mimimi_pose(video->images + i, model, &pose);
}
}
static void mimimi_appearance_videos(struct mimimi_video_set *videos, struct mimimi_model *model, int x, int y, int coefficient)
{
static struct mimimi_pose_layer layer0 = {0};
int video_count;
int i, j;
int slant, y_angle;
struct mimimi_pose poses[3], pose;
struct mimimi_movement movement;
struct mimimi_pose_layer layers[2][10];
video_count = videos->standing_video_count;
for (i = 0 ; i < video_count ; i++)
{
slant = 512 * i / video_count * coefficient;
y_angle = 64 + (20 + 20 * i / video_count) * coefficient;
for (j = 0 ; j < 10 ; j++)
{
layers[0][j] = layer0;
layers[1][j] = layer0;
}
layers[0][0].y_angle = y_angle;
layers[1][0].y_angle = y_angle;
layers[0][0].slant = -slant / 8;
layers[1][0].slant = -slant / 8;
layers[0][1].slant = slant / 8;
layers[1][1].slant = slant / 8;
layers[1][4].slant = slant / 3;
layers[1][8].slant = -slant / 3;
layers[0][8].slant = -slant / 8;
layers[0][5].slant = slant / 3;
layers[0][9].slant = -slant / 3;
layers[1][9].slant = -slant / 8;
layers[0][2].slant = slant / 5;
layers[1][2].slant = -slant / 3;
layers[0][6].slant = slant / 4;
layers[1][6].slant = slant / 2;
layers[1][3].slant = slant / 5;
layers[0][3].slant = -slant / 3;
layers[1][7].slant = slant / 4;
layers[0][7].slant = slant / 2;
for (j = 0 ; j < 3 ; j++)
{
poses[j].x = x;
poses[j].y = y;
poses[j].count = 10;
}
for (j = 0 ; j < 10 ; j++)
{
poses[0].layers[j] = layers[0][j];
poses[1].layers[j] = layers[1][j];
poses[2].layers[j] = layers[0][j];
}
movement.count = 3;
movement.poses = poses;
mimimi_movement(videos->standing + i, model, &movement);
}
for (i = 0 ; i < 7 ; i++) pose.layers[i] = layer0;
pose.layers[0].z_angle = coefficient;
pose.layers[0].y_angle = 64 + 32 * coefficient;
pose.layers[4].slant = 96 * coefficient;
pose.layers[5].slant = 96 * coefficient;
pose.layers[2].z_angle = coefficient;
pose.layers[2].slant = -96;
pose.layers[3].z_angle = coefficient;
pose.layers[3].slant = 96;
pose.x = x - 12 * coefficient;
pose.y = y - 12;
pose.count = 7;
movement.count = 1;
movement.poses = &pose;
mimimi_movement(videos->falling, model, &movement);
pose.layers[0] = layer0;
pose.layers[0].slant = 0;
pose.layers[0].z_angle = coefficient;
pose.layers[0].y_angle = 64 + 32 * coefficient;
pose.x = x - 12 * coefficient;
pose.y = y - 20;
pose.count = 1;
movement.count = 1;
movement.poses = &pose;
mimimi_movement(videos->knocked, model, &movement);
video_count = videos->jumping_video_count;
for (i = 0 ; i < video_count ; i++)
{
for (j = 0 ; j < 6 ; j++)
{
poses[0].layers[j] = layer0;
poses[1].layers[j] = layer0;
}
slant = 64 * i / videos->jumping[i].count * coefficient;
y_angle = 64 + (20 + 20 * i / videos->jumping[i].count) * coefficient;
poses[0].x = x;
poses[0].y = y;
poses[0].count = 6;
poses[0].layers[0].y_angle = y_angle;
poses[0].layers[0].slant = -slant * 2;
poses[0].layers[1].slant = slant * 2;
poses[0].layers[4].slant = -slant / 2;
poses[0].layers[5].slant = -slant / 2;
poses[1].x = x;
poses[1].y = y;
poses[1].count = 6;
poses[1].layers[0].y_angle = y_angle;
poses[1].layers[2].slant = -slant * 2;
poses[1].layers[3].slant = -slant * 2;
poses[1].layers[4].slant = slant * 2;
poses[1].layers[5].slant = slant * 2;
movement.count = 2;
movement.poses = poses;
mimimi_movement(videos->jumping + i, model, &movement);
}
}
void mimimi_appearance(struct mimimi_appearance *appearance, struct mimimi_model *model, int x, int y)
{
mimimi_appearance_videos(&appearance->left, model, x, y, 1);
mimimi_appearance_videos(&appearance->right, model, x, y, -1);
}