only re-calculate all xforms before publishing game tick
This commit is contained in:
parent
a7d8e19784
commit
dbeb0f0f72
BIN
res/graphics/gun.ase
(Stored with Git LFS)
Normal file
BIN
res/graphics/gun.ase
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
res/graphics/tim.ase
(Stored with Git LFS)
BIN
res/graphics/tim.ase
(Stored with Git LFS)
Binary file not shown.
@ -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 */
|
||||||
|
|||||||
145
src/game.c
145
src/game.c
@ -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 */
|
||||||
|
|||||||
23
src/user.c
23
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 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));
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user