fix entity gen comparison

This commit is contained in:
jacob 2024-08-06 16:05:29 -05:00
parent 53ae299816
commit bac9d797b9
10 changed files with 108 additions and 74 deletions

View File

@ -64,6 +64,7 @@ struct entity *entity_alloc_unlinked(struct entity_store *store)
/* Reuse from free list */ /* Reuse from free list */
entity = entity_from_handle(store, store->first_free); entity = entity_from_handle(store, store->first_free);
handle = entity->handle; handle = entity->handle;
++handle.gen;
store->first_free = entity->next_free; store->first_free = entity->next_free;
} else { } else {
/* Make new */ /* Make new */
@ -122,7 +123,7 @@ struct entity_store *entity_get_store(struct entity *ent)
} }
} }
/* Returns a valid entity or nil entity. Always safe to read result, need to check `valid` to write. */ /* Returns a valid entity or read-only nil entity. Always safe to read result, need to check `valid` to write. */
struct entity *entity_from_handle(struct entity_store *store, struct entity_handle handle) struct entity *entity_from_handle(struct entity_store *store, struct entity_handle handle)
{ {
if (handle.gen != 0 && handle.idx < store->count) { if (handle.gen != 0 && handle.idx < store->count) {

View File

@ -131,11 +131,6 @@ INLINE struct entity_handle entity_nil_handle(void)
return (struct entity_handle) { 0 }; return (struct entity_handle) { 0 };
} }
INLINE b32 entity_handle_is_nil(struct entity_handle h)
{
return h.gen == 0;
}
INLINE b32 entity_handle_eq(struct entity_handle a, struct entity_handle b) INLINE b32 entity_handle_eq(struct entity_handle a, struct entity_handle b)
{ {
return a.gen == b.gen && a.idx == b.idx; return a.gen == b.gen && a.idx == b.idx;

View File

@ -95,6 +95,56 @@ INTERNAL struct game_cmd_array pop_cmds(struct arena *arena)
return array; return array;
} }
/* ========================== *
* Test
* ========================== */
/* TODO: Remove this */
INTERNAL void spawn_test_entities(void)
{
/* Player ent */
struct entity *player_ent;
{
struct v2 pos = V2(1, 1);
struct v2 size = V2(1, 1);
f32 r = 0;
struct entity *e = entity_alloc_top(G.world.entity_store);
e->xform = XFORM_TRS(.t = pos, .r = r, .s = size);
e->sprite = sprite_tag_from_path(STR("res/graphics/tim.ase"));
e->sprite_span_name = STR("idle.unarmed");
//e->sprite_span_name = STR("idle.one_handed");
//e->sprite_span_name = STR("idle.two_handed");
entity_enable_prop(e, ENTITY_PROP_PLAYER_CONTROLLED);
e->player_max_speed = 4.f;
e->player_acceleration = 20.0f;
e->focus = V2(0, -1);
entity_enable_prop(e, ENTITY_PROP_ANIMATING);
player_ent = e;
//entity_enable_prop(e, ENTITY_PROP_TEST);
}
/* Camera ent */
{
struct entity *e = entity_alloc_top(G.world.entity_store);
e->xform = XFORM_IDENT;
entity_enable_prop(e, ENTITY_PROP_CAMERA);
entity_enable_prop(e, ENTITY_PROP_CAMERA_ACTIVE);
e->camera_follow = player_ent->handle;
f32 width = (f32)DEFAULT_CAMERA_WIDTH;
f32 height = (f32)DEFAULT_CAMERA_HEIGHT;
e->camera_quad_xform = XFORM_TRS(.s = V2(width, height));
}
}
/* ========================== * /* ========================== *
* Update * Update
* ========================== */ * ========================== */
@ -165,47 +215,7 @@ INTERNAL void game_update(void)
static b32 run = 0; static b32 run = 0;
if (!run) { if (!run) {
run = 1; run = 1;
spawn_test_entities();
/* Player ent */
struct entity *player_ent;
{
struct v2 pos = V2(1, 1);
struct v2 size = V2(1, 1);
f32 r = 0;
struct entity *e = entity_alloc_top(G.world.entity_store);
e->xform = XFORM_TRS(.t = pos, .r = r, .s = size);
e->sprite = sprite_tag_from_path(STR("res/graphics/tim.ase"));
e->sprite_span_name = STR("idle.unarmed");
//e->sprite_span_name = STR("idle.one_handed");
//e->sprite_span_name = STR("idle.two_handed");
entity_enable_prop(e, ENTITY_PROP_PLAYER_CONTROLLED);
e->player_max_speed = 4.f;
e->player_acceleration = 20.0f;
e->focus = V2(0, -1);
entity_enable_prop(e, ENTITY_PROP_ANIMATING);
player_ent = e;
//entity_enable_prop(e, ENTITY_PROP_TEST);
}
/* Camera ent */
{
struct entity *e = entity_alloc_top(G.world.entity_store);
e->xform = XFORM_IDENT;
entity_enable_prop(e, ENTITY_PROP_CAMERA);
entity_enable_prop(e, ENTITY_PROP_CAMERA_ACTIVE);
e->camera_follow = player_ent->handle;
f32 width = (f32)DEFAULT_CAMERA_WIDTH;
f32 height = (f32)DEFAULT_CAMERA_HEIGHT;
e->camera_quad_xform = XFORM_TRS(.s = V2(width, height));
}
} }
++G.world.tick_id; ++G.world.tick_id;
@ -237,12 +247,18 @@ INTERNAL void game_update(void)
logf_info("Clearing level"); logf_info("Clearing level");
for (u64 i = 0; i < entities_array.count; ++i) { for (u64 i = 0; i < entities_array.count; ++i) {
struct entity *ent = &entities_array.entities[i]; struct entity *ent = &entities_array.entities[i];
if (ent->valid) { if (ent->valid && !ent->root) {
entity_release(G.world.entity_store, ent); entity_release(G.world.entity_store, ent);
} }
} }
} break; } break;
/* Spawn test */
case GAME_CMD_KIND_SPAWN_TEST: {
logf_info("Spawning (test)");
spawn_test_entities();
} break;
default: break; default: break;
}; };
} }
@ -255,6 +271,8 @@ INTERNAL void game_update(void)
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
struct entity_handle root_handle = G.world.entity_store->root;
/* ========================== * /* ========================== *
* Update sprite * Update sprite
* ========================== */ * ========================== */
@ -262,7 +280,7 @@ INTERNAL void game_update(void)
/* Recalculate world xforms */ /* Recalculate world xforms */
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 && !ent->parent.gen) { if (ent->valid && entity_handle_eq(ent->parent, root_handle)) {
recalculate_world_xforms_recurse(ent); recalculate_world_xforms_recurse(ent);
} }
} }
@ -320,7 +338,7 @@ INTERNAL void game_update(void)
/* Recalculate world xforms */ /* Recalculate world xforms */
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 && !ent->parent.gen) { if (ent->valid && entity_handle_eq(ent->parent, root_handle)) {
recalculate_world_xforms_recurse(ent); recalculate_world_xforms_recurse(ent);
} }
} }
@ -420,7 +438,7 @@ INTERNAL void game_update(void)
/* Recalculate world xforms */ /* Recalculate world xforms */
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 && !ent->parent.gen) { if (ent->valid && entity_handle_eq(ent->parent, root_handle)) {
recalculate_world_xforms_recurse(ent); recalculate_world_xforms_recurse(ent);
} }
} }
@ -467,7 +485,7 @@ INTERNAL void game_update(void)
/* Recalculate world xforms */ /* Recalculate world xforms */
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 && !ent->parent.gen) { if (ent->valid && entity_handle_eq(ent->parent, root_handle)) {
recalculate_world_xforms_recurse(ent); recalculate_world_xforms_recurse(ent);
} }
} }
@ -543,7 +561,7 @@ INTERNAL void game_update(void)
/* Recalculate world xforms */ /* Recalculate world xforms */
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 && !ent->parent.gen) { if (ent->valid && entity_handle_eq(ent->parent, root_handle)) {
recalculate_world_xforms_recurse(ent); recalculate_world_xforms_recurse(ent);
} }
} }
@ -584,6 +602,7 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(game_thread_entry_point, arg)
void game_get_latest_tick(struct world *dest) void game_get_latest_tick(struct world *dest)
{ {
__prof;
struct sys_lock lock = sys_mutex_lock_e(&G.published_tick_mutex); struct sys_lock lock = sys_mutex_lock_e(&G.published_tick_mutex);
world_copy_replace(dest, &G.published_tick); world_copy_replace(dest, &G.published_tick);
sys_mutex_unlock(&lock); sys_mutex_unlock(&lock);

View File

@ -14,6 +14,7 @@ enum game_cmd_kind {
/* Testing */ /* Testing */
GAME_CMD_KIND_CLEAR_ALL, GAME_CMD_KIND_CLEAR_ALL,
GAME_CMD_KIND_SPAWN_TEST,
GAME_CMD_KIND_COUNT GAME_CMD_KIND_COUNT
}; };

View File

@ -115,7 +115,7 @@ INTERNAL struct track *track_alloc_locked(struct sys_lock *lock, struct sound *s
if (next_free) { if (next_free) {
next_free->prev = NULL; next_free->prev = NULL;
} }
*track = (struct track) { 0 }; *track = (struct track) { .gen = track->gen + 1 };
} else { } else {
/* Allocate new */ /* Allocate new */
track = arena_push_zero(&G.track_arena, struct track); track = arena_push_zero(&G.track_arena, struct track);

View File

@ -205,6 +205,7 @@ INTERNAL struct renderer_handle handle_alloc(void *data)
slot = store->head_free; slot = store->head_free;
store->head_free = slot->next_free; store->head_free = slot->next_free;
slot->next_free = NULL; slot->next_free = NULL;
++slot->gen;
} else { } else {
/* Or push onto arena */ /* Or push onto arena */
if (store->count + 1 >= HANDLE_IDX_MAX) { if (store->count + 1 >= HANDLE_IDX_MAX) {

View File

@ -1585,7 +1585,9 @@ INTERNAL struct win32_thread *win32_thread_alloc_locked(struct sys_lock *lock)
if (G.threads_first_free) { if (G.threads_first_free) {
t = G.threads_first_free; t = G.threads_first_free;
G.threads_first_free = t->next; G.threads_first_free = t->next;
MEMZERO_STRUCT(t); *t = (struct win32_thread) {
.gen = t->gen + 1
};
} else { } else {
t = arena_push_zero(&G.threads_arena, struct win32_thread); t = arena_push_zero(&G.threads_arena, struct win32_thread);
t->gen = 1; t->gen = 1;

View File

@ -84,6 +84,7 @@ GLOBAL READONLY enum user_bind_kind g_binds[SYS_BTN_COUNT] = {
/* Testing */ /* Testing */
[SYS_BTN_C] = USER_BIND_KIND_DEBUG_CLEAR, [SYS_BTN_C] = USER_BIND_KIND_DEBUG_CLEAR,
[SYS_BTN_V] = USER_BIND_KIND_DEBUG_SPAWN,
[SYS_BTN_F6] = USER_BIND_KIND_DEBUG_DRAW, [SYS_BTN_F6] = USER_BIND_KIND_DEBUG_DRAW,
[SYS_BTN_F7] = USER_BIND_KIND_DEBUG_CAMERA, [SYS_BTN_F7] = USER_BIND_KIND_DEBUG_CAMERA,
[SYS_BTN_F11] = USER_BIND_KIND_FULLSCREEN, [SYS_BTN_F11] = USER_BIND_KIND_FULLSCREEN,
@ -443,26 +444,29 @@ INTERNAL void user_update(void)
struct entity_array world_entities = entity_store_as_array(G.world.entity_store); struct entity_array world_entities = entity_store_as_array(G.world.entity_store);
u64 num_entities = min_u64(t0_entities.count, t1_entities.count); u64 num_entities = min_u64(t0_entities.count, t1_entities.count);
for (u64 i = 0; i < num_entities; ++i) { {
struct entity *e0 = &t0_entities.entities[i]; __profscope(tick_blending);
struct entity *e1 = &t1_entities.entities[i]; for (u64 i = 0; i < num_entities; ++i) {
struct entity *e = &world_entities.entities[i]; struct entity *e0 = &t0_entities.entities[i];
if (e0->handle.gen == e1->handle.gen && e0->continuity_gen == e1->continuity_gen) { struct entity *e1 = &t1_entities.entities[i];
e->xform = xform_lerp(e0->xform, e1->xform, tick_blend); struct entity *e = &world_entities.entities[i];
e->xform_world = xform_lerp(e0->xform_world, e1->xform_world, tick_blend); if (e0->handle.gen == e1->handle.gen && e0->continuity_gen == e1->continuity_gen) {
e->xform = xform_lerp(e0->xform, e1->xform, tick_blend);
e->xform_world = xform_lerp(e0->xform_world, e1->xform_world, tick_blend);
e->acceleration = v2_lerp(e0->acceleration, e1->acceleration, tick_blend); e->acceleration = v2_lerp(e0->acceleration, e1->acceleration, tick_blend);
e->velocity = v2_lerp(e0->velocity, e1->velocity, tick_blend); e->velocity = v2_lerp(e0->velocity, e1->velocity, tick_blend);
e->player_acceleration = math_lerp(e0->player_acceleration, e1->player_acceleration, tick_blend); e->player_acceleration = math_lerp(e0->player_acceleration, e1->player_acceleration, tick_blend);
e->focus = v2_lerp(e0->focus, e1->focus, tick_blend); e->focus = v2_lerp(e0->focus, e1->focus, tick_blend);
e->sprite_xform = xform_lerp(e0->sprite_xform, e1->sprite_xform, tick_blend); e->sprite_xform = xform_lerp(e0->sprite_xform, e1->sprite_xform, tick_blend);
e->sprite_xform_world = xform_lerp(e0->sprite_xform_world, e1->sprite_xform_world, tick_blend); e->sprite_xform_world = xform_lerp(e0->sprite_xform_world, e1->sprite_xform_world, 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));
e->camera_quad_xform = xform_lerp(e0->camera_quad_xform, e1->camera_quad_xform, tick_blend); e->camera_quad_xform = xform_lerp(e0->camera_quad_xform, e1->camera_quad_xform, tick_blend);
e->camera_rel_xform_target = xform_lerp(e0->camera_rel_xform_target, e1->camera_rel_xform_target, tick_blend); e->camera_rel_xform_target = xform_lerp(e0->camera_rel_xform_target, e1->camera_rel_xform_target, tick_blend);
}
} }
} }
#else #else
@ -570,13 +574,23 @@ INTERNAL void user_update(void)
/* Test clear world */ /* Test clear world */
{ {
struct bind_state state = G.bind_states[USER_BIND_KIND_DEBUG_CLEAR]; struct bind_state state = G.bind_states[USER_BIND_KIND_DEBUG_CLEAR];
if (state.num_presses || state.is_held) { if (state.num_presses) {
queue_game_cmd(&cmd_list, (struct game_cmd) { queue_game_cmd(&cmd_list, (struct game_cmd) {
.kind = GAME_CMD_KIND_CLEAR_ALL .kind = GAME_CMD_KIND_CLEAR_ALL
}); });
} }
} }
/* Test spawn */
{
struct bind_state state = G.bind_states[USER_BIND_KIND_DEBUG_SPAWN];
if (state.num_presses) {
queue_game_cmd(&cmd_list, (struct game_cmd) {
.kind = GAME_CMD_KIND_SPAWN_TEST
});
}
}
if (G.bind_states[USER_BIND_KIND_DEBUG_DRAW].num_presses > 0) { if (G.bind_states[USER_BIND_KIND_DEBUG_DRAW].num_presses > 0) {
G.debug_draw = !G.debug_draw; G.debug_draw = !G.debug_draw;
} }

View File

@ -22,6 +22,7 @@ enum user_bind_kind {
/* Testing */ /* Testing */
USER_BIND_KIND_DEBUG_CLEAR, USER_BIND_KIND_DEBUG_CLEAR,
USER_BIND_KIND_DEBUG_SPAWN,
USER_BIND_KIND_DEBUG_DRAW, USER_BIND_KIND_DEBUG_DRAW,
USER_BIND_KIND_DEBUG_CAMERA, USER_BIND_KIND_DEBUG_CAMERA,
USER_BIND_KIND_FULLSCREEN, USER_BIND_KIND_FULLSCREEN,

View File

@ -176,7 +176,7 @@ INTERNAL struct work *work_alloc_locked(struct sys_lock *lock)
G.free_work_head = work->next_free; G.free_work_head = work->next_free;
*work = (struct work) { *work = (struct work) {
.condition_variable_finished = work->condition_variable_finished, .condition_variable_finished = work->condition_variable_finished,
.gen = work->gen .gen = work->gen + 1
}; };
} else { } else {
/* Make new */ /* Make new */