ecs work
This commit is contained in:
@@ -10,6 +10,9 @@ target_sources(${DUSK_TARGET_NAME}
|
|||||||
camera.c
|
camera.c
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Subdirectories
|
||||||
|
add_subdirectory(mesh)
|
||||||
|
|
||||||
if(DUSK_TARGET_SYSTEM STREQUAL "linux")
|
if(DUSK_TARGET_SYSTEM STREQUAL "linux")
|
||||||
target_compile_definitions(${DUSK_TARGET_NAME}
|
target_compile_definitions(${DUSK_TARGET_NAME}
|
||||||
PRIVATE
|
PRIVATE
|
||||||
|
@@ -14,6 +14,8 @@ typedef struct {
|
|||||||
|
|
||||||
extern camera_t CAMERA_DATA[ECS_ENTITY_COUNT_MAX];
|
extern camera_t CAMERA_DATA[ECS_ENTITY_COUNT_MAX];
|
||||||
extern ecscomponent_t CAMERA_COMPONENT;
|
extern ecscomponent_t CAMERA_COMPONENT;
|
||||||
|
extern ecsid_t CAMERA_MAIN;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the camera component.
|
* Initializes the camera component.
|
||||||
|
@@ -8,8 +8,17 @@
|
|||||||
#include "display/display.h"
|
#include "display/display.h"
|
||||||
#include "console/console.h"
|
#include "console/console.h"
|
||||||
|
|
||||||
|
#include "display/mesh/mesh.h"
|
||||||
|
|
||||||
display_t DISPLAY;
|
display_t DISPLAY;
|
||||||
|
|
||||||
|
mesh_t mesh;
|
||||||
|
meshvertex_t triangle[3] = {
|
||||||
|
{{255, 0, 0, 255}, {0.0f, 0.0f}, {0.0f, 1.0f}}, // Vertex 1
|
||||||
|
{{0, 255, 0, 255}, {1.0f, 0.0f}, {1.0f, 1.0f}}, // Vertex 2
|
||||||
|
{{0, 0, 255, 255}, {0.5f, 1.0f}, {0.5f, 0.0f}} // Vertex 3
|
||||||
|
};
|
||||||
|
|
||||||
errorret_t displayInit(void) {
|
errorret_t displayInit(void) {
|
||||||
#if DUSK_DISPLAY_SDL2
|
#if DUSK_DISPLAY_SDL2
|
||||||
if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER) != 0) {
|
if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER) != 0) {
|
||||||
@@ -53,6 +62,8 @@ errorret_t displayInit(void) {
|
|||||||
glEnableClientState(GL_VERTEX_ARRAY);
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
meshInit(&mesh, MESH_PRIMITIVE_TRIANGLES, 3, triangle);
|
||||||
|
|
||||||
// For now, we just return an OK error.
|
// For now, we just return an OK error.
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
@@ -74,11 +85,16 @@ errorret_t displayUpdate(void) {
|
|||||||
SDL_GL_SwapWindow(DISPLAY.window);
|
SDL_GL_SwapWindow(DISPLAY.window);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
meshDraw(&mesh, 0, -1);
|
||||||
|
|
||||||
|
|
||||||
// For now, we just return an OK error.
|
// For now, we just return an OK error.
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
errorret_t displayDispose(void) {
|
errorret_t displayDispose(void) {
|
||||||
|
meshDispose(&mesh);
|
||||||
|
|
||||||
#if DUSK_DISPLAY_SDL2
|
#if DUSK_DISPLAY_SDL2
|
||||||
if(DISPLAY.glContext) {
|
if(DISPLAY.glContext) {
|
||||||
SDL_GL_DeleteContext(DISPLAY.glContext);
|
SDL_GL_DeleteContext(DISPLAY.glContext);
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
// https://opensource.org/licenses/MIT
|
// https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "display/render.h"
|
#include "display/display.h"
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
#if DUSK_DISPLAY_SDL2
|
#if DUSK_DISPLAY_SDL2
|
||||||
|
@@ -6,60 +6,104 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ecscomponent.h"
|
#include "ecscomponent.h"
|
||||||
|
#include "ecssystem.h"
|
||||||
#include "assert/assert.h"
|
#include "assert/assert.h"
|
||||||
#include "util/memory.h"
|
#include "util/memory.h"
|
||||||
|
|
||||||
bool_t ecsComponentDataHas(const ecscomponent_t *cmp, const ecsid_t id) {
|
void ecsComponentInitialize(ecscomponent_t *cmp) {
|
||||||
assertNotNull(cmp, "Component pointer cannot be NULL.");
|
assertNotNull(cmp, "Component pointer cannot be NULL.");
|
||||||
assertTrue(id >= 0 && id < ECS_ENTITY_COUNT_MAX, "Invalid entity ID.");
|
|
||||||
assertTrue(
|
assertTrue(
|
||||||
(cmp->componentFlags & ECS_COMPONENT_FLAG_INITIALIZED) != 0,
|
ECS_SYSTEM.componentCount < ECS_SYSTEM_ECS_COMPONENTS_MAX,
|
||||||
"Component must be initialized before checking data."
|
"ECS Component count exceeded maximum limit."
|
||||||
);
|
);
|
||||||
|
|
||||||
|
memoryZero(cmp->data, sizeof(ecscomponent_t));
|
||||||
|
|
||||||
|
if(cmp->callbacks.init) cmp->callbacks.init();
|
||||||
|
cmp->componentFlags |= ECS_COMPONENT_FLAG_INITIALIZED;
|
||||||
|
|
||||||
|
ECS_SYSTEM.components[ECS_SYSTEM.componentCount++] = cmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool_t ecsComponentIsInitialized(const ecscomponent_t *cmp) {
|
||||||
|
assertNotNull(cmp, "Component pointer cannot be NULL.");
|
||||||
|
return (cmp->componentFlags & ECS_COMPONENT_FLAG_INITIALIZED) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool_t ecsComponentDataHas(const ecscomponent_t *cmp, const ecsid_t id) {
|
||||||
|
assertTrue(
|
||||||
|
id >= 0 && id < ECS_ENTITY_COUNT_MAX,
|
||||||
|
"Invalid entity ID."
|
||||||
|
);
|
||||||
|
if(!ecsComponentIsInitialized(cmp)) return false;
|
||||||
|
|
||||||
return cmp->entityFlags[id] & ECS_COMPONENT_ENTITY_FLAG_USED;
|
return cmp->entityFlags[id] & ECS_COMPONENT_ENTITY_FLAG_USED;
|
||||||
}
|
}
|
||||||
|
|
||||||
void * ecsComponentDataGet(const ecscomponent_t *cmp, const ecsid_t id) {
|
void * ecsComponentDataGet(const ecscomponent_t *cmp, const ecsid_t id) {
|
||||||
assertTrue(ecsComponentDataHas(cmp, id), "No data for entity ID.");
|
assertTrue(ecsComponentDataHas(cmp, id), "No data for entity ID.");
|
||||||
|
|
||||||
// Calculate the offset for the entity's data.
|
|
||||||
return (void *)((uint8_t *)cmp->data + (id * cmp->dataSize));
|
return (void *)((uint8_t *)cmp->data + (id * cmp->dataSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
void * ecsComponentDataAdd(ecscomponent_t *cmp, const ecsid_t id) {
|
void * ecsComponentDataAdd(ecscomponent_t *cmp, const ecsid_t id) {
|
||||||
assertNotNull(cmp, "Component pointer cannot be NULL.");
|
if(!ecsComponentIsInitialized(cmp)) ecsComponentInitialize(cmp);
|
||||||
|
|
||||||
assertTrue(id >= 0 && id < ECS_ENTITY_COUNT_MAX, "Invalid entity ID.");
|
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.");
|
assertFalse(ecsComponentDataHas(cmp, id), "Entity already has data.");
|
||||||
|
|
||||||
// Zero out the entity's data.
|
|
||||||
memoryZero(
|
memoryZero(
|
||||||
(uint8_t *)cmp->data + (id * cmp->dataSize),
|
(uint8_t *)cmp->data + (id * cmp->dataSize),
|
||||||
cmp->dataSize
|
cmp->dataSize
|
||||||
);
|
);
|
||||||
|
cmp->entityFlags[id] |= ECS_COMPONENT_ENTITY_FLAG_USED;
|
||||||
// Mark the entity as having data.
|
if(cmp->callbacks.entityAdd) cmp->callbacks.entityAdd(id);
|
||||||
cmp->entityFlags[id] = ECS_COMPONENT_ENTITY_FLAG_USED;
|
cmp->entitiesWithData[id] = id;
|
||||||
|
cmp->entitiesWithDataCount++;
|
||||||
|
|
||||||
return ecsComponentDataGet(cmp, id);
|
return ecsComponentDataGet(cmp, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ecsComponentDataRemove(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(
|
assertTrue(
|
||||||
(cmp->componentFlags & ECS_COMPONENT_FLAG_INITIALIZED) != 0,
|
ecsComponentIsInitialized(cmp), "Component was never initialized."
|
||||||
"Component must be initialized before removing data."
|
|
||||||
);
|
);
|
||||||
assertTrue(ecsComponentDataHas(cmp, id), "Entity does not have data.");
|
assertTrue(ecsComponentDataHas(cmp, id), "Entity does not have data.");
|
||||||
|
|
||||||
// Clear the entity's data flag.
|
|
||||||
cmp->entityFlags[id] = 0;
|
cmp->entityFlags[id] = 0;
|
||||||
|
|
||||||
|
// Remove entity from the entitiesWithData array by finding its index and
|
||||||
|
// shifting the rest of the array down. Use memoryCopy to avoid
|
||||||
|
// unnecessary loops.
|
||||||
|
uint32_t index = 0;
|
||||||
|
for(; index < cmp->entitiesWithDataCount; index++) {
|
||||||
|
if(cmp->entitiesWithData[index] == id) break;
|
||||||
|
}
|
||||||
|
assertTrue(
|
||||||
|
index < cmp->entitiesWithDataCount,
|
||||||
|
"Entity not found in entitiesWithData?"
|
||||||
|
);
|
||||||
|
memoryCopy(
|
||||||
|
&cmp->entitiesWithData[index],
|
||||||
|
&cmp->entitiesWithData[index + 1],
|
||||||
|
sizeof(ecsid_t) * (cmp->entitiesWithDataCount - index - 1)
|
||||||
|
);
|
||||||
|
|
||||||
|
if(cmp->callbacks.entityRemove) cmp->callbacks.entityRemove(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ecsComponentDispose(ecscomponent_t *cmp) {
|
||||||
|
assertNotNull(cmp, "Component pointer cannot be NULL.");
|
||||||
|
assertTrue(
|
||||||
|
ecsComponentIsInitialized(cmp),
|
||||||
|
"Component was never initialized."
|
||||||
|
);
|
||||||
|
|
||||||
|
for(uint32_t i = 0; i < cmp->entitiesWithDataCount; i++) {
|
||||||
|
if(cmp->callbacks.entityRemove)
|
||||||
|
cmp->callbacks.entityRemove(cmp->entitiesWithData[i]);
|
||||||
|
}
|
||||||
|
memoryZero(cmp->entityFlags, sizeof(cmp->entityFlags));
|
||||||
|
cmp->entitiesWithDataCount = 0;
|
||||||
|
cmp->componentFlags = 0;
|
||||||
}
|
}
|
@@ -12,30 +12,53 @@
|
|||||||
|
|
||||||
#define ECS_COMPONENT_FLAG_INITIALIZED (1 << 0)
|
#define ECS_COMPONENT_FLAG_INITIALIZED (1 << 0)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
void (*init)();
|
||||||
|
void (*entityAdd)(const ecsid_t id);
|
||||||
|
void (*entityRemove)(const ecsid_t id);
|
||||||
|
} ecscomponentcallbacks_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
void *data;
|
void *data;
|
||||||
size_t dataSize;
|
size_t dataSize;
|
||||||
uint8_t entityFlags[ECS_ENTITY_COUNT_MAX];
|
uint8_t entityFlags[ECS_ENTITY_COUNT_MAX];
|
||||||
uint8_t componentFlags;
|
uint8_t componentFlags;
|
||||||
|
ecscomponentcallbacks_t callbacks;
|
||||||
|
|
||||||
void (*componentInit)();
|
ecsid_t entitiesWithData[ECS_ENTITY_COUNT_MAX];
|
||||||
|
uint32_t entitiesWithDataCount;;
|
||||||
} ecscomponent_t;
|
} ecscomponent_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes an ECS Component.
|
* Initializes an ECS Component.
|
||||||
*
|
*
|
||||||
* @param dPointer 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.
|
* @param cbs Callback functions for the component.
|
||||||
*/
|
*/
|
||||||
#define ecsComponentInit(dPointer, cInit) \
|
#define ecsComponentInit(dPointer, cbs) \
|
||||||
(ecscomponent_t){ \
|
(ecscomponent_t){ \
|
||||||
.data = dPointer, \
|
.data = dPointer, \
|
||||||
.dataSize = sizeof(*dPointer), \
|
.dataSize = sizeof(*dPointer), \
|
||||||
.entityFlags = 0, \
|
.entityFlags = 0, \
|
||||||
.componentFlags = 0, \
|
.componentFlags = 0, \
|
||||||
.componentInit = cInit \
|
.callbacks = (cbs) \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes an ECS Component.
|
||||||
|
*
|
||||||
|
* @param cmp Pointer to the ecscomponent_t to initialize.
|
||||||
|
*/
|
||||||
|
void ecsComponentInitialize(ecscomponent_t *cmp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the component is initialized.
|
||||||
|
*
|
||||||
|
* @param cmp Pointer to the ecscomponent_t.
|
||||||
|
* @return True if the component is initialized, false otherwise.
|
||||||
|
*/
|
||||||
|
bool_t ecsComponentIsInitialized(const ecscomponent_t *cmp);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the component has data for a specific entity.
|
* Checks if the component has data for a specific entity.
|
||||||
*
|
*
|
||||||
@@ -69,3 +92,10 @@ void * ecsComponentDataAdd(ecscomponent_t *cmp, const ecsid_t id);
|
|||||||
* @param id The ID of the entity to remove data for.
|
* @param id The ID of the entity to remove data for.
|
||||||
*/
|
*/
|
||||||
void ecsComponentDataRemove(ecscomponent_t *cmp, const ecsid_t id);
|
void ecsComponentDataRemove(ecscomponent_t *cmp, const ecsid_t id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disposes the component, freeing any resources it holds.
|
||||||
|
*
|
||||||
|
* @param cmp Pointer to the ecscomponent_t to dispose.
|
||||||
|
*/
|
||||||
|
void ecsComponentDispose(ecscomponent_t *cmp);
|
@@ -57,3 +57,13 @@ void ecsEntityRemove(const ecsid_t id) {
|
|||||||
"Available count exceeded maximum limit"
|
"Available count exceeded maximum limit"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ecsSystemDispose() {
|
||||||
|
for(uint32_t i = 0; i < ECS_SYSTEM.componentCount; i++) {
|
||||||
|
ecscomponent_t *cmp = ECS_SYSTEM.components[i];
|
||||||
|
ecsComponentDispose(cmp);
|
||||||
|
assertTrue(cmp->entitiesWithDataCount == 0, "Component still has data.");
|
||||||
|
}
|
||||||
|
|
||||||
|
memoryZero(&ECS_SYSTEM, sizeof(ecssystem_t));
|
||||||
|
}
|
@@ -7,6 +7,9 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "ecsentity.h"
|
#include "ecsentity.h"
|
||||||
|
#include "ecscomponent.h"
|
||||||
|
|
||||||
|
#define ECS_SYSTEM_ECS_COMPONENTS_MAX 64
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
ecsentity_t entities[ECS_ENTITY_COUNT_MAX];
|
ecsentity_t entities[ECS_ENTITY_COUNT_MAX];
|
||||||
@@ -14,6 +17,9 @@ typedef struct {
|
|||||||
ecsentity_t *available[ECS_ENTITY_COUNT_MAX];
|
ecsentity_t *available[ECS_ENTITY_COUNT_MAX];
|
||||||
uint32_t availableCount;
|
uint32_t availableCount;
|
||||||
|
|
||||||
|
ecscomponent_t *components[ECS_SYSTEM_ECS_COMPONENTS_MAX];
|
||||||
|
uint32_t componentCount;
|
||||||
|
|
||||||
ecsid_t root;
|
ecsid_t root;
|
||||||
} ecssystem_t;
|
} ecssystem_t;
|
||||||
|
|
||||||
@@ -39,3 +45,8 @@ ecsid_t ecsEntityAdd();
|
|||||||
* @param id The ID of the entity to destroy.
|
* @param id The ID of the entity to destroy.
|
||||||
*/
|
*/
|
||||||
void ecsEntityRemove(const ecsid_t id);
|
void ecsEntityRemove(const ecsid_t id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispose the ECS system, freeing all resources.
|
||||||
|
*/
|
||||||
|
void ecsSystemDispose();
|
@@ -25,7 +25,6 @@ errorret_t engineInit(void) {
|
|||||||
timeInit();
|
timeInit();
|
||||||
consoleInit();
|
consoleInit();
|
||||||
ecsSystemInit();
|
ecsSystemInit();
|
||||||
sceneTreeInit();
|
|
||||||
errorChain(displayInit());
|
errorChain(displayInit());
|
||||||
|
|
||||||
ecsid_t sceneTest = sceneTestAdd();
|
ecsid_t sceneTest = sceneTestAdd();
|
||||||
@@ -43,6 +42,7 @@ errorret_t engineUpdate(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
errorret_t engineDispose(void) {
|
errorret_t engineDispose(void) {
|
||||||
|
ecsSystemDispose();
|
||||||
errorChain(displayDispose());
|
errorChain(displayDispose());
|
||||||
consoleDispose();
|
consoleDispose();
|
||||||
|
|
||||||
|
@@ -10,7 +10,11 @@
|
|||||||
scenetreenode_t SCENE_TREE_DATA[ECS_ENTITY_COUNT_MAX] = { 0 };
|
scenetreenode_t SCENE_TREE_DATA[ECS_ENTITY_COUNT_MAX] = { 0 };
|
||||||
ecscomponent_t SCENE_TREE_COMPONENT = ecsComponentInit(
|
ecscomponent_t SCENE_TREE_COMPONENT = ecsComponentInit(
|
||||||
SCENE_TREE_DATA,
|
SCENE_TREE_DATA,
|
||||||
sceneTreeInit
|
((ecscomponentcallbacks_t){
|
||||||
|
.init = sceneTreeInit,
|
||||||
|
.entityAdd = sceneTreeEntityAdded,
|
||||||
|
.entityRemove = sceneTreeEntityRemoved
|
||||||
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
void sceneTreeInit(void) {
|
void sceneTreeInit(void) {
|
||||||
@@ -22,12 +26,12 @@ void sceneTreeInit(void) {
|
|||||||
|
|
||||||
ecsid_t sceneTreeParentGet(const ecsid_t child) {
|
ecsid_t sceneTreeParentGet(const ecsid_t child) {
|
||||||
assertTrue(child >= 0 && child < ECS_ENTITY_COUNT_MAX, "Invalid child ID");
|
assertTrue(child >= 0 && child < ECS_ENTITY_COUNT_MAX, "Invalid child ID");
|
||||||
|
if(!ecsComponentDataHas(&SCENE_TREE_COMPONENT, child)) return -1;
|
||||||
return SCENE_TREE_DATA[child].parent;
|
return SCENE_TREE_DATA[child].parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t sceneTreeChildGetAll(const ecsid_t id, ecsid_t *children) {
|
uint8_t sceneTreeChildGetAll(const ecsid_t id, ecsid_t *children) {
|
||||||
assertTrue(id >= 0 && id < ECS_ENTITY_COUNT_MAX, "Invalid parent ID");
|
if(!ecsComponentDataHas(&SCENE_TREE_COMPONENT, id)) return 0;
|
||||||
|
|
||||||
if(children == NULL) return SCENE_TREE_DATA[id].childCount;
|
if(children == NULL) return SCENE_TREE_DATA[id].childCount;
|
||||||
|
|
||||||
memoryCopy(
|
memoryCopy(
|
||||||
@@ -40,17 +44,12 @@ uint8_t sceneTreeChildGetAll(const ecsid_t id, ecsid_t *children) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void sceneTreeChildAdd(const ecsid_t parent, const ecsid_t child) {
|
void sceneTreeChildAdd(const ecsid_t parent, const ecsid_t child) {
|
||||||
assertTrue(parent >= 0 && parent < ECS_ENTITY_COUNT_MAX, "Invalid parent ID");
|
if(!ecsComponentDataHas(&SCENE_TREE_COMPONENT, parent)) {
|
||||||
assertTrue(child >= 0 && child < ECS_ENTITY_COUNT_MAX, "Invalid child ID");
|
ecsComponentDataAdd(&SCENE_TREE_COMPONENT, parent);
|
||||||
assertTrue(parent != child, "Child cannot be a child of itself.");
|
}
|
||||||
assertFalse(
|
if(!ecsComponentDataHas(&SCENE_TREE_COMPONENT, child)) {
|
||||||
sceneTreeChildInTree(parent, child),
|
ecsComponentDataAdd(&SCENE_TREE_COMPONENT, child);
|
||||||
"Child is already in the parent's tree"
|
}
|
||||||
);
|
|
||||||
assertFalse(
|
|
||||||
sceneTreeChildInTree(child, parent),
|
|
||||||
"Child cannot be a deep child of itself."
|
|
||||||
);
|
|
||||||
|
|
||||||
scenetreenode_t *parentNode = &SCENE_TREE_DATA[parent];
|
scenetreenode_t *parentNode = &SCENE_TREE_DATA[parent];
|
||||||
assertTrue(parentNode->childCount < SCENE_ITEM_CHILD_MAX, "Parent full.");
|
assertTrue(parentNode->childCount < SCENE_ITEM_CHILD_MAX, "Parent full.");
|
||||||
@@ -67,9 +66,14 @@ void sceneTreeChildRemove(
|
|||||||
const ecsid_t parent,
|
const ecsid_t parent,
|
||||||
const ecsid_t child
|
const ecsid_t child
|
||||||
) {
|
) {
|
||||||
assertTrue(parent >= 0 && parent < ECS_ENTITY_COUNT_MAX, "Invalid parent ID");
|
assertTrue(
|
||||||
assertTrue(child >= 0 && child < ECS_ENTITY_COUNT_MAX, "Invalid child ID");
|
ecsComponentDataHas(&SCENE_TREE_COMPONENT, parent),
|
||||||
assertTrue(parent != child, "Child cannot be a child of itself.");
|
"SCENE TREE ECS lacks Parent."
|
||||||
|
);
|
||||||
|
assertTrue(
|
||||||
|
ecsComponentDataHas(&SCENE_TREE_COMPONENT, child),
|
||||||
|
"SCENE TREE ECS lacks Child."
|
||||||
|
);
|
||||||
|
|
||||||
scenetreenode_t *childNode = &SCENE_TREE_DATA[child];
|
scenetreenode_t *childNode = &SCENE_TREE_DATA[child];
|
||||||
scenetreenode_t *parentNode = &SCENE_TREE_DATA[parent];
|
scenetreenode_t *parentNode = &SCENE_TREE_DATA[parent];
|
||||||
@@ -90,25 +94,48 @@ void sceneTreeChildRemove(
|
|||||||
|
|
||||||
// Clear child's parent
|
// Clear child's parent
|
||||||
childNode->parent = -1;
|
childNode->parent = -1;
|
||||||
|
|
||||||
|
if(childNode->childCount == 0) {
|
||||||
|
ecsComponentDataRemove(&SCENE_TREE_COMPONENT, child);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(parentNode->childCount == 0) {
|
||||||
|
ecsComponentDataRemove(&SCENE_TREE_COMPONENT, parent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void sceneTreeChildRemoveAll(const ecsid_t parent) {
|
void sceneTreeChildRemoveAll(const ecsid_t parent) {
|
||||||
assertTrue(parent >= 0 && parent < ECS_ENTITY_COUNT_MAX, "Invalid parent ID");
|
assertTrue(
|
||||||
|
ecsComponentDataHas(&SCENE_TREE_COMPONENT, parent),
|
||||||
|
"SCENE TREE ECS lacks Parent."
|
||||||
|
);
|
||||||
|
|
||||||
scenetreenode_t *parentNode = &SCENE_TREE_DATA[parent];
|
scenetreenode_t *parentNode = &SCENE_TREE_DATA[parent];
|
||||||
for(uint8_t i = 0; i < parentNode->childCount; i++) {
|
for(uint8_t i = 0; i < parentNode->childCount; i++) {
|
||||||
ecsid_t child = parentNode->children[i];
|
ecsid_t child = parentNode->children[i];
|
||||||
SCENE_TREE_DATA[child].parent = -1;
|
SCENE_TREE_DATA[child].parent = -1;
|
||||||
|
|
||||||
|
if(SCENE_TREE_DATA[child].childCount == 0) {
|
||||||
|
ecsComponentDataRemove(&SCENE_TREE_COMPONENT, child);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset child count
|
ecsComponentDataRemove(&SCENE_TREE_COMPONENT, parent);
|
||||||
parentNode->childCount = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool_t sceneTreeChildInTree(
|
bool_t sceneTreeChildInTree(
|
||||||
const ecsid_t parent,
|
const ecsid_t parent,
|
||||||
const ecsid_t child
|
const ecsid_t child
|
||||||
) {
|
) {
|
||||||
|
assertTrue(
|
||||||
|
ecsComponentDataHas(&SCENE_TREE_COMPONENT, parent),
|
||||||
|
"SCENE TREE ECS lacks Parent."
|
||||||
|
);
|
||||||
|
assertTrue(
|
||||||
|
ecsComponentDataHas(&SCENE_TREE_COMPONENT, child),
|
||||||
|
"SCENE TREE ECS lacks Child."
|
||||||
|
);
|
||||||
|
|
||||||
assertTrue(parent >= 0 && parent < ECS_ENTITY_COUNT_MAX, "Invalid parent ID");
|
assertTrue(parent >= 0 && parent < ECS_ENTITY_COUNT_MAX, "Invalid parent ID");
|
||||||
assertTrue(child >= 0 && child < ECS_ENTITY_COUNT_MAX, "Invalid child ID");
|
assertTrue(child >= 0 && child < ECS_ENTITY_COUNT_MAX, "Invalid child ID");
|
||||||
assertTrue(parent != child, "Child cannot be a child of itself.");
|
assertTrue(parent != child, "Child cannot be a child of itself.");
|
||||||
@@ -122,3 +149,12 @@ bool_t sceneTreeChildInTree(
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sceneTreeEntityAdded(const ecsid_t id) {
|
||||||
|
SCENE_TREE_DATA[id].parent = -1; // Default parent to -1 (no parent)
|
||||||
|
}
|
||||||
|
|
||||||
|
void sceneTreeEntityRemoved(const ecsid_t id) {
|
||||||
|
if(SCENE_TREE_DATA[id].parent == -1) return;
|
||||||
|
sceneTreeChildRemove(SCENE_TREE_DATA[id].parent, id);
|
||||||
|
}
|
@@ -83,3 +83,19 @@ void sceneTreeChildRemoveAll(const ecsid_t parent);
|
|||||||
* @return True if the child is in the parent's children, false otherwise.
|
* @return True if the child is in the parent's children, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool_t sceneTreeChildInTree(const ecsid_t parent, const ecsid_t child);
|
bool_t sceneTreeChildInTree(const ecsid_t parent, const ecsid_t child);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback for when an entity is added to the ECS.
|
||||||
|
* This will initialize the scene tree data for the entity.
|
||||||
|
*
|
||||||
|
* @param id The ID of the entity being added.
|
||||||
|
*/
|
||||||
|
void sceneTreeEntityAdded(const ecsid_t id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback for when an entity is removed from the ECS.
|
||||||
|
* This will clean up any scene tree data associated with the entity.
|
||||||
|
*
|
||||||
|
* @param id The ID of the entity being removed.
|
||||||
|
*/
|
||||||
|
void sceneTreeEntityRemoved(const ecsid_t id);
|
Reference in New Issue
Block a user