only re-calculate all xforms before publishing game tick

This commit is contained in:
jacob 2024-08-08 14:23:18 -05:00
parent a7d8e19784
commit dbeb0f0f72
5 changed files with 62 additions and 116 deletions

BIN
res/graphics/gun.ase (Stored with Git LFS) Normal file

Binary file not shown.

BIN
res/graphics/tim.ase (Stored with Git LFS)

Binary file not shown.

View File

@ -81,8 +81,7 @@ struct entity {
struct string sprite_span_name; struct string sprite_span_name;
u32 sprite_tint; u32 sprite_tint;
struct xform sprite_local_xform; /* Sprite transform in relation to xform_world */ struct xform sprite_local_xform; /* Sprite transform in relation to entity */
struct xform sprite_global_xform;
/* ====================================================================== */ /* ====================================================================== */
/* Animation */ /* Animation */

View File

@ -197,74 +197,6 @@ INTERNAL void publish_game_tick(void)
sys_mutex_unlock(&lock); 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) INTERNAL void game_update(void)
{ {
__prof; __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); struct entity_array entities_array = entity_store_as_array(store);
/* ========================== * /* ========================== *
* Update sprite * 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) { for (u64 entity_index = 0; entity_index < entities_array.count; ++entity_index) {
struct entity *ent = &entities_array.entities[entity_index]; struct entity *ent = &entities_array.entities[entity_index];
if (!ent->valid) continue; if (!ent->valid) continue;
@ -410,14 +335,6 @@ INTERNAL void game_update(void)
* Update entities pre-physics * 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 */ /* Find active camera */
struct entity *active_camera; struct entity *active_camera;
{ {
@ -540,14 +457,6 @@ INTERNAL void game_update(void)
* Update entity physics * 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) { for (u64 entity_index = 0; entity_index < entities_array.count; ++entity_index) {
struct entity *ent = &entities_array.entities[entity_index]; struct entity *ent = &entities_array.entities[entity_index];
if (!ent->valid) continue; if (!ent->valid) continue;
@ -587,14 +496,6 @@ INTERNAL void game_update(void)
* Update entities post-physics * 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) { for (u64 entity_index = 0; entity_index < entities_array.count; ++entity_index) {
struct entity *ent = &entities_array.entities[entity_index]; struct entity *ent = &entities_array.entities[entity_index];
if (!ent->valid) continue; if (!ent->valid) continue;
@ -666,12 +567,46 @@ INTERNAL void game_update(void)
* Publish tick * Publish tick
* ========================== */ * ========================== */
/* Recalculate world xforms */ /* Update cached global xforms to ensure they're accurate in published tick */
for (u64 entity_index = 0; entity_index < entities_array.count; ++entity_index) { {
struct entity *ent = &entities_array.entities[entity_index]; struct temp_arena temp = arena_temp_begin(scratch.arena);
if (ent->valid && ent->is_top) {
recalculate_world_xforms_recurse(ent); 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 */ /* Publish tick */

View File

@ -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 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)); 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)); struct quad quad = quad_from_rect(RECT(0, 0, 1, -1));
quad = quad_mul_xform(quad_scale(quad, 0.075f), xf); 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 *e0 = &t0_entities.entities[i];
struct entity *e1 = &t1_entities.entities[i]; struct entity *e1 = &t1_entities.entities[i];
struct entity *e = &world_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) { 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->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); 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->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_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_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)); 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 = !G.debug_camera && ent == active_camera;
b32 skip_debug_draw_transform = entity_has_prop(ent, ENTITY_PROP_CAMERA); b32 skip_debug_draw_transform = entity_has_prop(ent, ENTITY_PROP_CAMERA);
struct xform sprite_xform = xf;
/* Draw sprite */ /* Draw sprite */
if (!sprite_tag_is_nil(ent->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 */ /* Async load */
struct sprite_tag sprite = ent->sprite;
struct sprite_sheet *sheet = sprite_sheet_from_tag_async(sprite_frame_scope, 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); struct sprite_texture *texture = sprite_texture_from_tag_async(sprite_frame_scope, sprite);
(UNUSED)texture; (UNUSED)texture;
@ -786,7 +795,7 @@ INTERNAL void user_update(void)
/* TODO: Fade in placeholder if texture isn't loaded */ /* TODO: Fade in placeholder if texture isn't loaded */
if (sheet->loaded) { if (sheet->loaded) {
struct sprite_sheet_frame frame = sprite_sheet_get_frame(sheet, ent->animation_frame); 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); 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); 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)) { 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 *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 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); start = xform_mul_v2(G.world_view, start);
struct v2 end = v2_add(xf.og, ent->focus); struct v2 end = v2_add(xf.og, ent->focus);
end = xform_mul_v2(G.world_view, end); 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) { 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 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); center = xform_mul_v2(G.world_view, center);
if (!slice.has_ray) { if (!slice.has_ray) {
struct quad quad = quad_from_rect(slice.rect); 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); 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)); 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); draw_solid_circle(G.viewport_canvas, center, 3, RGBA_32_F(1, 0, 0, 1), 20);
if (slice.has_ray) { 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 = xform_basis_mul_v2(G.world_view, ray);
ray = v2_mul(v2_norm(ray), 25); 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)); draw_solid_arrow_ray(G.viewport_canvas, center, ray, 2, 10, RGBA_32_F(1, 0, 0.5, 1));