diff --git a/res/graphics/gun.ase b/res/graphics/gun.ase new file mode 100644 index 00000000..43394560 --- /dev/null +++ b/res/graphics/gun.ase @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c02919188c293812b7743dfa50da32a88b711f0f6cc2e9e86ed587ec9de714c0 +size 698 diff --git a/res/graphics/tim.ase b/res/graphics/tim.ase index 38449ab2..005b7485 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:9535c14cdb801d25a07247d344f15582fa1b873c2353218dfc7dc3e65bc9220d -size 4411 +oid sha256:7304d94a74ed1eda141f109fcaa43eee01d4e535f5530e1db6d01a6468a51ef9 +size 4294 diff --git a/src/entity.h b/src/entity.h index 7a39bd26..572028d2 100644 --- a/src/entity.h +++ b/src/entity.h @@ -81,8 +81,7 @@ struct entity { struct string sprite_span_name; u32 sprite_tint; - struct xform sprite_local_xform; /* Sprite transform in relation to xform_world */ - struct xform sprite_global_xform; + struct xform sprite_local_xform; /* Sprite transform in relation to entity */ /* ====================================================================== */ /* Animation */ diff --git a/src/game.c b/src/game.c index f02a6580..f3d03a67 100644 --- a/src/game.c +++ b/src/game.c @@ -197,74 +197,6 @@ INTERNAL void publish_game_tick(void) sys_mutex_unlock(&lock); } - - - - - -/* TODO: Remove this(?) */ -#if 0 -INTERNAL void recalculate_world_xforms_recurse(struct entity *parent) -{ - struct temp_arena scratch = scratch_begin_no_conflict(); - - struct stack_node { - struct entity *entity; - struct xform parent_xform_world; - }; - - /* Depth first iteration */ - *arena_push(scratch.arena, struct stack_node) = (struct stack_node) { .entity = parent, .parent_xform_world = XFORM_IDENT }; - u64 stack_count = 1; - while (stack_count > 0) { - /* Pull from top of stack */ - struct stack_node node; - arena_pop(scratch.arena, struct stack_node, &node); - --stack_count; - - struct entity *child = node.entity; - - /* Calculate world xform */ - struct xform xform_world = xform_mul(node.parent_xform_world, child->_xform); - child->_xform_world = xform_world; - - /* Calculate sprite world xform */ - struct xform sprite_xform_world = xform_mul(xform_world, child->sprite_xform); - child->sprite_xform_world = sprite_xform_world; - - /* Append sub-children to stack */ - struct entity *subchild = entity_from_handle(G.world.entity_store, child->last); - while (subchild->valid) { - *arena_push(scratch.arena, struct stack_node) = (struct stack_node) { .entity = subchild, .parent_xform_world = xform_world }; - ++stack_count; - subchild = entity_from_handle(G.world.entity_store, subchild->prev); - } - } - - scratch_end(scratch); -} -#else -INTERNAL void recalculate_world_xforms_recurse(struct entity *ent) -{ - struct xform xform_global = entity_get_xform(ent); - //struct xform xform_local = entity_get_local_xform(ent); - (UNUSED)xform_global; - //(UNUSED)xform_local; - - struct entity_store *store = G.world.entity_store; - struct xform sprite_global_xform = xform_mul(xform_global, ent->sprite_local_xform); - ent->sprite_global_xform = sprite_global_xform; - for (struct entity *child = entity_from_handle(store, ent->first); child->valid; child = entity_from_handle(store, child->next)) { - recalculate_world_xforms_recurse(child); - } -} -#endif - - - - - - INTERNAL void game_update(void) { __prof; @@ -339,20 +271,13 @@ INTERNAL void game_update(void) /* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */ + struct entity *root = entity_from_handle(store, store->root); struct entity_array entities_array = entity_store_as_array(store); /* ========================== * * Update sprite * ========================== */ - /* Recalculate world xforms */ - for (u64 entity_index = 0; entity_index < entities_array.count; ++entity_index) { - struct entity *ent = &entities_array.entities[entity_index]; - if (ent->valid && ent->is_top) { - recalculate_world_xforms_recurse(ent); - } - } - for (u64 entity_index = 0; entity_index < entities_array.count; ++entity_index) { struct entity *ent = &entities_array.entities[entity_index]; if (!ent->valid) continue; @@ -410,14 +335,6 @@ INTERNAL void game_update(void) * Update entities pre-physics * ========================== */ - /* Recalculate world xforms */ - for (u64 entity_index = 0; entity_index < entities_array.count; ++entity_index) { - struct entity *ent = &entities_array.entities[entity_index]; - if (ent->valid && ent->is_top) { - recalculate_world_xforms_recurse(ent); - } - } - /* Find active camera */ struct entity *active_camera; { @@ -540,14 +457,6 @@ INTERNAL void game_update(void) * Update entity physics * ========================== */ - /* Recalculate world xforms */ - for (u64 entity_index = 0; entity_index < entities_array.count; ++entity_index) { - struct entity *ent = &entities_array.entities[entity_index]; - if (ent->valid && ent->is_top) { - recalculate_world_xforms_recurse(ent); - } - } - for (u64 entity_index = 0; entity_index < entities_array.count; ++entity_index) { struct entity *ent = &entities_array.entities[entity_index]; if (!ent->valid) continue; @@ -587,14 +496,6 @@ INTERNAL void game_update(void) * Update entities post-physics * ========================== */ - /* Recalculate world xforms */ - for (u64 entity_index = 0; entity_index < entities_array.count; ++entity_index) { - struct entity *ent = &entities_array.entities[entity_index]; - if (ent->valid && ent->is_top) { - recalculate_world_xforms_recurse(ent); - } - } - for (u64 entity_index = 0; entity_index < entities_array.count; ++entity_index) { struct entity *ent = &entities_array.entities[entity_index]; if (!ent->valid) continue; @@ -666,12 +567,46 @@ INTERNAL void game_update(void) * Publish tick * ========================== */ - /* Recalculate world xforms */ - for (u64 entity_index = 0; entity_index < entities_array.count; ++entity_index) { - struct entity *ent = &entities_array.entities[entity_index]; - if (ent->valid && ent->is_top) { - recalculate_world_xforms_recurse(ent); + /* Update cached global xforms to ensure they're accurate in published tick */ + { + struct temp_arena temp = arena_temp_begin(scratch.arena); + + struct stack_node { + struct entity *entity; + struct xform parent_global_xform; + }; + + /* Depth first iteration */ + *arena_push(temp.arena, struct stack_node) = (struct stack_node) { .entity = root, .parent_global_xform = XFORM_IDENT }; + u64 stack_count = 1; + while (stack_count > 0) { + /* Pull from top of stack */ + struct stack_node node; + arena_pop(temp.arena, struct stack_node, &node); + --stack_count; + + struct entity *child = node.entity; + + /* Calculate world xform */ + struct xform xf; + if (child->cached_global_xform_dirty) { + xf = xform_mul(node.parent_global_xform, child->local_xform); + child->cached_global_xform = xf; + child->cached_global_xform_dirty = false; + } else { + xf = child->cached_global_xform; + } + + /* Append sub-children to stack */ + struct entity *subchild = entity_from_handle(store, child->last); + while (subchild->valid) { + *arena_push(temp.arena, struct stack_node) = (struct stack_node) { .entity = subchild, .parent_global_xform = xf }; + ++stack_count; + subchild = entity_from_handle(store, subchild->prev); + } } + + arena_temp_end(temp); } /* Publish tick */ diff --git a/src/user.c b/src/user.c index d4cd1c80..e5fba856 100644 --- a/src/user.c +++ b/src/user.c @@ -359,6 +359,10 @@ INTERNAL void debug_draw_xform(struct xform xf) struct v2 x_ray = xform_basis_mul_v2(G.world_view, xform_get_right(xf)); struct v2 y_ray = xform_basis_mul_v2(G.world_view, xform_get_up(xf)); + f32 ray_scale = 1; + x_ray = v2_mul(x_ray, ray_scale); + y_ray = v2_mul(y_ray, ray_scale); + struct quad quad = quad_from_rect(RECT(0, 0, 1, -1)); quad = quad_mul_xform(quad_scale(quad, 0.075f), xf); @@ -454,6 +458,7 @@ INTERNAL void user_update(void) struct entity *e0 = &t0_entities.entities[i]; struct entity *e1 = &t1_entities.entities[i]; struct entity *e = &world_entities.entities[i]; + ASSERT(e->cached_global_xform_dirty == false); /* Game thread should have cached all global xforms before publishing */ if (e0->handle.gen == e1->handle.gen && e0->continuity_gen == e1->continuity_gen) { e->local_xform = xform_lerp(e0->local_xform, e1->local_xform, tick_blend); e->cached_global_xform = xform_lerp(e0->cached_global_xform, e1->cached_global_xform, tick_blend); @@ -464,7 +469,6 @@ INTERNAL void user_update(void) e->focus = v2_lerp(e0->focus, e1->focus, tick_blend); e->sprite_local_xform = xform_lerp(e0->sprite_local_xform, e1->sprite_local_xform, tick_blend); - e->sprite_global_xform = xform_lerp(e0->sprite_global_xform, e1->sprite_global_xform, tick_blend); e->animation_time_in_frame = math_lerp64(e0->animation_time_in_frame, e1->animation_time_in_frame, (f64)tick_blend); e->animation_frame = (u32)math_round_to_int(math_lerp(e0->animation_frame, e1->animation_frame, tick_blend)); @@ -774,11 +778,16 @@ INTERNAL void user_update(void) b32 skip_debug_draw = !G.debug_camera && ent == active_camera; b32 skip_debug_draw_transform = entity_has_prop(ent, ENTITY_PROP_CAMERA); + struct xform sprite_xform = xf; + /* Draw sprite */ if (!sprite_tag_is_nil(ent->sprite)) { - struct sprite_tag sprite = ent->sprite; + /* Calculate sprite xform */ + sprite_xform = xform_mul(xf, ent->sprite_local_xform); + /* Async load */ + struct sprite_tag sprite = ent->sprite; struct sprite_sheet *sheet = sprite_sheet_from_tag_async(sprite_frame_scope, sprite); struct sprite_texture *texture = sprite_texture_from_tag_async(sprite_frame_scope, sprite); (UNUSED)texture; @@ -786,7 +795,7 @@ INTERNAL void user_update(void) /* TODO: Fade in placeholder if texture isn't loaded */ if (sheet->loaded) { struct sprite_sheet_frame frame = sprite_sheet_get_frame(sheet, ent->animation_frame); - struct quad quad = quad_mul_xform(QUAD_UNIT_SQUARE_CENTERED, ent->sprite_global_xform); + struct quad quad = quad_mul_xform(QUAD_UNIT_SQUARE_CENTERED, sprite_xform); struct draw_sprite_params params = DRAW_SPRITE_PARAMS(.sprite = sprite, .tint = ent->sprite_tint, .clip = frame.clip); draw_sprite_quad(G.world_canvas, params, quad); } @@ -843,7 +852,7 @@ INTERNAL void user_update(void) if (entity_has_prop(ent, ENTITY_PROP_PLAYER_CONTROLLED)) { struct sprite_sheet *sheet = sprite_sheet_from_tag_async(sprite_frame_scope, ent->sprite); struct sprite_sheet_slice slice = sprite_sheet_get_slice(sheet, STR("hold"), ent->animation_frame); - struct v2 start = xform_mul_v2(ent->sprite_global_xform, slice.center); + struct v2 start = xform_mul_v2(sprite_xform, slice.center); start = xform_mul_v2(G.world_view, start); struct v2 end = v2_add(xf.og, ent->focus); end = xform_mul_v2(G.world_view, end); @@ -862,12 +871,12 @@ INTERNAL void user_update(void) for (u32 j = 0; j < group->per_frame_count; ++j) { struct sprite_sheet_slice slice = group->frame_slices[(ent->animation_frame * group->per_frame_count) + j]; - struct v2 center = xform_mul_v2(ent->sprite_global_xform, slice.center); + struct v2 center = xform_mul_v2(sprite_xform, slice.center); center = xform_mul_v2(G.world_view, center); if (!slice.has_ray) { struct quad quad = quad_from_rect(slice.rect); - quad = quad_mul_xform(quad, ent->sprite_global_xform); + quad = quad_mul_xform(quad, sprite_xform); quad = quad_mul_xform(quad, G.world_view); draw_solid_quad_line(G.viewport_canvas, quad, 2, RGBA_32_F(1, 0, 0.5, 1)); } @@ -875,7 +884,7 @@ INTERNAL void user_update(void) draw_solid_circle(G.viewport_canvas, center, 3, RGBA_32_F(1, 0, 0, 1), 20); if (slice.has_ray) { - struct v2 ray = xform_basis_mul_v2(ent->sprite_global_xform, slice.dir); + struct v2 ray = xform_basis_mul_v2(sprite_xform, slice.dir); ray = xform_basis_mul_v2(G.world_view, ray); ray = v2_mul(v2_norm(ray), 25); draw_solid_arrow_ray(G.viewport_canvas, center, ray, 2, 10, RGBA_32_F(1, 0, 0.5, 1));