From 94ad64675d5deb738acf579b5ab9db97697ba96b Mon Sep 17 00:00:00 2001 From: Dominic Masters Date: Fri, 22 Aug 2025 12:40:18 -0500 Subject: [PATCH] cleaned more stuff --- archive/dusksdl2/display/mesh/CMakeLists.txt | 1 + archive/dusksdl2/display/mesh/meshrenderer.c | 27 ++++ archive/dusksdl2/display/mesh/meshrenderer.h | 33 ++++ src/CMakeLists.txt | 3 + src/display/camera.c | 74 ++++++++- src/display/camera.h | 65 +++++--- src/display/color.h | 106 ++++++++++++ src/display/display.c | 16 +- src/dusk.h | 1 + src/engine/engine.c | 4 +- src/scene/CMakeLists.txt | 2 +- src/scene/node.c | 127 +++++++++++++++ src/scene/{scenetree.h => node.h} | 47 +++--- src/scene/scenetree.c | 160 ------------------- src/scene/test/scenetest.c | 12 +- 15 files changed, 467 insertions(+), 211 deletions(-) create mode 100644 archive/dusksdl2/display/mesh/meshrenderer.c create mode 100644 archive/dusksdl2/display/mesh/meshrenderer.h create mode 100644 src/display/color.h create mode 100644 src/scene/node.c rename src/scene/{scenetree.h => node.h} (70%) delete mode 100644 src/scene/scenetree.c diff --git a/archive/dusksdl2/display/mesh/CMakeLists.txt b/archive/dusksdl2/display/mesh/CMakeLists.txt index 9befe9a..45708f9 100644 --- a/archive/dusksdl2/display/mesh/CMakeLists.txt +++ b/archive/dusksdl2/display/mesh/CMakeLists.txt @@ -8,4 +8,5 @@ target_sources(${DUSK_TARGET_NAME} PRIVATE mesh.c quad.c + meshrenderer.c ) \ No newline at end of file diff --git a/archive/dusksdl2/display/mesh/meshrenderer.c b/archive/dusksdl2/display/mesh/meshrenderer.c new file mode 100644 index 0000000..7ca5a32 --- /dev/null +++ b/archive/dusksdl2/display/mesh/meshrenderer.c @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include "meshrenderer.h" + +meshrenderer_t MESH_RENDERER_DATA[ECS_ENTITY_COUNT_MAX] = { 0 }; +ecscomponent_t MESH_RENDERER_COMPONENT = ecsComponentInit( + MESH_RENDERER_DATA, + ((ecscomponentcallbacks_t){ + .init = NULL, + .entityAdd = NULL, + .entityRemove = NULL + }) +); + +void meshRendererDraw(const ecsid_t id) { + if (!meshRendererHas(id)) return; + + meshrenderer_t *renderer = meshRendererGet(id); + if (!renderer || !renderer->mesh) return; + + meshDraw(renderer->mesh, 0, -1); +} \ No newline at end of file diff --git a/archive/dusksdl2/display/mesh/meshrenderer.h b/archive/dusksdl2/display/mesh/meshrenderer.h new file mode 100644 index 0000000..73a55a9 --- /dev/null +++ b/archive/dusksdl2/display/mesh/meshrenderer.h @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "ecs/ecscomponent.h" +#include "display/mesh/mesh.h" + +typedef struct { + mesh_t *mesh; +} meshrenderer_t; + +extern meshrenderer_t MESH_RENDERER_DATA[ECS_ENTITY_COUNT_MAX]; +extern ecscomponent_t MESH_RENDERER_COMPONENT; + +#define meshRendererAdd(id) \ + ((meshrenderer_t*)ecsComponentDataAdd(&MESH_RENDERER_COMPONENT, id)) +#define meshRendererGet(id) \ + ((meshrenderer_t*)ecsComponentDataGet(&MESH_RENDERER_COMPONENT, id)) +#define meshRendererHas(id) \ + (ecsComponentDataHas(&MESH_RENDERER_COMPONENT, id)) +#define meshRendererRemove(id) \ + ecsComponentDataRemove(&MESH_RENDERER_COMPONENT, id) + +/** + * Draw the mesh for the given entity. + * + * @param id The ID of the entity with the mesh renderer component. + */ +void meshRendererDraw(const ecsid_t id); \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8bb17b3..d58be8c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,10 +3,13 @@ # This software is released under the MIT License. # https://opensource.org/licenses/MIT +find_package(cglm REQUIRED) + # Libs target_link_libraries(${DUSK_TARGET_NAME} PUBLIC m + cglm ) # Includes diff --git a/src/display/camera.c b/src/display/camera.c index 45d7c01..3fddce8 100644 --- a/src/display/camera.c +++ b/src/display/camera.c @@ -6,6 +6,78 @@ */ #include "camera.h" +#include "display/display.h" +#include "assert/assert.h" camera_t CAMERA_DATA[ECS_ENTITY_COUNT_MAX] = { 0 }; -ecscomponent_t CAMERA_COMPONENT = ecsComponentInit(CAMERA_DATA, NULL); +ecscomponent_t CAMERA_COMPONENT = ecsComponentInit( + CAMERA_DATA, + ((ecscomponentcallbacks_t){ + .init = NULL, + .entityAdd = cameraEntityAdded + }) +); + +ecsid_t CAMERA_MAIN = -1; + +void cameraEntityAdded(const ecsid_t id) { + if(CAMERA_MAIN == -1) CAMERA_MAIN = id; + + camera_t *cam = cameraGet(id); + cam->type = CAMERA_TYPE_ORTHOGRAPHIC; + cam->perspective.fov = glm_rad(75.0f); + cam->nearClip = 0.1f; + cam->farClip = 1000.0f; + cam->clearColor = COLOR_CORNFLOWER_BLUE; +} + +void cameraPush(const ecsid_t id) { + assertTrue(cameraHas(id), "Not a camera component"); + + camera_t *cam = cameraGet(id); + + mat4 projection; + switch(cam->type) { + case CAMERA_TYPE_ORTHOGRAPHIC: + glm_ortho( + cam->orthographic.left, + cam->orthographic.right, + cam->orthographic.bottom, + cam->orthographic.top, + cam->nearClip, + cam->farClip, + projection + ); + break; + + case CAMERA_TYPE_PERSPECTIVE: + glm_perspective( + cam->perspective.fov, + 4.0f / 3.0f, + cam->nearClip, + cam->farClip, + projection + ); + } + + #if DUSK_DISPLAY_SDL2 + glPushMatrix(); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glLoadMatrixf((const GLfloat*)projection); + + glClearColor( + cam->clearColor.r / 255.0f, + cam->clearColor.g / 255.0f, + cam->clearColor.b / 255.0f, + cam->clearColor.a / 255.0f + ); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + #endif +} + +void cameraPop(void) { + #if DUSK_DISPLAY_SDL2 + glPopMatrix(); + #endif +} \ No newline at end of file diff --git a/src/display/camera.h b/src/display/camera.h index 1fdf4b5..a795f2f 100644 --- a/src/display/camera.h +++ b/src/display/camera.h @@ -7,42 +7,59 @@ #pragma once #include "ecs/ecscomponent.h" +#include "display/color.h" + +typedef enum { + CAMERA_TYPE_PERSPECTIVE, + CAMERA_TYPE_ORTHOGRAPHIC +} cameraprojectiontype_t; typedef struct { - float_t view[16]; // 4x4 matrix for view transformation + cameraprojectiontype_t type; + + union { + struct { + float_t fov; + } perspective; + + struct { + float_t left; + float_t right; + float_t top; + float_t bottom; + } orthographic; + }; + + float_t nearClip; + float_t farClip; + color_t clearColor; } camera_t; extern camera_t CAMERA_DATA[ECS_ENTITY_COUNT_MAX]; extern ecscomponent_t CAMERA_COMPONENT; extern ecsid_t CAMERA_MAIN; - -/** - * Initializes the camera component. - * - * @param id The ID of the entity to initialize the camera for. - */ #define cameraAdd(id) ((camera_t*)ecsComponentDataAdd(&CAMERA_COMPONENT, id)) - -/** - * Gets the camera component data for a specific entity. - * - * @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) ((camera_t*)ecsComponentDataGet(&CAMERA_COMPONENT, id)) - -/** - * Checks if the camera component has data for a specific entity. - * - * @param id The ID of the entity to check. - * @return True if the camera component has data for the entity, false otherwise. - */ #define cameraHas(id) ecsComponentDataHas(&CAMERA_COMPONENT, id) +#define cameraRemove(id) ecsComponentDataRemove(&CAMERA_COMPONENT, id) /** - * Removes the camera component data for a specific entity. + * Callback function called when a new entity is added to the camera component. + * Initializes the camera data for the entity. * - * @param id The ID of the entity to remove the camera data for. + * @param id The ID of the newly added entity. */ -#define cameraRemove(id) ecsComponentDataRemove(&CAMERA_COMPONENT, id) \ No newline at end of file +void cameraEntityAdded(const ecsid_t id); + +/** + * Pushes the camera's view matrix onto the matrix stack. + * + * @param id The ID of the camera entity to use. + */ +void cameraPush(const ecsid_t id); + +/** + * Pops the camera's view matrix off the matrix stack. + */ +void cameraPop(void); \ No newline at end of file diff --git a/src/display/color.h b/src/display/color.h new file mode 100644 index 0000000..91fd15b --- /dev/null +++ b/src/display/color.h @@ -0,0 +1,106 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "dusk.h" + +typedef float_t colorchannelf_t; +typedef uint8_t colorchannelb_t; + +typedef struct { + colorchannelf_t r; + colorchannelf_t g; + colorchannelf_t b; +} color3f_t; + +typedef struct { + colorchannelf_t r; + colorchannelf_t g; + colorchannelf_t b; + colorchannelf_t a; +} color4f_t; + +typedef struct { + colorchannelb_t r; + colorchannelb_t g; + colorchannelb_t b; +} color3b_t; + +typedef struct { + colorchannelb_t r; + colorchannelb_t g; + colorchannelb_t b; + colorchannelb_t a; +} color4b_t; + +typedef color4b_t color_t; + +#define color3f(r, g, b) ((color3f_t){r, g, b}) +#define color4f(r, g, b, a) ((color4f_t){r, g, b, a}) +#define color3b(r, g, b) ((color3b_t){r, g, b}) +#define color4b(r, g, b, a) ((color4b_t){r, g, b, a}) +#define color(r, g, b, a) ((color_t){r, g, b, a}) + +#define COLOR_WHITE_3F color3f(1.0f, 1.0f, 1.0f) +#define COLOR_WHITE_4F color4f(1.0f, 1.0f, 1.0f, 1.0f) +#define COLOR_WHITE_3B color3b(255, 255, 255) +#define COLOR_WHITE_4B color4b(255, 255, 255, 255) +#define COLOR_WHITE color(255, 255, 255, 255) + +#define COLOR_BLACK_3F color3f(0.0f, 0.0f, 0.0f) +#define COLOR_BLACK_4F color4f(0.0f, 0.0f, 0.0f, 1.0f) +#define COLOR_BLACK_3B color3b(0, 0, 0) +#define COLOR_BLACK_4B color4b(0, 0, 0, 255) +#define COLOR_BLACK color(0, 0, 0, 255) + +#define COLOR_RED_3F color3f(1.0f, 0.0f, 0.0f) +#define COLOR_RED_4F color4f(1.0f, 0.0f, 0.0f, 1.0f) +#define COLOR_RED_3B color3b(255, 0, 0) +#define COLOR_RED_4B color4b(255, 0, 0, 255) +#define COLOR_RED color(255, 0, 0, 255) + +#define COLOR_GREEN_3F color3f(0.0f, 1.0f, 0.0f) +#define COLOR_GREEN_4F color4f(0.0f, 1.0f, 0.0f, 1.0f) +#define COLOR_GREEN_3B color3b(0, 255, 0) +#define COLOR_GREEN_4B color4b(0, 255, 0, 255) +#define COLOR_GREEN color(0, 255, 0, 255) + +#define COLOR_BLUE_3F color3f(0.0f, 0.0f, 1.0f) +#define COLOR_BLUE_4F color4f(0.0f, 0.0f, 1.0f, 1.0f) +#define COLOR_BLUE_3B color3b(0, 0, 255) +#define COLOR_BLUE_4B color4b(0, 0, 255, 255) +#define COLOR_BLUE color(0, 0, 255, 255) + +#define COLOR_YELLOW_3F color3f(1.0f, 1.0f, 0.0f) +#define COLOR_YELLOW_4F color4f(1.0f, 1.0f, 0.0f, 1.0f) +#define COLOR_YELLOW_3B color3b(255, 255, 0) +#define COLOR_YELLOW_4B color4b(255, 255, 0, 255) +#define COLOR_YELLOW color(255, 255, 0, 255) + +#define COLOR_CYAN_3F color3f(0.0f, 1.0f, 1.0f) +#define COLOR_CYAN_4F color4f(0.0f, 1.0f, 1.0f, 1.0f) +#define COLOR_CYAN_3B color3b(0, 255, 255) +#define COLOR_CYAN_4B color4b(0, 255, 255, 255) +#define COLOR_CYAN color(0, 255, 255, 255) + +#define COLOR_MAGENTA_3F color3f(1.0f, 0.0f, 1.0f) +#define COLOR_MAGENTA_4F color4f(1.0f, 0.0f, 1.0f, 1.0f) +#define COLOR_MAGENTA_3B color3b(255, 0, 255) +#define COLOR_MAGENTA_4B color4b(255, 0, 255, 255) +#define COLOR_MAGENTA color(255, 0, 255, 255) + +#define COLOR_TRANSPARENT_3F color3f(0.0f, 0.0f, 0.0f) +#define COLOR_TRANSPARENT_4F color4f(0.0f, 0.0f, 0.0f, 0.0f) +#define COLOR_TRANSPARENT_3B color3b(0, 0, 0) +#define COLOR_TRANSPARENT_4B color4b(0, 0, 0, 0) +#define COLOR_TRANSPARENT color(0, 0, 0, 0) + +#define COLOR_CORNFLOWER_BLUE_3F color3f(0.39f, 0.58f, 0.93f) +#define COLOR_CORNFLOWER_BLUE_4F color4f(0.39f, 0.58f, 0.93f, 1.0f) +#define COLOR_CORNFLOWER_BLUE_3B color3b(100, 149, 237) +#define COLOR_CORNFLOWER_BLUE_4B color4b(100, 149, 237, 255) +#define COLOR_CORNFLOWER_BLUE color(100, 149, 237, 255) \ No newline at end of file diff --git a/src/display/display.c b/src/display/display.c index 504a47e..0360eea 100644 --- a/src/display/display.c +++ b/src/display/display.c @@ -7,7 +7,7 @@ #include "display/display.h" #include "console/console.h" - +#include "display/camera.h" #include "display/mesh/mesh.h" display_t DISPLAY; @@ -82,11 +82,21 @@ errorret_t displayUpdate(void) { } } - SDL_GL_SwapWindow(DISPLAY.window); + // Set viewport size. + int32_t windowWidth, windowHeight; + SDL_GetWindowSize(DISPLAY.window, &windowWidth, &windowHeight); + glViewport(0, 0, windowWidth, windowHeight); #endif - meshDraw(&mesh, 0, -1); + if(CAMERA_MAIN != -1) { + cameraPush(CAMERA_MAIN); + meshDraw(&mesh, 0, -1); + cameraPop(); + } + #if DUSK_DISPLAY_SDL2 + SDL_GL_SwapWindow(DISPLAY.window); + #endif // For now, we just return an OK error. errorOk(); diff --git a/src/dusk.h b/src/dusk.h index 8dd5e00..0e1bfed 100644 --- a/src/dusk.h +++ b/src/dusk.h @@ -16,6 +16,7 @@ #include #include #include +#include typedef bool bool_t; typedef int int_t; diff --git a/src/engine/engine.c b/src/engine/engine.c index ecf6580..1b80d0a 100644 --- a/src/engine/engine.c +++ b/src/engine/engine.c @@ -11,7 +11,7 @@ #include "console/console.h" #include "display/display.h" #include "ecs/ecssystem.h" -#include "scene/scenetree.h" +#include "scene/node.h" #include "scene/test/scenetest.h" @@ -28,7 +28,7 @@ errorret_t engineInit(void) { errorChain(displayInit()); ecsid_t sceneTest = sceneTestAdd(); - sceneTreeChildAdd(ECS_SYSTEM.root, sceneTest); + nodeChildAdd(ECS_SYSTEM.root, sceneTest); errorOk(); } diff --git a/src/scene/CMakeLists.txt b/src/scene/CMakeLists.txt index 08f302c..3fa686a 100644 --- a/src/scene/CMakeLists.txt +++ b/src/scene/CMakeLists.txt @@ -6,7 +6,7 @@ # Sources target_sources(${DUSK_TARGET_NAME} PRIVATE - scenetree.c + node.c ) # Subdirs diff --git a/src/scene/node.c b/src/scene/node.c new file mode 100644 index 0000000..adbc982 --- /dev/null +++ b/src/scene/node.c @@ -0,0 +1,127 @@ +// Copyright (c) 2025 Dominic Masters +// +// This software is released under the MIT License. +// https://opensource.org/licenses/MIT + +#include "node.h" +#include "util/memory.h" +#include "assert/assert.h" + +node_t NODE_DATA[ECS_ENTITY_COUNT_MAX] = { 0 }; +ecscomponent_t NODE_COMPONENT = ecsComponentInit( + NODE_DATA, + ((ecscomponentcallbacks_t){ + .init = nodeInit, + .entityAdd = nodeEntityAdded, + .entityRemove = nodeEntityRemoved + }) +); + +ecsid_t nodeParentGet(const ecsid_t child) { + assertTrue(child >= 0 && child < ECS_ENTITY_COUNT_MAX, "Invalid child ID"); + if(!nodeHas(child)) return -1; + return NODE_DATA[child].parent; +} + +uint8_t nodeChildGetAll(const ecsid_t id, ecsid_t *children) { + if(!nodeHas(id)) return 0; + if(children == NULL) return NODE_DATA[id].childCount; + + memoryCopy( + children, + NODE_DATA[id].children, + sizeof(ecsid_t) * NODE_DATA[id].childCount + ); + + return NODE_DATA[id].childCount; +} + +void nodeChildAdd(const ecsid_t parent, const ecsid_t child) { + if(!nodeHas(parent)) nodeAdd(parent); + if(!nodeHas(child)) nodeAdd(child); + + node_t *parentNode = &NODE_DATA[parent]; + assertTrue(parentNode->childCount < SCENE_ITEM_CHILD_MAX, "Parent full."); + + // Add child to parent's children array + parentNode->children[parentNode->childCount] = child; + parentNode->childCount++; + + // Set child's parent + NODE_DATA[child].parent = parent; +} + +void nodeChildRemove(const ecsid_t parent, const ecsid_t child) { + assertTrue(nodeHas(parent), "NODE ECS lacks Parent."); + assertTrue(nodeHas(child), "NODE ECS lacks Child."); + + node_t *childNode = &NODE_DATA[child]; + node_t *parentNode = &NODE_DATA[parent]; + assertTrue(childNode->parent == parent, "Child does not belong to parent"); + assertTrue(parentNode->childCount > 0, "Parent has no children"); + + // Remove child from parent's children array + for (uint8_t i = 0; i < parentNode->childCount; i++) { + if (parentNode->children[i] == child) { + // Shift remaining children down + for (uint8_t j = i; j < parentNode->childCount - 1; j++) { + parentNode->children[j] = parentNode->children[j + 1]; + } + parentNode->childCount--; + break; + } + } + + // Clear child's parent + childNode->parent = -1; + + if(childNode->childCount == 0) nodeRemove(child); + if(parentNode->childCount == 0) nodeRemove(parent); +} + +void nodeChildRemoveAll(const ecsid_t parent) { + assertTrue(nodeHas(parent), "NODE ECS lacks Parent."); + + node_t *parentNode = &NODE_DATA[parent]; + for(uint8_t i = 0; i < parentNode->childCount; i++) { + ecsid_t child = parentNode->children[i]; + NODE_DATA[child].parent = -1; + + if(NODE_DATA[child].childCount == 0) nodeRemove(child); + } + + nodeRemove(parent); +} + +bool_t nodeChildInTree(const ecsid_t parent, const ecsid_t child) { + assertTrue(nodeHas(parent), "NODE ECS lacks Parent."); + assertTrue(nodeHas(child), "NODE ECS lacks Child."); + + assertTrue(parent >= 0 && parent < ECS_ENTITY_COUNT_MAX, "Invalid parent ID"); + assertTrue(child >= 0 && child < ECS_ENTITY_COUNT_MAX, "Invalid child ID"); + assertTrue(parent != child, "Child cannot be a child of itself."); + + node_t *childNode = &NODE_DATA[child]; + while(childNode) { + if(childNode->parent == parent) return true; + if(childNode->parent == -1) break; // No parent means we've reached the root + childNode = &NODE_DATA[childNode->parent]; + } + + return false; +} + +void nodeInit(void) { + for(ecsid_t i = 0; i < ECS_ENTITY_COUNT_MAX; i++) { + NODE_DATA[i].parent = -1; + } +} + +void nodeEntityAdded(const ecsid_t id) { + NODE_DATA[id].parent = -1; +} + +void nodeEntityRemoved(const ecsid_t id) { + if(NODE_DATA[id].parent == -1) return; + nodeChildRemove(NODE_DATA[id].parent, id); +} \ No newline at end of file diff --git a/src/scene/scenetree.h b/src/scene/node.h similarity index 70% rename from src/scene/scenetree.h rename to src/scene/node.h index 92c9b88..a613d29 100644 --- a/src/scene/scenetree.h +++ b/src/scene/node.h @@ -14,17 +14,21 @@ typedef struct { ecsid_t children[SCENE_ITEM_CHILD_MAX]; uint8_t childCount; ecsid_t parent; -} scenetreenode_t; + + vec3 position; + vec3 rotation; + vec3 scale; +} node_t; -extern scenetreenode_t SCENE_TREE_DATA[ECS_ENTITY_COUNT_MAX]; -extern ecscomponent_t SCENE_TREE_COMPONENT; +extern node_t NODE_DATA[ECS_ENTITY_COUNT_MAX]; +extern ecscomponent_t NODE_COMPONENT; -/** - * Initialize the scene tree. - * - * This will initialize the ECS system and prepare the scene tree for use. - */ -void sceneTreeInit(void); +#define nodeHas(id) ecsComponentDataHas(&NODE_COMPONENT, id) +#define nodeGet(id) \ + ((node_t*)ecsComponentDataGet(&NODE_COMPONENT, id)) +#define nodeAdd(id) \ + ((node_t*)ecsComponentDataAdd(&NODE_COMPONENT, id)) +#define nodeRemove(id) ecsComponentDataRemove(&NODE_COMPONENT, id) /** * Create a new scene item in the scene tree. @@ -32,7 +36,7 @@ void sceneTreeInit(void); * * @return The ID of the newly created scene item. */ -ecsid_t sceneTreeCreate(void); +ecsid_t nodeCreate(void); /** * Get the parent of a given scene item. @@ -40,7 +44,7 @@ ecsid_t sceneTreeCreate(void); * @param id The ID of the scene item. * @return The ID of the parent scene item, or -1 if it has no parent. */ -ecsid_t sceneTreeParentGet(const ecsid_t child); +ecsid_t nodeParentGet(const ecsid_t child); /** * Get the children of a given scene item. If children is NULL only the count @@ -50,7 +54,7 @@ ecsid_t sceneTreeParentGet(const ecsid_t child); * @param children Pointer to an array where the children IDs will be stored. * @return The number of children found. */ -uint8_t sceneTreeChildGetAll(const ecsid_t id, ecsid_t *children); +uint8_t nodeChildGetAll(const ecsid_t id, ecsid_t *children); /** * Add a child to a parent in the scene tree. @@ -58,7 +62,7 @@ uint8_t sceneTreeChildGetAll(const ecsid_t id, ecsid_t *children); * @param parent The ID of the parent scene item. * @param child The ID of the child scene item to add. */ -void sceneTreeChildAdd(const ecsid_t parent, const ecsid_t child); +void nodeChildAdd(const ecsid_t parent, const ecsid_t child); /** * Remove a child from a parent in the scene tree. @@ -66,14 +70,14 @@ void sceneTreeChildAdd(const ecsid_t parent, const ecsid_t child); * @param prnt The ID of the parent scene item. * @param child The ID of the child scene item to remove. */ -void sceneTreeChildRemove(const ecsid_t prnt, const ecsid_t child); +void nodeChildRemove(const ecsid_t prnt, const ecsid_t child); /** * Remove all children from a parent in the scene tree. * * @param parent The ID of the parent scene item. */ -void sceneTreeChildRemoveAll(const ecsid_t parent); +void nodeChildRemoveAll(const ecsid_t parent); /** * Returns true if the child is within the parent's children, recursively. @@ -82,7 +86,14 @@ void sceneTreeChildRemoveAll(const ecsid_t parent); * @param child The ID of the child scene item to check. * @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 nodeChildInTree(const ecsid_t parent, const ecsid_t child); + +/** + * Initialize the scene tree. + * + * This will initialize the ECS system and prepare the scene tree for use. + */ +void nodeInit(void); /** * Callback for when an entity is added to the ECS. @@ -90,7 +101,7 @@ bool_t sceneTreeChildInTree(const ecsid_t parent, const ecsid_t child); * * @param id The ID of the entity being added. */ -void sceneTreeEntityAdded(const ecsid_t id); +void nodeEntityAdded(const ecsid_t id); /** * Callback for when an entity is removed from the ECS. @@ -98,4 +109,4 @@ void sceneTreeEntityAdded(const ecsid_t id); * * @param id The ID of the entity being removed. */ -void sceneTreeEntityRemoved(const ecsid_t id); \ No newline at end of file +void nodeEntityRemoved(const ecsid_t id); \ No newline at end of file diff --git a/src/scene/scenetree.c b/src/scene/scenetree.c deleted file mode 100644 index 20c9569..0000000 --- a/src/scene/scenetree.c +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright (c) 2025 Dominic Masters -// -// This software is released under the MIT License. -// https://opensource.org/licenses/MIT - -#include "scenetree.h" -#include "util/memory.h" -#include "assert/assert.h" - -scenetreenode_t SCENE_TREE_DATA[ECS_ENTITY_COUNT_MAX] = { 0 }; -ecscomponent_t SCENE_TREE_COMPONENT = ecsComponentInit( - SCENE_TREE_DATA, - ((ecscomponentcallbacks_t){ - .init = sceneTreeInit, - .entityAdd = sceneTreeEntityAdded, - .entityRemove = sceneTreeEntityRemoved - }) -); - -void sceneTreeInit(void) { - // Default all items to have no parent - for (ecsid_t i = 0; i < ECS_ENTITY_COUNT_MAX; i++) { - SCENE_TREE_DATA[i].parent = -1; - } -} - -ecsid_t sceneTreeParentGet(const ecsid_t child) { - 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; -} - -uint8_t sceneTreeChildGetAll(const ecsid_t id, ecsid_t *children) { - if(!ecsComponentDataHas(&SCENE_TREE_COMPONENT, id)) return 0; - if(children == NULL) return SCENE_TREE_DATA[id].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) { - if(!ecsComponentDataHas(&SCENE_TREE_COMPONENT, parent)) { - ecsComponentDataAdd(&SCENE_TREE_COMPONENT, parent); - } - if(!ecsComponentDataHas(&SCENE_TREE_COMPONENT, child)) { - ecsComponentDataAdd(&SCENE_TREE_COMPONENT, child); - } - - scenetreenode_t *parentNode = &SCENE_TREE_DATA[parent]; - assertTrue(parentNode->childCount < SCENE_ITEM_CHILD_MAX, "Parent full."); - - // Add child to parent's children array - parentNode->children[parentNode->childCount] = child; - parentNode->childCount++; - - // Set child's parent - SCENE_TREE_DATA[child].parent = parent; -} - -void sceneTreeChildRemove( - const ecsid_t parent, - 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." - ); - - 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"); - - // Remove child from parent's children array - for (uint8_t i = 0; i < parentNode->childCount; i++) { - if (parentNode->children[i] == child) { - // Shift remaining children down - for (uint8_t j = i; j < parentNode->childCount - 1; j++) { - parentNode->children[j] = parentNode->children[j + 1]; - } - parentNode->childCount--; - break; - } - } - - // Clear child's parent - 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) { - assertTrue( - ecsComponentDataHas(&SCENE_TREE_COMPONENT, parent), - "SCENE TREE ECS lacks 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_DATA[child].parent = -1; - - if(SCENE_TREE_DATA[child].childCount == 0) { - ecsComponentDataRemove(&SCENE_TREE_COMPONENT, child); - } - } - - ecsComponentDataRemove(&SCENE_TREE_COMPONENT, parent); -} - -bool_t sceneTreeChildInTree( - const ecsid_t parent, - 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(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_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_DATA[childNode->parent]; - } - - 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); -} \ No newline at end of file diff --git a/src/scene/test/scenetest.c b/src/scene/test/scenetest.c index 3293a31..af6e41d 100644 --- a/src/scene/test/scenetest.c +++ b/src/scene/test/scenetest.c @@ -6,16 +6,24 @@ */ #include "scenetest.h" -#include "scene/scenetree.h" +#include "scene/node.h" #include "display/camera.h" +#include "display/display.h" ecsid_t sceneTestAdd(void) { ecsid_t id = ecsEntityAdd(); // Initialize the entity with a camera component ecsid_t camera = ecsEntityAdd(); - sceneTreeChildAdd(id, camera); + nodeChildAdd(id, camera); camera_t *camData = cameraAdd(camera); + camData->type = CAMERA_TYPE_ORTHOGRAPHIC; + camData->orthographic.left = 0.0f; + camData->orthographic.right = 1.0f; + camData->orthographic.top = 0.0f; + camData->orthographic.bottom = 1.0f; + camData->nearClip = -1.0f; + camData->farClip = 1.0f; // Optionally, you can set other properties or components here