This repository has been archived on 2025-02-04. You can view files and clone it, but cannot push or open issues or pull requests.
helpless/oogabooga/examples/sprite_animation.c
2024-08-23 18:13:02 +02:00

95 lines
No EOL
4.3 KiB
C

int entry(int argc, char **argv) {
window.title = STR("Sprite animation example");
Gfx_Image *anim_sheet = load_image_from_disk(STR("oogabooga/examples/male_animation.png"), get_heap_allocator());
assert(anim_sheet, "Could not open oogabooga/examples/male_animation.png");
// Configure information about the whole image as a sprite sheet
u32 number_of_columns = 10;
u32 number_of_rows = 6;
u32 total_number_of_frames = number_of_rows * number_of_columns;
u32 anim_frame_width = anim_sheet->width / number_of_columns;
u32 anim_frame_height = anim_sheet->height / number_of_rows;
// Configure the animation by setting the start & end frames in the grid of frames
// (Inspect sheet image and count the frame indices you want)
// In sprite sheet animations, it usually goes down. So Y 0 is actuall the top of the
// sprite sheet, and +Y is down on the sprite sheet.
u32 anim_start_frame_x = 2;
u32 anim_start_frame_y = 1;
u32 anim_end_frame_x = 6;
u32 anim_end_frame_y = 2;
u32 anim_start_index = anim_start_frame_y * number_of_columns + anim_start_frame_x;
u32 anim_end_index = anim_end_frame_y * number_of_columns + anim_end_frame_x;
u32 anim_number_of_frames = max(anim_end_index, anim_start_index)-min(anim_end_index, anim_start_index)+1;
// Sanity check configuration
assert(anim_end_index > anim_start_index, "The last frame must come before the first frame");
assert(anim_start_frame_x < number_of_columns, "anim_start_frame_x is out of bounds");
assert(anim_start_frame_y < number_of_rows, "anim_start_frame_y is out of bounds");
assert(anim_end_frame_x < number_of_columns, "anim_end_frame_x is out of bounds");
assert(anim_end_frame_y < number_of_rows, "anim_end_frame_y is out of bounds");
// Calculate duration per frame in seconds
float32 playback_fps = 4;
float32 anim_time_per_frame = 1.0 / playback_fps;
float32 anim_duration = anim_time_per_frame * (float32)anim_number_of_frames;
float32 anim_start_time = os_get_elapsed_seconds();
float64 last_time = os_get_elapsed_seconds();
while (!window.should_close) {
reset_temporary_storage();
float64 now = os_get_elapsed_seconds();
float64 delta = now-last_time;
last_time = now;
draw_frame.projection = m4_make_orthographic_projection(window.pixel_width * -0.5, window.pixel_width * 0.5, window.pixel_height * -0.5, window.pixel_height * 0.5, -1, 10);
// Float modulus to "loop" around the timer over the anim duration
float32 anim_elapsed = fmodf(now - anim_start_time, anim_duration);
// Get current progression in animation from 0.0 to 1.0
float32 anim_progression_factor = anim_elapsed / anim_duration;
u32 anim_current_index = anim_number_of_frames * anim_progression_factor;
u32 anim_absolute_index_in_sheet = anim_start_index + anim_current_index;
u32 anim_index_x = anim_absolute_index_in_sheet % number_of_columns;
u32 anim_index_y = anim_absolute_index_in_sheet / number_of_columns + 1;
u32 anim_sheet_pos_x = anim_index_x * anim_frame_width;
u32 anim_sheet_pos_y = (number_of_rows - anim_index_y) * anim_frame_height; // Remember, Y inverted.
// Draw the sprite sheet, with the uv box for the current frame.
// Uv box is a Vector4 of x1, y1, x2, y2 where each value is a percentage value 0.0 to 1.0
// from left to right / bottom to top in the texture.
Draw_Quad *quad = draw_image(anim_sheet, v2(0, 0), v2(anim_frame_width*4, anim_frame_height*4), COLOR_WHITE);
quad->uv.x1 = (float32)(anim_sheet_pos_x)/(float32)anim_sheet->width;
quad->uv.y1 = (float32)(anim_sheet_pos_y)/(float32)anim_sheet->height;
quad->uv.x2 = (float32)(anim_sheet_pos_x+anim_frame_width) /(float32)anim_sheet->width;
quad->uv.y2 = (float32)(anim_sheet_pos_y+anim_frame_height)/(float32)anim_sheet->height;
// Visualize sprite sheet animation
Vector2 sheet_pos = v2(-window.width/2+40, -window.height/2+40);
Vector2 sheet_size = v2(anim_sheet->width, anim_sheet->height);
Vector2 frame_pos_in_sheet = v2(anim_sheet_pos_x, anim_sheet_pos_y);
Vector2 frame_size = v2(anim_frame_width, anim_frame_height);
draw_rect(sheet_pos, sheet_size, COLOR_BLACK); // Draw black background
draw_rect(v2_add(sheet_pos, frame_pos_in_sheet), frame_size, COLOR_WHITE); // Draw white rect on current frame
draw_image(anim_sheet, sheet_pos, sheet_size, COLOR_WHITE); // Draw the seet
os_update();
gfx_update();
}
return 0;
}