diff --git a/src/entity.c b/src/entity.c index 2183bac6..c894d57d 100644 --- a/src/entity.c +++ b/src/entity.c @@ -29,6 +29,11 @@ struct entity_store *entity_store_alloc(void) store->arena = arena; store->entities = arena_dry_push(&arena, struct entity); ASSERT((u64)store->entities - (u64)store == STORE_ENTITIES_OFFSET); /* Offset must be correct */ + + struct entity *root = entity_alloc_unlinked(store); + root->root = true; + store->root = root->handle; + return store; } @@ -51,7 +56,7 @@ void entity_store_copy_replace(struct entity_store *dest, struct entity_store *s * Allocation * ========================== */ -struct entity *entity_alloc(struct entity_store *store) +struct entity *entity_alloc_unlinked(struct entity_store *store) { struct entity *entity = NULL; struct entity_handle handle = { 0 }; @@ -71,13 +76,34 @@ struct entity *entity_alloc(struct entity_store *store) return entity; } +struct entity *entity_alloc_top(struct entity_store *store) +{ + struct entity *e = entity_alloc_unlinked(store); + struct entity *root = entity_from_handle(store, store->root); + entity_link(root, e); + return e; +} + +struct entity *entity_alloc_child(struct entity *parent) +{ + struct entity_store *store = entity_get_store(parent); + struct entity *e = entity_alloc_unlinked(store); + entity_link(parent, e); + return e; +} + void entity_release(struct entity_store *store, struct entity *entity) { - /* FIXME: Unlink entity */ ++entity->handle.gen; entity->valid = false; entity->next_free = store->first_free; store->first_free = entity->handle; + /* Release children */ + if (entity->first.gen) { + for (struct entity *child = entity_from_handle(store, entity->first); child->valid; child = entity_from_handle(store, child->next)) { + entity_release(store, child); + } + } } /* ========================== * @@ -86,19 +112,20 @@ void entity_release(struct entity_store *store, struct entity *entity) struct entity_store *entity_get_store(struct entity *ent) { - struct entity_store *store = entity_store_nil(); if (ent->valid) { u64 first_entity_addr = (u64)(ent - ent->handle.idx); - store = (struct entity_store *)(first_entity_addr - STORE_ENTITIES_OFFSET); + struct entity_store *store = (struct entity_store *)(first_entity_addr - STORE_ENTITIES_OFFSET); ASSERT(store->entities == (struct entity *)first_entity_addr); + return store; + } else { + return entity_store_nil(); } - return store; } /* Returns a valid entity or 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) { - if (handle.idx < store->count) { + if (handle.gen != 0 && handle.idx < store->count) { struct entity *entity = &store->entities[handle.idx]; if (entity->handle.gen == handle.gen) { return entity; @@ -202,4 +229,32 @@ void entity_link(struct entity *parent, struct entity *child) } } -/* TODO: entity_unlink() */ +void entity_unlink(struct entity *ent) +{ + struct entity_store *store = entity_get_store(ent); + ASSERT(!entity_handle_eq(ent->handle, store->root)); + + struct entity *parent = entity_from_handle(store, ent->parent); + struct entity *prev = entity_from_handle(store, ent->prev); + struct entity *next = entity_from_handle(store, ent->next); + + /* Unlink from parent & siblings */ + if (prev->valid) { + prev->next = next->handle; + } else { + parent->first = next->handle; + } + if (next->valid) { + next->prev = prev->handle; + } else { + parent->last = prev->handle; + } + + /* Link children to grandparent */ + if (ent->first.gen) { + struct entity_handle parent_handle = parent->handle; + for (struct entity *child = entity_from_handle(store, ent->first); child->valid; child = entity_from_handle(store, child->next)) { + child->parent = parent_handle; + } + } +} diff --git a/src/entity.h b/src/entity.h index e8ba8b42..c549c901 100644 --- a/src/entity.h +++ b/src/entity.h @@ -29,6 +29,7 @@ struct entity_store { struct arena arena; u64 count; struct entity_handle first_free; + struct entity_handle root; struct entity *entities; }; @@ -43,6 +44,9 @@ struct entity { /* Special value stored in first entity in store array */ u64 store_offset; + /* Is this the root entity */ + b32 root; + /* Tree */ struct entity_handle parent; struct entity_handle next; @@ -118,6 +122,25 @@ struct entity_prop_array { u64 count; }; +/* ========================== * + * Handle helpers + * ========================== */ + +INLINE struct entity_handle entity_nil_handle(void) +{ + 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) +{ + return a.gen == b.gen && a.idx == b.idx; +} + /* ========================== * * Nil * ========================== */ @@ -171,7 +194,9 @@ void entity_store_release(struct entity_store *store); void entity_store_copy_replace(struct entity_store *dest, struct entity_store *src); /* Entity */ -struct entity *entity_alloc(struct entity_store *store); +struct entity *entity_alloc_unlinked(struct entity_store *store); +struct entity *entity_alloc_top(struct entity_store *store); +struct entity *entity_alloc_child(struct entity *parent); void entity_release(struct entity_store *store, struct entity *entity); /* Xform */ @@ -188,5 +213,6 @@ struct entity *entity_find_first_match_all(struct entity_store *store, struct en /* Tree */ void entity_link(struct entity *parent, struct entity *child); +void entity_unlink(struct entity *ent); #endif diff --git a/src/game.c b/src/game.c index 1e6f2c9a..36ebe59c 100644 --- a/src/game.c +++ b/src/game.c @@ -173,7 +173,7 @@ INTERNAL void game_update(void) struct v2 size = V2(1, 1); f32 r = 0; - struct entity *e = entity_alloc(G.world.entity_store); + 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")); @@ -195,7 +195,7 @@ INTERNAL void game_update(void) /* Camera ent */ { - struct entity *e = entity_alloc(G.world.entity_store); + struct entity *e = entity_alloc_top(G.world.entity_store); e->xform = XFORM_IDENT; entity_enable_prop(e, ENTITY_PROP_CAMERA); diff --git a/src/user.c b/src/user.c index 67ffce5a..51e1b68d 100644 --- a/src/user.c +++ b/src/user.c @@ -755,6 +755,7 @@ INTERNAL void user_update(void) struct entity *ent = &entities_array.entities[entity_index]; if (!ent->valid) continue; + if (ent->root) continue; b32 skip_debug_draw = !G.debug_camera && ent == active_camera; b32 skip_debug_draw_transform = ent == active_camera; @@ -871,7 +872,7 @@ INTERNAL void user_update(void) /* Draw hierarchy */ struct entity *parent = entity_from_handle(G.world.entity_store, ent->parent); - if (parent->valid) { + if (parent->valid && !parent->root) { u32 color = RGBA_32_F(0.6, 0.6, 1, 0.75); f32 thickness = 5; f32 arrow_height = 15;