From ed9841c1b1a892112038a9d60d0074a1ce9acc88 Mon Sep 17 00:00:00 2001 From: jacob Date: Wed, 6 Mar 2024 19:26:00 -0600 Subject: [PATCH] sprite tag / animating logic touchup --- res/graphics/tim.ase | 4 +-- src/ase.c | 1 + src/ase.h | 1 + src/entity.c | 15 -------- src/entity.h | 21 +++-------- src/game.c | 64 +++++++++++++++++++-------------- src/math.h | 9 +++++ src/sheet.c | 1 + src/sheet.h | 1 + src/user.c | 84 +++++++++++++++++++++++++++++++------------- 10 files changed, 117 insertions(+), 84 deletions(-) diff --git a/res/graphics/tim.ase b/res/graphics/tim.ase index 1835dcfb..e767efc9 100644 --- a/res/graphics/tim.ase +++ b/res/graphics/tim.ase @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3df0d8172cdcef00d61763c19c6bc3bfe5d9cb2ef6d0e9b9324d9908a3af57df -size 985 +oid sha256:424a19cf31766609c2e6daa5875990cfeb796c0d2206f0f089424899c5412d51 +size 3606 diff --git a/src/ase.c b/src/ase.c index 1073bbb1..2f0134cd 100644 --- a/src/ase.c +++ b/src/ase.c @@ -910,6 +910,7 @@ struct ase_decode_sheet_result ase_decode_sheet(struct arena *arena, struct buff scratch_end(scratch); res.image_size = V2(image_width, image_height); + res.frame_size = V2(frame_width, frame_height); res.num_frames = num_frames; res.num_tags = num_tags; res.frame_head = frame_head; diff --git a/src/ase.h b/src/ase.h index 1fbfc6ec..a59e59e8 100644 --- a/src/ase.h +++ b/src/ase.h @@ -23,6 +23,7 @@ struct ase_decode_image_result { struct ase_decode_sheet_result { struct v2 image_size; + struct v2 frame_size; u32 num_frames; u32 num_tags; struct ase_frame *frame_head; diff --git a/src/entity.c b/src/entity.c index 0f94a948..87cd72c9 100644 --- a/src/entity.c +++ b/src/entity.c @@ -26,18 +26,3 @@ b32 entity_has_prop(struct entity *entity, enum entity_prop prop) u64 bit = prop % 64; return !!(entity->props[index] & ((u64)1 << bit)); } - -/* ========================== * - * Animation - * ========================== */ - -/* TODO: Move this to game */ - -void entity_start_animation(struct entity *entity, struct string animation_name, u64 flags) -{ - entity_enable_prop(entity, ENTITY_PROP_SPRITE_ANIMATED); - entity->animation_name = animation_name; - entity->animation_flags = flags; - entity->animation_time_in_frame = 0; - ++entity->animation_start_gen; -} diff --git a/src/entity.h b/src/entity.h index 4ec14a86..7fa8556e 100644 --- a/src/entity.h +++ b/src/entity.h @@ -16,7 +16,7 @@ struct entity_handle { enum entity_prop { ENTITY_PROP_NONE, - ENTITY_PROP_SPRITE_ANIMATED, + ENTITY_PROP_ANIMATING, ENTITY_PROP_PLAYER_CONTROLLED, ENTITY_PROP_CAMERA, @@ -48,7 +48,6 @@ struct entity { /* Translation, rotation, scale in relation to parent entity */ struct trs rel_trs; - struct mat3x3 world_xform; /* Calculated post-physics */ /* ====================================================================== */ @@ -65,6 +64,7 @@ struct entity { /* Sprite */ struct string sprite_name; + struct string sprite_tag_name; struct trs sprite_trs; struct v2 sprite_pivot_norm; /* Pivot x & y are each normalized about sprite dimensions. <0, 0> is center, <1, 1> is bottom right corner, etc. */ u32 sprite_tint; @@ -72,13 +72,9 @@ struct entity { /* ====================================================================== */ /* Animation */ - /* ENTITY_PROP_SPRITE_ANIMATED */ - struct string animation_name; - u64 animation_flags; - f64 animation_time_in_frame; - u64 animation_start_gen; - u64 animation_gen; - struct sheet_frame animation_frame; + /* ENTITY_PROP_ANIMATING */ + b32 animation_looping; + f64 animation_start_time; /* Calculated */ /* ====================================================================== */ /* Testing */ @@ -117,11 +113,4 @@ void entity_enable_prop(struct entity *entity, enum entity_prop prop); void entity_disable_prop(struct entity *entity, enum entity_prop prop); b32 entity_has_prop(struct entity *entity, enum entity_prop prop); -/* Animation */ - -#define ANIMATION_FLAG_NONE 0x0 -#define ANIMATION_FLAG_LOOPING 0x1 - -void entity_start_animation(struct entity *entity, struct string animation_name, u64 flags); - #endif diff --git a/src/game.c b/src/game.c index 35c720a6..84b020b4 100644 --- a/src/game.c +++ b/src/game.c @@ -167,10 +167,11 @@ INTERNAL void game_update(void) { struct string sprite_name = STR("res/graphics/tim.ase"); + struct string sprite_tag_name = STR("UNARMED"); struct sheet *sheet = sheet_load(sprite_name); - f32 meters_width = sheet->image_size.x / PIXELS_PER_UNIT; - f32 meters_height = sheet->image_size.y / PIXELS_PER_UNIT; + f32 meters_width = sheet->frame_size.x / PIXELS_PER_UNIT; + f32 meters_height = sheet->frame_size.y / PIXELS_PER_UNIT; struct v2 sprite_size = V2(meters_width, meters_height); struct v2 pos = V2(0, 0); @@ -181,6 +182,7 @@ INTERNAL void game_update(void) e->rel_trs = TRS(.t = pos, .r = 0, .s = V2(1, 1)); e->sprite_name = sprite_name; + e->sprite_tag_name = sprite_tag_name; e->sprite_trs = TRS(.s = sprite_size); e->sprite_pivot_norm = V2(0, 0.65); //e->sprite_pivot_norm = V2(0.4, 0.65); @@ -190,6 +192,9 @@ INTERNAL void game_update(void) e->player_max_speed = 5.f; e->player_acceleration = 15.0f; + entity_enable_prop(e, ENTITY_PROP_ANIMATING); + e->animation_looping = true; + player_ent = e; //entity_enable_prop(e, ENTITY_PROP_TEST); @@ -205,7 +210,7 @@ INTERNAL void game_update(void) entity_enable_prop(e, ENTITY_PROP_CAMERA); e->camera_active = true; e->camera_follow = player_ent->handle; - e->camera_zoom = 1; + e->camera_zoom = 1.5; } } @@ -260,39 +265,46 @@ INTERNAL void game_update(void) ent->test_start_sprite_trs = ent->sprite_trs; } + /* ENTITY_PROP_ANIMATING */ + if (entity_has_prop(ent, ENTITY_PROP_ANIMATING) && ent->animation_start_time == 0) { + ent->animation_start_time = L.tick.time; + } + /* ========================== * * Update animation * ========================== */ - if (entity_has_prop(ent, ENTITY_PROP_SPRITE_ANIMATED)) { - struct sheet *sheet = sheet_load(ent->sprite_name); - struct sheet_tag tag = sheet_get_tag(sheet, ent->animation_name); + if (ent->animation_start_time > 0) { + /* Stop animation if past duration and not looping */ + if (!ent->animation_looping) { + f64 time_in_anim = L.tick.time - ent->animation_start_time; - if (ent->animation_start_gen == ent->animation_gen) { - ent->animation_time_in_frame += L.tick.dt; - } else { - ent->animation_frame = sheet_get_frame(sheet, tag.start); - ent->animation_start_gen = ent->animation_gen; - } + struct sheet *sheet = sheet_load(ent->sprite_name); + if (sheet) { + struct sheet_tag tag = sheet_get_tag(sheet, ent->sprite_tag_name); - while (ent->animation_frame.duration != 0 && ent->animation_time_in_frame > ent->animation_frame.duration) { - u64 new_frame_index = ent->animation_frame.index + 1; - if (new_frame_index > tag.end) { - if (ent->animation_flags & ANIMATION_FLAG_LOOPING) { - /* Restart animation */ - new_frame_index = tag.start; - } else { - /* End animation */ - entity_start_animation(ent, STR("Default"), ANIMATION_FLAG_LOOPING); - goto break_animation; + struct sheet_frame frame = { 0 }; + u64 frame_index = tag.start; + while (time_in_anim > 0) { + frame = sheet_get_frame(sheet, frame_index); + if (frame_index > tag.end) { + entity_disable_prop(ent, ENTITY_PROP_ANIMATING); + ent->animation_start_time = 0; + break; + } + time_in_anim -= frame.duration; + ++frame_index; } + } else { + entity_disable_prop(ent, ENTITY_PROP_ANIMATING); + ent->animation_start_time = 0; } - ent->animation_frame = sheet_get_frame(sheet, new_frame_index); - ent->animation_time_in_frame -= ent->animation_frame.duration; } } -break_animation: - (UNUSED)0; /* Disable label at end of compound statement warning */ + + /* ========================== * + * Test + * ========================== */ /* ENTITY_PROP_TEST */ if (entity_has_prop(ent, ENTITY_PROP_TEST)) { diff --git a/src/math.h b/src/math.h index f754737f..eb72fd94 100644 --- a/src/math.h +++ b/src/math.h @@ -331,6 +331,15 @@ INLINE struct v2 v2_norm(struct v2 a) return a; } + +INLINE struct v2 v2_round(struct v2 a) +{ + return V2( + (f32)math_round_f32(a.x), + (f32)math_round_f32(a.y) + ); +} + INLINE f32 v2_dot(struct v2 a, struct v2 b) { return a.x * b.x + a.y * b.y; diff --git a/src/sheet.c b/src/sheet.c index 11313ab0..10824452 100644 --- a/src/sheet.c +++ b/src/sheet.c @@ -83,6 +83,7 @@ INTERNAL struct sheet sheet_from_ase(struct arena *arena, struct ase_decode_shee /* Init frames */ sheet.image_size = ase.image_size; + sheet.frame_size = ase.frame_size; sheet.frames = arena_push_array_zero(arena, struct sheet_frame, ase.num_frames); sheet.frames_count = ase.num_frames; for (struct ase_frame *ase_frame = ase.frame_head; ase_frame; ase_frame = ase_frame->next) { diff --git a/src/sheet.h b/src/sheet.h index c49cafcd..0c755a5b 100644 --- a/src/sheet.h +++ b/src/sheet.h @@ -8,6 +8,7 @@ struct sheet_frame; struct sheet { struct v2 image_size; + struct v2 frame_size; u32 frames_count; struct sheet_frame *frames; u32 tags_count; diff --git a/src/user.c b/src/user.c index c1c299c0..1f6e6a1e 100644 --- a/src/user.c +++ b/src/user.c @@ -226,7 +226,13 @@ INTERNAL struct mat3x3 view_get_xform(struct view view) return res; } -INTERNAL struct v2 view_inverse_point(struct view view, struct v2 p) +INTERNAL struct v2 view_xform_point(struct view view, struct v2 p) +{ + struct mat3x3 mtx = view_get_xform(view); + return mat3x3_mul_v2(mtx, p); +} + +INTERNAL struct v2 view_inverse_xform_point(struct view view, struct v2 p) { struct mat3x3 mtx_inverse = mat3x3_inverse(view_get_xform(view)); return mat3x3_mul_v2(mtx_inverse, p); @@ -234,7 +240,7 @@ INTERNAL struct v2 view_inverse_point(struct view view, struct v2 p) INTERNAL struct v2 view_mouse_pos(struct view view) { - return view_inverse_point(view, L.screen_mouse); + return view_inverse_xform_point(view, L.screen_mouse); } /* ========================== * @@ -606,11 +612,33 @@ INTERNAL void user_update(void) if (texture) { u32 tint = ent->sprite_tint; struct draw_texture_params params = DRAW_TEXTURE_PARAMS(.texture = texture, .tint = tint); - if (entity_has_prop(ent, ENTITY_PROP_SPRITE_ANIMATED)) { - struct sheet_frame frame = ent->animation_frame; + + struct sheet *sheet = sheet_load(ent->sprite_name); + if (sheet) { + struct sheet_tag tag = sheet_get_tag(sheet, ent->sprite_tag_name); + + struct sheet_frame frame = sheet_get_frame(sheet, tag.start); + if (entity_has_prop(ent, ENTITY_PROP_ANIMATING)) { + b32 looping = ent->animation_looping; + f64 time_in_anim = tick->time - ent->animation_start_time; + + u64 frame_index = tag.start; + while (time_in_anim > 0) { + frame = sheet_get_frame(sheet, frame_index); + time_in_anim -= frame.duration; + ++frame_index; + if (frame_index > tag.end) { + frame_index = tag.start; + if (!looping) { + break; + } + } + } + } + params.clip = frame.clip; - params = DRAW_TEXTURE_PARAMS(.texture = texture, .clip = frame.clip); } + draw_texture_quad(L.world_canvas, params, quad); } @@ -645,22 +673,18 @@ INTERNAL void user_update(void) /* Debug draw info */ if (L.debug_draw && !is_camera) { - struct mat3x3 mtx = ent->world_xform; - struct trs trs = trs_from_mat3x3(mtx); - struct v2 velocity = ent->velocity; - struct v2 acceleration = ent->acceleration; - struct font *disp_font = font_load_async(STR("res/fonts/fixedsys.ttf"), 12.0f); - - //f32 offset = 0.75; - //struct v2 dir = v2_mul(mat3x3_get_up(mtx), 0.5f); - //dir = v2_add(dir, v2_mul(v2_norm(dir), offset)); - //struct v2 pos = v2_add(mat3x3_get_pos(mtx), dir); - - f32 offset = 1.5; - struct v2 pos = v2_add(mat3x3_get_pos(mtx), v2_mul(V2(0, -1), offset)); - if (disp_font) { + struct mat3x3 mtx = ent->world_xform; + struct trs trs = trs_from_mat3x3(mtx); + struct v2 velocity = ent->velocity; + struct v2 acceleration = ent->acceleration; + + f32 offset = 1; + struct v2 pos = v2_add(mat3x3_get_pos(mtx), v2_mul(V2(0, -1), offset)); + pos = view_xform_point(L.world_view, pos); + pos = v2_round(pos); + struct string disp_name = ent->sprite_name; struct string fmt = STR( @@ -681,7 +705,7 @@ INTERNAL void user_update(void) ); - draw_text_ex(L.world_canvas, disp_font, pos, 1.0f / PIXELS_PER_UNIT, text); + draw_text(L.ui_canvas, disp_font, pos, text); } debug_draw_xform(ent->world_xform); @@ -753,11 +777,21 @@ INTERNAL void user_update(void) /* Present */ i32 vsync = VSYNC_ENABLED; - struct renderer_canvas *canvases[] = { - L.world_canvas, - L.ui_canvas - }; - renderer_canvas_present(canvases, ARRAY_COUNT(canvases), L.screen_size.x, L.screen_size.y, vsync); + + struct renderer_canvas **canvases = NULL; + u64 canvases_count = 0; + + if (t0->id <= 0 || t1->id <= 0) { + /* Don't render world on first frame */ + struct renderer_canvas *present_canvases[] = { L.ui_canvas }; + canvases = present_canvases; + canvases_count = ARRAY_COUNT(present_canvases); + } else { + struct renderer_canvas *present_canvases[] = { L.world_canvas, L.ui_canvas }; + canvases = present_canvases; + canvases_count = ARRAY_COUNT(present_canvases); + } + renderer_canvas_present(canvases, canvases_count, L.screen_size.x, L.screen_size.y, vsync); scratch_end(scratch); }