diff --git a/src/display/camera.c b/src/display/camera.c index c7a19e1..45d7c01 100644 --- a/src/display/camera.c +++ b/src/display/camera.c @@ -8,4 +8,4 @@ #include "camera.h" camera_t CAMERA_DATA[ECS_ENTITY_COUNT_MAX] = { 0 }; -ecscomponent_t CAMERA_COMPONENT = ecsComponentInit(CAMERA_DATA); +ecscomponent_t CAMERA_COMPONENT = ecsComponentInit(CAMERA_DATA, NULL); diff --git a/src/display/camera.h b/src/display/camera.h index 10a8f23..3e85015 100644 --- a/src/display/camera.h +++ b/src/display/camera.h @@ -20,7 +20,7 @@ extern ecscomponent_t CAMERA_COMPONENT; * * @param id The ID of the entity to initialize the camera for. */ -#define cameraAdd(id) ecsComponentDataAdd(&CAMERA_COMPONENT, id) +#define cameraAdd(id) ((camera_t*)ecsComponentDataAdd(&CAMERA_COMPONENT, id)) /** * Gets the camera component data for a specific entity. @@ -28,7 +28,7 @@ extern ecscomponent_t CAMERA_COMPONENT; * @param id The ID of the entity to get the camera data for. * @return Pointer to the camera data for the entity. */ -#define cameraGet(id) ecsComponentDataGet(&CAMERA_COMPONENT, id) +#define cameraGet(id) ((camera_t*)ecsComponentDataGet(&CAMERA_COMPONENT, id)) /** * Checks if the camera component has data for a specific entity. diff --git a/src/ecs/CMakeLists.txt b/src/ecs/CMakeLists.txt index c97bd8f..18a4ba5 100644 --- a/src/ecs/CMakeLists.txt +++ b/src/ecs/CMakeLists.txt @@ -7,4 +7,5 @@ target_sources(${DUSK_TARGET_NAME} PRIVATE ecssystem.c + ecscomponent.c ) \ No newline at end of file diff --git a/src/ecs/ecscomponent.c b/src/ecs/ecscomponent.c index dbfee10..5d49f1c 100644 --- a/src/ecs/ecscomponent.c +++ b/src/ecs/ecscomponent.c @@ -12,8 +12,12 @@ bool_t ecsComponentDataHas(const ecscomponent_t *cmp, const ecsid_t id) { assertNotNull(cmp, "Component pointer cannot be NULL."); assertTrue(id >= 0 && id < ECS_ENTITY_COUNT_MAX, "Invalid entity ID."); + assertTrue( + (cmp->componentFlags & ECS_COMPONENT_FLAG_INITIALIZED) != 0, + "Component must be initialized before checking data." + ); - return cmp->entityFlags[id] != 0; + return cmp->entityFlags[id] & ECS_COMPONENT_ENTITY_FLAG_USED; } void * ecsComponentDataGet(const ecscomponent_t *cmp, const ecsid_t id) { @@ -23,9 +27,16 @@ void * ecsComponentDataGet(const ecscomponent_t *cmp, const ecsid_t id) { return (void *)((uint8_t *)cmp->data + (id * cmp->dataSize)); } -void * ecsComponentDataAdd(const ecscomponent_t *cmp, const ecsid_t id) { +void * ecsComponentDataAdd(ecscomponent_t *cmp, const ecsid_t id) { assertNotNull(cmp, "Component pointer cannot be NULL."); assertTrue(id >= 0 && id < ECS_ENTITY_COUNT_MAX, "Invalid entity ID."); + + // Initialize the component if it hasn't been initialized yet. + if((cmp->componentFlags & ECS_COMPONENT_FLAG_INITIALIZED) == 0) { + if(cmp->componentInit) cmp->componentInit(); + cmp->componentFlags |= ECS_COMPONENT_FLAG_INITIALIZED; + } + assertFalse(ecsComponentDataHas(cmp, id), "Entity already has data."); // Zero out the entity's data. @@ -35,7 +46,7 @@ void * ecsComponentDataAdd(const ecscomponent_t *cmp, const ecsid_t id) { ); // Mark the entity as having data. - cmp->entityFlags[id] = ECS_COMPONENT_FLAG_USED; + cmp->entityFlags[id] = ECS_COMPONENT_ENTITY_FLAG_USED; return ecsComponentDataGet(cmp, id); } @@ -43,6 +54,10 @@ void * ecsComponentDataAdd(const ecscomponent_t *cmp, const ecsid_t id) { void ecsComponentDataRemove(ecscomponent_t *cmp, const ecsid_t id) { assertNotNull(cmp, "Component pointer cannot be NULL."); assertTrue(id >= 0 && id < ECS_ENTITY_COUNT_MAX, "Invalid entity ID."); + assertTrue( + (cmp->componentFlags & ECS_COMPONENT_FLAG_INITIALIZED) != 0, + "Component must be initialized before removing data." + ); assertTrue(ecsComponentDataHas(cmp, id), "Entity does not have data."); // Clear the entity's data flag. diff --git a/src/ecs/ecscomponent.h b/src/ecs/ecscomponent.h index a80ef67..7963b39 100644 --- a/src/ecs/ecscomponent.h +++ b/src/ecs/ecscomponent.h @@ -8,25 +8,33 @@ #pragma once #include "ecs/ecsentity.h" -#define ECS_COMPONENT_FLAG_USED (1 << 0) +#define ECS_COMPONENT_ENTITY_FLAG_USED (1 << 0) + +#define ECS_COMPONENT_FLAG_INITIALIZED (1 << 0) typedef struct { void *data; size_t dataSize; uint8_t entityFlags[ECS_ENTITY_COUNT_MAX]; + uint8_t componentFlags; + + void (*componentInit)(); } ecscomponent_t; /** * Initializes an ECS Component. * - * @param dataPointer Pointer to the data that the component owns. + * @param dPointer Pointer to the data that the component owns. + * @param cInit Function to call to initialize the component. */ -#define ecsComponentInit(dataPointer) \ +#define ecsComponentInit(dPointer, cInit) \ (ecscomponent_t){ \ - .data = dataPointer, \ - .dataSize = (sizeof(*dataPointer) / ECS_ENTITY_COUNT_MAX), \ - .entityFlags = {0} \ - }; + .data = dPointer, \ + .dataSize = sizeof(*dPointer), \ + .entityFlags = 0, \ + .componentFlags = 0, \ + .componentInit = cInit \ + } /** * Checks if the component has data for a specific entity. @@ -52,7 +60,7 @@ void * ecsComponentDataGet(const ecscomponent_t *cmp, const ecsid_t id); * @param cmp Pointer to the ecscomponent_t. * @param id The ID of the entity to add data for. */ -void * ecsComponentDataAdd(const ecscomponent_t *cmp, const ecsid_t id); +void * ecsComponentDataAdd(ecscomponent_t *cmp, const ecsid_t id); /** * Removes data for a specific entity in the component. diff --git a/src/engine/engine.c b/src/engine/engine.c index 5e5c1f1..bc2db00 100644 --- a/src/engine/engine.c +++ b/src/engine/engine.c @@ -13,6 +13,8 @@ #include "ecs/ecssystem.h" #include "scene/scenetree.h" +#include "scene/test/scenetest.h" + engine_t ENGINE; errorret_t engineInit(void) { @@ -26,6 +28,9 @@ errorret_t engineInit(void) { sceneTreeInit(); errorChain(displayInit()); + ecsid_t sceneTest = sceneTestAdd(); + sceneTreeChildAdd(ECS_SYSTEM.root, sceneTest); + errorOk(); } diff --git a/src/scene/scenetree.c b/src/scene/scenetree.c index 27f5844..4357e5a 100644 --- a/src/scene/scenetree.c +++ b/src/scene/scenetree.c @@ -7,29 +7,36 @@ #include "util/memory.h" #include "assert/assert.h" -scenetree_t SCENE_TREE; +scenetreenode_t SCENE_TREE_DATA[ECS_ENTITY_COUNT_MAX] = { 0 }; +ecscomponent_t SCENE_TREE_COMPONENT = ecsComponentInit( + SCENE_TREE_DATA, + sceneTreeInit +); void sceneTreeInit(void) { - memoryZero(&SCENE_TREE, sizeof(scenetree_t)); - // Default all items to have no parent for (ecsid_t i = 0; i < ECS_ENTITY_COUNT_MAX; i++) { - SCENE_TREE.items[i].parent = -1; + SCENE_TREE_DATA[i].parent = -1; } } ecsid_t sceneTreeParentGet(const ecsid_t child) { assertTrue(child >= 0 && child < ECS_ENTITY_COUNT_MAX, "Invalid child ID"); - return SCENE_TREE.items[child].parent; + return SCENE_TREE_DATA[child].parent; } uint8_t sceneTreeChildGetAll(const ecsid_t id, ecsid_t *children) { assertTrue(id >= 0 && id < ECS_ENTITY_COUNT_MAX, "Invalid parent ID"); + + if(children == NULL) return SCENE_TREE_DATA[id].childCount; - const scenetreenode_t *node = &SCENE_TREE.items[id]; - if(children == NULL) return node->childCount; - - return node->childCount; + memoryCopy( + children, + SCENE_TREE_DATA[id].children, + sizeof(ecsid_t) * SCENE_TREE_DATA[id].childCount + ); + + return SCENE_TREE_DATA[id].childCount; } void sceneTreeChildAdd(const ecsid_t parent, const ecsid_t child) { @@ -45,7 +52,7 @@ void sceneTreeChildAdd(const ecsid_t parent, const ecsid_t child) { "Child cannot be a deep child of itself." ); - scenetreenode_t *parentNode = &SCENE_TREE.items[parent]; + scenetreenode_t *parentNode = &SCENE_TREE_DATA[parent]; assertTrue(parentNode->childCount < SCENE_ITEM_CHILD_MAX, "Parent full."); // Add child to parent's children array @@ -53,7 +60,7 @@ void sceneTreeChildAdd(const ecsid_t parent, const ecsid_t child) { parentNode->childCount++; // Set child's parent - SCENE_TREE.items[child].parent = parent; + SCENE_TREE_DATA[child].parent = parent; } void sceneTreeChildRemove( @@ -64,8 +71,8 @@ void sceneTreeChildRemove( assertTrue(child >= 0 && child < ECS_ENTITY_COUNT_MAX, "Invalid child ID"); assertTrue(parent != child, "Child cannot be a child of itself."); - scenetreenode_t *childNode = &SCENE_TREE.items[child]; - scenetreenode_t *parentNode = &SCENE_TREE.items[parent]; + scenetreenode_t *childNode = &SCENE_TREE_DATA[child]; + scenetreenode_t *parentNode = &SCENE_TREE_DATA[parent]; assertTrue(childNode->parent == parent, "Child does not belong to parent"); assertTrue(parentNode->childCount > 0, "Parent has no children"); @@ -88,10 +95,10 @@ void sceneTreeChildRemove( void sceneTreeChildRemoveAll(const ecsid_t parent) { assertTrue(parent >= 0 && parent < ECS_ENTITY_COUNT_MAX, "Invalid parent ID"); - scenetreenode_t *parentNode = &SCENE_TREE.items[parent]; + scenetreenode_t *parentNode = &SCENE_TREE_DATA[parent]; for(uint8_t i = 0; i < parentNode->childCount; i++) { ecsid_t child = parentNode->children[i]; - SCENE_TREE.items[child].parent = -1; + SCENE_TREE_DATA[child].parent = -1; } // Reset child count @@ -106,11 +113,11 @@ bool_t sceneTreeChildInTree( assertTrue(child >= 0 && child < ECS_ENTITY_COUNT_MAX, "Invalid child ID"); assertTrue(parent != child, "Child cannot be a child of itself."); - scenetreenode_t *childNode = &SCENE_TREE.items[child]; + scenetreenode_t *childNode = &SCENE_TREE_DATA[child]; while(childNode) { if(childNode->parent == parent) return true; if(childNode->parent == -1) break; // No parent means we've reached the root - childNode = &SCENE_TREE.items[childNode->parent]; + childNode = &SCENE_TREE_DATA[childNode->parent]; } return false; diff --git a/src/scene/scenetree.h b/src/scene/scenetree.h index e0296d9..6c9f965 100644 --- a/src/scene/scenetree.h +++ b/src/scene/scenetree.h @@ -6,7 +6,7 @@ */ #pragma once -#include "ecs/ecsentity.h" +#include "ecs/ecscomponent.h" #define SCENE_ITEM_CHILD_MAX 16 @@ -16,11 +16,8 @@ typedef struct { ecsid_t parent; } scenetreenode_t; -typedef struct scene_s { - scenetreenode_t items[ECS_ENTITY_COUNT_MAX]; -} scenetree_t; - -extern scenetree_t SCENE_TREE; +extern scenetreenode_t SCENE_TREE_DATA[ECS_ENTITY_COUNT_MAX]; +extern ecscomponent_t SCENE_TREE_COMPONENT; /** * Initialize the scene tree.