95 lines
No EOL
4.3 KiB
C
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;
|
|
} |