Mirai's Miscellaneous Misadventures
M22 / core / animations.c
#include <mimimi/models.h>
#include <mimimi/appearances.h>
#include <mimimi/allocators.h>
#include <mimimi/animations.h>
#include <mimimi/assets.h>
#include <mimimi/poses.h>
#include "math.c"
static unsigned char mimimi_rotating_image_pixel(struct mimimi_rotating_image *rotating_image, unsigned char slant, int x, int y)
{
y += rotating_image->oy;
int h = rotating_image->count;
if (y < 0) return 0;
if (y >= h) return 0;
int w = rotating_image->rows[y].size;
if (x < -w / 2) return 0;
if (x >= w / 2) return 0;
x += w / 2;
int count = rotating_image->rows[y].count;
int a = slant;
a *= count;
a += 128;
a /= 256;
a += x;
a %= count;
return rotating_image->rows[y].colors[a];
}
static 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)
{
int width = image->width;
int height = image->height;
unsigned char y_angle = layer->y_angle;
unsigned char z_angle = layer->z_angle;
unsigned char slant = layer->slant;
z_angle %= 4;
x0 += rotating_image->oz * mimimi_cosine[y_angle] / 256;
if (behind != 0) y_angle += 128;
for (int y = 0 ; y < height ; y++)
for (int x = 0 ; x < width ; x++)
{
if (behind != 0 && image->colors[x + y * width] != 0) continue;
int x1 = x - x0;
int y1 = y - y0;
if (z_angle == 1)
{
int x0 = x1;
x1 = -y1;
y1 = x0;
}
if (z_angle == 2)
{
x1 = -x1;
y1 = -y1;
}
if (z_angle == 3)
{
int x0 = x1;
x1 = y1;
y1 = -x0;
}
int x2 = x1 + y1 * mimimi_sine[slant] / 128;
if (behind != 0) x2 = -x2 - 1;
unsigned char color = mimimi_rotating_image_pixel(rotating_image, y_angle, x2, y1);
if (color == 0) continue;
image->colors[x + y * width] = color;
}
}
static 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)
{
z_angle %= 4;
if (z_angle == 1)
{
int x = x0;
x0 = y0 + image->width/2 - image->height;
y0 = image->width/2 + image->height - x;
}
if (z_angle == 2)
{
x0 = image->width - x0;
y0 = image->height * 2 - y0;
}
if (z_angle == 3)
{
int x = x0;
x0 = image->width/2 + image->height - y0;
y0 = x - image->width/2 + image->height;
}
for (int i = 0 ; i < layer->count ; i++)
mimimi_rotating_image_stamp(image, layer->images[i], x0, y0, pose_layer, 0),
mimimi_rotating_image_stamp(image, layer->images[i], x0, y0, pose_layer, 1);
}
static void mimimi_join_pose_layer(struct mimimi_pose_layer *a, struct mimimi_pose_layer *b)
{
a->slant += b->slant;
a->y_angle += b->y_angle;
a->z_angle += b->z_angle;
}
void mimimi_pose(struct mimimi_image *image, struct mimimi_model *model, struct mimimi_pose *pose)
{
struct mimimi_pose_layer *torso = &pose->torso;
struct mimimi_pose_layer head = pose->head;
struct mimimi_pose_layer left_arm = pose->left_arm;
struct mimimi_pose_layer right_arm = pose->right_arm;
struct mimimi_pose_layer left_leg = pose->left_leg;
struct mimimi_pose_layer right_leg = pose->right_leg;
mimimi_join_pose_layer(&head, torso);
mimimi_join_pose_layer(&left_arm, torso);
mimimi_join_pose_layer(&right_arm, torso);
mimimi_join_pose_layer(&left_leg, torso);
mimimi_join_pose_layer(&right_leg, torso);
for (int y = 0 ; y < image->height ; y++)
for (int x = 0 ; x < image->width ; x++)
image->colors[x + y * image->width] = 0;
int x = pose->x + image->width / 2;
int y = pose->y + image->height;
unsigned char slant = torso->slant;
unsigned char y_angle = torso->y_angle;
int leg_y = y - 12;
int leg_x = x + mimimi_sine[slant] * (image->height - leg_y) / 128;
int left_leg_x = leg_x + 6 * mimimi_sine[y_angle] / 256;
int right_leg_x = leg_x - 6 * mimimi_sine[y_angle] / 256;
int torso_y = y - 12;
int torso_x = x + mimimi_sine[slant] * (image->height - torso_y) / 128;
int arm_y = y - 20;
int arm_x = x + mimimi_sine[slant] * (image->height - arm_y) / 128;
int left_arm_x = arm_x + 10 * mimimi_sine[y_angle] / 256;
int right_arm_x = arm_x - 10 * mimimi_sine[y_angle] / 256;
int head_y = y - 23;
int head_x = x + mimimi_sine[slant] * (image->height - head_y) / 128;
int z_angle = torso->z_angle;
unsigned char y_angle2 = y_angle + 64;
if (y_angle2 < 128 + 8 && y_angle2 > 128 - 8)
{
mimimi_animation_layer(image, model->left_leg, left_leg_x, leg_y, &left_leg, z_angle);
mimimi_animation_layer(image, model->right_leg, right_leg_x, leg_y, &right_leg, z_angle);
mimimi_animation_layer(image, model->left_arm, left_arm_x, arm_y, &left_arm, z_angle);
mimimi_animation_layer(image, model->right_arm, right_arm_x, arm_y, &right_arm, z_angle);
mimimi_animation_layer(image, model->torso, torso_x, torso_y, torso, z_angle);
}
else if (y_angle2 < 128)
{
mimimi_animation_layer(image, model->left_leg, left_leg_x, leg_y, &left_leg, z_angle);
mimimi_animation_layer(image, model->right_leg, right_leg_x, leg_y, &right_leg, z_angle);
mimimi_animation_layer(image, model->left_arm, left_arm_x, arm_y, &left_arm, z_angle);
mimimi_animation_layer(image, model->torso, torso_x, torso_y, torso, z_angle);
mimimi_animation_layer(image, model->right_arm, right_arm_x, arm_y, &right_arm, z_angle);
}
else
{
mimimi_animation_layer(image, model->right_leg, right_leg_x, leg_y, &right_leg, z_angle);
mimimi_animation_layer(image, model->left_leg, left_leg_x, leg_y, &left_leg, z_angle);
mimimi_animation_layer(image, model->right_arm, right_arm_x, arm_y, &right_arm, z_angle);
mimimi_animation_layer(image, model->torso, torso_x, torso_y, torso, z_angle);
mimimi_animation_layer(image, model->left_arm, left_arm_x, arm_y, &left_arm, z_angle);
}
mimimi_animation_layer(image, model->head, head_x, head_y, &head, z_angle);
}
static void mimimi_interpolate_pose_layer(struct mimimi_pose_layer *a, struct mimimi_pose_layer *b, int i, int count)
{
int slant = a->slant * (count - i) / count;
slant += mimimi_div(b->slant * i, count);
int y_angle = a->y_angle * (count - i) / count;
y_angle += mimimi_div(b->y_angle * i, count);
int 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)
{
if (count == 0) return;
int x = a->x * (count - i) / count;
x += mimimi_div(b->x * i, count);
int y = a->y * (count - i) / count;
y += mimimi_div(b->y * i, count);
a->x = x;
a->y = y;
mimimi_interpolate_pose_layer(&a->torso, &b->torso, i, count);
mimimi_interpolate_pose_layer(&a->head, &b->head, i, count);
mimimi_interpolate_pose_layer(&a->left_arm, &b->left_arm, i, count);
mimimi_interpolate_pose_layer(&a->right_arm, &b->right_arm, i, count);
mimimi_interpolate_pose_layer(&a->left_leg, &b->left_leg, i, count);
mimimi_interpolate_pose_layer(&a->right_leg, &b->right_leg, i, count);
}
void mimimi_movement(struct mimimi_animation *animation, struct mimimi_model *model, struct mimimi_movement *movement)
{
if (movement->pose_count == 1)
{
for (int i = 0 ; i < animation->image_count ; i++)
mimimi_pose(animation->images + i, model, movement->poses);
return;
}
for (int i = 0 ; i < animation->image_count ; i++)
{
int j = i * (movement->pose_count - 1) / animation->image_count;
int k = i - j * animation->image_count / (movement->pose_count - 1);
struct mimimi_pose pose = movement->poses[j];
mimimi_interpolate_pose(&pose, movement->poses + j + 1, k, animation->image_count / (movement->pose_count - 1));
mimimi_pose(animation->images + i, model, &pose);
}
}
static void mimimi_appearance_animations(struct mimimi_animation_set *animations, struct mimimi_model *model, int coefficient)
{
int count = animations->standing_animation_count;
for (int i = 0 ; i < count ; i++)
{
struct mimimi_pose poses[3] = {};
struct mimimi_movement movement = {3, poses};
unsigned char slant = -8 * i / count * coefficient;
unsigned char y_angle = 64 + (12 + 24 * i / count) * coefficient;
unsigned char arm_slant = 16 * i / count;
poses[0].torso.slant = slant;
poses[0].torso.y_angle = y_angle;
poses[0].left_arm.slant = -arm_slant;
poses[0].right_arm.slant = arm_slant;
poses[0].left_leg.slant = arm_slant;
poses[0].right_leg.slant = -arm_slant;
poses[0].head.slant = -slant;
poses[1].torso.slant = slant;
poses[1].torso.y_angle = y_angle;
poses[1].left_arm.slant = arm_slant;
poses[1].right_arm.slant = -arm_slant;
poses[1].left_leg.slant = -arm_slant;
poses[1].right_leg.slant = arm_slant;
poses[1].head.slant = -slant;
poses[2] = poses[0];
mimimi_movement(animations->standing + i, model, &movement);
struct mimimi_pose falling_poses[1] = {};
struct mimimi_movement falling_movement = {1, falling_poses};
falling_poses[0].torso.z_angle = -coefficient;
falling_poses[0].torso.y_angle = 64 + 32 * coefficient;
falling_poses[0].left_arm.z_angle = -coefficient;
falling_poses[0].right_arm.z_angle = -coefficient;
falling_poses[0].left_leg.slant = -12 * coefficient;
falling_poses[0].right_leg.slant = -12 * coefficient;
falling_poses[0].left_arm.slant = 12 * coefficient;
falling_poses[0].right_arm.slant = -12 * coefficient;
falling_poses[0].x = -10 * coefficient;
falling_poses[0].y = 16;
mimimi_movement(animations->falling, model, &falling_movement);
struct mimimi_pose knocked_poses[1] = {};
struct mimimi_movement knocked_movement = {1, knocked_poses};
knocked_poses[0].torso.z_angle = -coefficient;
knocked_poses[0].torso.y_angle = 64 + 32 * coefficient;
knocked_poses[0].x = -20 * coefficient;
knocked_poses[0].y = 16;
mimimi_movement(animations->knocked, model, &knocked_movement);
}
}
void mimimi_appearance(struct mimimi_appearance *appearance, struct mimimi_model *model)
{
mimimi_appearance_animations(&appearance->left, model, 1);
mimimi_appearance_animations(&appearance->right, model, -1);
}