diff --git a/res/graphics/gun.ase b/res/graphics/gun.ase index cb30ac7a..980a602d 100644 --- a/res/graphics/gun.ase +++ b/res/graphics/gun.ase @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f44b16ea484509e632739567c4091236a1348cdc85fa6077d7b6b52f49cbd2b0 +oid sha256:6eb03261e8abdb3729c65a0f65b12c9771c92bb1ab5b8ee07bcc0f7025d664df size 816 diff --git a/res/graphics/tim.ase b/res/graphics/tim.ase index 005b7485..b68923ef 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:7304d94a74ed1eda141f109fcaa43eee01d4e535f5530e1db6d01a6468a51ef9 -size 4294 +oid sha256:5b633d18887574d0006971c2c57d451731c37ebc5c2e250959795414aba25a23 +size 4506 diff --git a/src/entity.c b/src/entity.c index f22afc09..b5ce23ee 100644 --- a/src/entity.c +++ b/src/entity.c @@ -265,25 +265,29 @@ struct xform entity_get_local_xform(struct entity *ent) void entity_set_xform(struct entity *ent, struct xform xf) { - struct entity_store *store = entity_get_store(ent); - /* Update local xform */ - if (ent->is_top) { - ent->local_xform = xf; - } else { - struct entity *parent = entity_from_handle(store, ent->parent); - struct xform parent_global = entity_get_xform_w_store(store, parent); - ent->local_xform = xform_mul(xform_invert(parent_global), xf); + if (!xform_eq(xf, ent->cached_global_xform)) { + struct entity_store *store = entity_get_store(ent); + /* Update local xform */ + if (ent->is_top) { + ent->local_xform = xf; + } else { + struct entity *parent = entity_from_handle(store, ent->parent); + struct xform parent_global = entity_get_xform_w_store(store, parent); + ent->local_xform = xform_mul(xform_invert(parent_global), xf); + } + ent->cached_global_xform = xf; + ent->cached_global_xform_dirty = false; + entity_mark_child_xforms_dirty(store, ent); } - ent->cached_global_xform = xf; - ent->cached_global_xform_dirty = false; - entity_mark_child_xforms_dirty(store, ent); } void entity_set_local_xform(struct entity *ent, struct xform xf) { - ent->local_xform = xf; - ent->cached_global_xform_dirty = true; - entity_mark_child_xforms_dirty(entity_get_store(ent), ent); + if (!xform_eq(xf, ent->local_xform)) { + ent->local_xform = xf; + ent->cached_global_xform_dirty = true; + entity_mark_child_xforms_dirty(entity_get_store(ent), ent); + } } /* ========================== * diff --git a/src/entity.h b/src/entity.h index 9985eb8d..2d7c1758 100644 --- a/src/entity.h +++ b/src/entity.h @@ -24,6 +24,8 @@ enum entity_prop { ENTITY_PROP_BULLET, + ENTITY_PROP_ATTACHED, + /* Test props */ ENTITY_PROP_TEST, @@ -122,6 +124,13 @@ struct entity { f64 animation_time_in_frame; u32 animation_frame; + /* ====================================================================== */ + /* Attachment */ + + /* ENTITY_PROP_ATTACHED */ + /* Slice name on the parent entity's sprite to attach to */ + struct string attach_slice; + /* ====================================================================== */ /* Equip */ diff --git a/src/game.c b/src/game.c index 63a3991e..98abf2d5 100644 --- a/src/game.c +++ b/src/game.c @@ -118,9 +118,9 @@ INTERNAL void spawn_test_entities(void) entity_set_xform(e, xf); e->sprite = sprite_tag_from_path(STR("res/graphics/tim.ase")); - e->sprite_span_name = STR("idle.unarmed"); + //e->sprite_span_name = STR("idle.unarmed"); //e->sprite_span_name = STR("idle.one_handed"); - //e->sprite_span_name = STR("idle.two_handed"); + e->sprite_span_name = STR("idle.two_handed"); entity_enable_prop(e, ENTITY_PROP_PLAYER_CONTROLLED); e->player_max_speed = 4.f; @@ -140,18 +140,14 @@ INTERNAL void spawn_test_entities(void) f32 r = PI / 4; struct entity *e = entity_alloc(root); #else - struct v2 pos = V2(0.1, 0); - struct v2 size = V2(1, 1); - f32 r = 0; struct entity *e = entity_alloc(player_ent); #endif - - struct xform xf = XFORM_TRS(.t = pos, .r = r, .s = size); - entity_set_local_xform(e, xf); - e->sprite = sprite_tag_from_path(STR("res/graphics/gun.ase")); + entity_enable_prop(e, ENTITY_PROP_ATTACHED); + e->attach_slice = STR("attach.wep"); + entity_enable_prop(e, ENTITY_PROP_WEAPON); e->trigger_delay = 1.0 / 10.0; @@ -284,7 +280,8 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) if (!ent->valid) continue; if (!entity_has_prop(ent, ENTITY_PROP_ACTIVE)) { - if (ent->activation_tick == 0 || G.tick.tick_id >= ent->activation_tick) { + u64 atick = ent->activation_tick; + if (atick != 0 || G.tick.tick_id >= atick) { entity_enable_prop(ent, ENTITY_PROP_ACTIVE); ent->activation_tick = G.tick.tick_id; ++ent->continuity_gen; @@ -360,6 +357,33 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) ent->sprite_local_xform = xf; } + /* ========================== * + * Update attachments + * ========================== */ + + for (u64 entity_index = 0; entity_index < store->reserved; ++entity_index) { + struct entity *ent = &store->entities[entity_index]; + if (!(ent->valid && entity_has_prop(ent, ENTITY_PROP_ACTIVE))) continue; + + if (entity_has_prop(ent, ENTITY_PROP_ATTACHED)) { + struct entity *parent = entity_from_handle(store, ent->parent); + struct sprite_tag parent_sprite = parent->sprite; + struct sprite_sheet *parent_sheet = sprite_sheet_from_tag_await(sprite_frame_scope, parent_sprite); + + struct xform parent_xf = entity_get_xform(parent); + struct xform parent_sprite_xf = xform_mul(parent_xf, parent->sprite_local_xform); + + struct sprite_sheet_slice attach_slice = sprite_sheet_get_slice(parent_sheet, ent->attach_slice, parent->animation_frame); + struct v2 attach_pos = xform_mul_v2(parent_sprite_xf, attach_slice.center); + struct v2 attach_dir = xform_basis_mul_v2(parent_sprite_xf, attach_slice.dir); + + struct xform xf = entity_get_xform(ent); + xf.og = attach_pos; + xf = xform_with_rotation(xf, v2_angle(attach_dir) + PI / 2); + entity_set_xform(ent, xf); + } + } + /* ========================== * * Update control from player cmds * ========================== */ @@ -506,7 +530,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) bullet->bullet_src = ent->handle; bullet->bullet_src_pos = rel_pos; bullet->bullet_src_dir = rel_dir; - bullet->bullet_impulse = 25; + bullet->bullet_impulse = 5; entity_enable_prop(bullet, ENTITY_PROP_BULLET); } @@ -530,7 +554,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) f32 final_xf_angle; { struct sprite_sheet *sheet = sprite_sheet_from_tag_await(sprite_frame_scope, ent->sprite); - struct sprite_sheet_slice slice = sprite_sheet_get_slice(sheet, STR("hold"), ent->animation_frame); + struct sprite_sheet_slice slice = sprite_sheet_get_slice(sheet, STR("attach.wep"), ent->animation_frame); f32 forward_hold_angle_offset; { diff --git a/src/math.h b/src/math.h index 70a8e47e..9f60f78b 100644 --- a/src/math.h +++ b/src/math.h @@ -741,6 +741,11 @@ INLINE struct v2 xform_get_scale(struct xform xf); INLINE struct trs trs_from_xform(struct xform m); INLINE struct trs trs_lerp(struct trs a, struct trs b, f32 t); +INLINE b32 xform_eq(struct xform xf1, struct xform xf2) +{ + return v2_eq(xf1.bx, xf2.bx) && v2_eq(xf1.by, xf2.by) && v2_eq(xf1.og, xf2.og); +} + INLINE struct xform xform_from_pos(struct v2 v) { return (struct xform) { diff --git a/src/memory.h b/src/memory.h index b7a05a3b..fc924f20 100644 --- a/src/memory.h +++ b/src/memory.h @@ -11,6 +11,9 @@ #define MEMCMP_STRUCT(p1, p2) MEMCMP((p1), (p2), sizeof(*p1)) #define MEMCMP(p1, p2, n) memcmp((p1), (p2), (n)) +#define MEMEQ_STRUCT(p1, p2) MEMEQ((p1), (p2), sizeof(*p1)) +#define MEMEQ(p1, p2, n) (MEMCMP((p1), (p2), (n)) == 0) + #define MEMSET(ptr, val, count) memset((ptr), (val), (count)) #if CRTLIB diff --git a/src/sprite.c b/src/sprite.c index 8ab8abc5..21319c5a 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -61,8 +61,8 @@ enum cache_node_state { }; struct cache_node_refcount { - i32 count; /* Number of scopes currently holding a reference to this node */ - u32 last_modified_cycle; /* Last time that refcount was modified */ + i32 count; /* Number of scopes currently holding a reference to this node */ + u32 last_modified_cycle; /* Last time that refcount was modified */ }; CT_ASSERT(sizeof(struct cache_node_refcount) == 8); /* Must fit into 64 bit atomic */ @@ -974,6 +974,8 @@ struct sprite_sheet_slice sprite_sheet_get_slice(struct sprite_sheet *sheet, str /* Return 'pivot' by default */ struct sprite_sheet_slice res = { 0 }; if (string_eq(name, STR("pivot"))) { + /* 'pivot' slice does not exist, return center */ + res.center = V2(0, 0); res.center_px = v2_mul(sheet->frame_size, 0.5f); res.dir_px = V2(res.center_px.x, 0); res.dir = V2(0, -0.5); @@ -1096,10 +1098,10 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(sprite_evictor_thread_entry_point, arg) } #endif - /* Check usage time */ #if RESOURCE_RELOADING + /* Check usage time */ /* Only check conditional if RESOURCE_RELOADING is enabled, - * since over-budget is assumed to be * true otherwise */ + * since over-budget is assumed to be true otherwise */ if (cache_over_budget) #endif {