Mirai's Miscellaneous Misadventures
M17 / core / appearances.c
#include <mimimi/models.h>
#include <mimimi/appearances.h>
#include "appearances.h"
#include "math.c"
int mimimi_sprite_appearance_size = sizeof (struct mimimi_sprite_appearance);
static unsigned char mimimi_rotating_image_pixel(struct mimimi_rotating_image *rotating_image, unsigned char angle, 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 = angle;
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, unsigned char y_angle, unsigned char z_angle, int x0, int y0, int behind)
{
int width = image->width;
int height = image->height;
x0 += rotating_image->oz * mimimi_cosine[y_angle] / 256;
if (behind != 0) y_angle += 128;
for (int x = 0 ; x < width ; x++)
for (int y = 0 ; y < height ; y++)
{
if (behind != 0 && image->colors[x + y * width] != 0) continue;
int x1 = x - x0;
int y1 = y - y0;
int x2 = x1 + y1 * mimimi_sine[z_angle] / 127;
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, unsigned char y_angle, unsigned char z_angle, int x0, int y0)
{
for (int i = 0 ; i < layer->count ; i++)
{
mimimi_rotating_image_stamp(image, layer->images[i], y_angle, z_angle, x0, y0, 0);
mimimi_rotating_image_stamp(image, layer->images[i], y_angle, z_angle, x0, y0, 1);
}
}
static 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)
{
struct mimimi_image *image = &sprite_image->image;
image->colors = sprite_image->colors;
image->width = 26;
image->height = 36;
for (int x = 0 ; x < image->width ; x++)
for (int y = 0 ; y < image->height ; y++)
image->colors[x + y * image->width] = 0;
int x = image->width / 2;
int head_y = 13;
int head_x = x + mimimi_sine[z_angle] * (image->height - head_y) / 127;
int arm_y = 16;
int arm_x = x + mimimi_sine[z_angle] * (image->height - arm_y) / 127;
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 leg_y = 24;
int leg_x = x + mimimi_sine[z_angle] * (image->height - leg_y) / 127;
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 = 24;
int torso_x = x + mimimi_sine[z_angle] * (image->height - torso_y) / 127;
mimimi_animation_layer(image, model->left_leg, y_angle, -arm_angle, left_leg_x, leg_y);
mimimi_animation_layer(image, model->right_leg, y_angle, arm_angle, right_leg_x, leg_y);
if ((y_angle + 64) % 256 < 128)
{
mimimi_animation_layer(image, model->left_arm, y_angle, arm_angle, left_arm_x, arm_y);
mimimi_animation_layer(image, model->torso, y_angle, z_angle, torso_x, torso_y);
mimimi_animation_layer(image, model->right_arm, y_angle, -arm_angle, right_arm_x, arm_y);
}
else
{
mimimi_animation_layer(image, model->right_arm, y_angle, -arm_angle, right_arm_x, arm_y);
mimimi_animation_layer(image, model->torso, y_angle, z_angle, torso_x, torso_y);
mimimi_animation_layer(image, model->left_arm, y_angle, arm_angle, left_arm_x, arm_y);
}
mimimi_animation_layer(image, model->head, y_angle, 0, head_x, head_y);
}
static void mimimi_animation(struct mimimi_animation *animation, struct mimimi_model *model, unsigned char y_angle, unsigned char z_angle, unsigned char arm_angle)
{
int count = mimimi_image_count;
for (int i = 0 ; i < count ; i++)
mimimi_animation_frame(animation->images + i, model, y_angle, z_angle, arm_angle * mimimi_sine[i * 255 / count] / 127);
}
static void mimimi_animation_set(struct mimimi_animation *animations, struct mimimi_model *model, int coefficient, unsigned char z_angle, unsigned char arm_angle)
{
int count = mimimi_animation_count;
for (int i = 0 ; i < count ; i++)
mimimi_animation(animations + i, model, 64 + (12 + 34 * i / count) * coefficient, -z_angle * i / count * coefficient, arm_angle * i / count);
}
static void mimimi_transpose_image(struct mimimi_image *image)
{
int width = image->width;
int height = image->height;
image->width = height;
image->height = width;
for (int start = 0 ; start < width * height ; start++)
{
int next = start;
int i = 0;
for (;;)
{
i++;
next = (next % height) * width + next / height;
if (next <= start) break;
}
if (i == 1) continue;
if (next < start) continue;
char tmp = image->colors[next = start];
for (;;)
{
int i = (next % height) * width + next / height;
image->colors[next] = (i == start) ? tmp : image->colors[i];
next = i;
if (next <= start) break;
}
}
}
static void mimimi_flip_image(struct mimimi_image *image)
{
for (int x = 0 ; x < image->width / 2 ; x++)
for (int y = 0 ; y < image->height ; y++)
{
unsigned char color = image->colors[image->width - x - 1 + y * image->width];
image->colors[image->width - x - 1 + y * image->width] = image->colors[x + y * image->width];
image->colors[x + y * image->width] = color;
}
}
static void mimimi_rotate_image_cw(struct mimimi_image *image)
{
mimimi_transpose_image(image);
mimimi_flip_image(image);
}
static void mimimi_rotate_image_ccw(struct mimimi_image *image)
{
mimimi_flip_image(image);
mimimi_transpose_image(image);
}
void mimimi_sprite_appearance(struct mimimi_sprite_appearance *appearance, struct mimimi_model *model)
{
unsigned char z_angle = 9;
unsigned char arm_angle = 16;
unsigned char arm_flail_angle = 32;
mimimi_animation_set(appearance->left.standing, model, 1, z_angle, arm_angle);
mimimi_animation_set(appearance->right.standing, model, -1, z_angle, arm_angle);
mimimi_animation(&appearance->left.knocked, model, 64 + 16, 0, arm_flail_angle);
mimimi_animation(&appearance->right.knocked, model, 64 - 16, 0, arm_flail_angle);
for (int i = 0 ; i < mimimi_image_count ; i++)
{
mimimi_rotate_image_cw(&appearance->left.knocked.images[i].image);
mimimi_rotate_image_ccw(&appearance->right.knocked.images[i].image);
}
}
static struct mimimi_sprite_appearance mimimi_empty_appearance_value = {};
struct mimimi_sprite_appearance *mimimi_empty_appearance = &mimimi_empty_appearance_value;