diff --git a/build b/build index e365d9c..0c38577 100755 --- a/build +++ b/build @@ -10,6 +10,8 @@ else time clang -O2 $COMMON_FLAGS ./src/main.c -o ./target/somaesque $LIB_INCLUDE fi echo [Target built] + +if [ "$1" == "run" ]; then ./target/somaesque - +fi diff --git a/src/SomaSolve.c b/src/SomaSolve.c index 809c0ed..e009692 100644 --- a/src/SomaSolve.c +++ b/src/SomaSolve.c @@ -139,7 +139,7 @@ void backtrackSolve(Arena *arena, Solver *solver, uint64 working_solution, size_ VoxelSpaceReprList last_soln_copy = PushList(arena, VoxelSpaceReprList, last_soln.length); last_soln_copy.length = last_soln.length; memcpy(last_soln_copy.data, last_soln.data, last_soln.length * ListElementSize(VoxelSpaceReprList)); - AppendList(solutions, last_soln_copy); + ListAppend(*solutions, last_soln_copy); return; } else { backtrackSolve(arena, solver, new_working_solution, curr_piece + 1); @@ -165,7 +165,7 @@ SomaSolutionList getSolutionRotations(Arena *arena, SomaSolution *solution, int }; VoxelSpaceList pieceRotations = getAllRotations(arena, &space); for (EachIn(pieceRotations, rot_i)) { - AppendList(&result.data[rot_i], pieceRotations.data[rot_i].space); + ListAppend(result.data[rot_i], pieceRotations.data[rot_i].space); } } return result; @@ -204,7 +204,7 @@ SomaSolutionList filterUnique(Arena *arena, SomaSolutionList *solutions, int dim solutionCopy.capacity = solution->length; solutionCopy.length = solution->length; memcpy(solutionCopy.data, solution->data, ListElementSize(SomaSolutionList) * solution->length); - AppendList(&uniqueSolns, solutionCopy); + ListAppend(uniqueSolns, solutionCopy); } } return uniqueSolns; @@ -233,7 +233,7 @@ SomaSolutionList solveSoma(Arena *solutionsArena, VoxelSpaceReprList reprsInput, dims[2], }; - AppendList(&offsets, 0); + ListAppend(offsets, 0); uint64 possibleCombos = 0; @@ -250,7 +250,7 @@ SomaSolutionList solveSoma(Arena *solutionsArena, VoxelSpaceReprList reprsInput, }; for (size_t i = 1; i < reprsInput.length; i++) { - AppendList(&offsets, polycubes.capacity); + ListAppend(offsets, polycubes.capacity); VoxelSpace space = emptyVoxelSpace; space.space = reprsInput.data[i]; cullEmptySpace(&space); @@ -262,10 +262,10 @@ SomaSolutionList solveSoma(Arena *solutionsArena, VoxelSpaceReprList reprsInput, memcpy(insertion, perms.data, perms.capacity * ListElementSize(VoxelSpaceReprList)); } - AppendList(&offsets, polycubes.length); + ListAppend(offsets, polycubes.length); SomaSolutionList solutions = PushList(permsArena, SomaSolutionList, (size_t)floor(sqrt(possibleCombos))); - AppendList(&solutions, PushFullList(permsArena, SomaSolution, reprsInput.length)); + ListAppend(solutions, PushFullList(permsArena, SomaSolution, reprsInput.length)); Solver solver = { &polycubes, diff --git a/src/VoxelSpace.c b/src/VoxelSpace.c index a0d5591..d73442a 100644 --- a/src/VoxelSpace.c +++ b/src/VoxelSpace.c @@ -177,7 +177,7 @@ void pushNewUniqueSpins(VoxelSpaceList *existingSpaces, VoxelSpace* spaceToSpin) } } if (!matchFound) { - AppendList(existingSpaces, spins[i]); + ListAppend(*existingSpaces, spins[i]); } } } @@ -186,7 +186,7 @@ void pushXAxisSpins(Arena *arena, VoxelSpaceList *existingSpaces, VoxelSpace* sp VoxelSpace refSpace = *spaceToSpin; for (int i = 0; i < 4; i++) { rotate90X(&refSpace); - AppendList(existingSpaces, refSpace); + ListAppend(*existingSpaces, refSpace); } } diff --git a/src/lib/djstdlib b/src/lib/djstdlib index 9b772e2..3f3ef53 160000 --- a/src/lib/djstdlib +++ b/src/lib/djstdlib @@ -1 +1 @@ -Subproject commit 9b772e204672e03bf73388ae8aca21ea5559a764 +Subproject commit 3f3ef5351fa083095984642bc408850deb23f7f1 diff --git a/src/main.c b/src/main.c index 1ae5429..0dd1243 100644 --- a/src/main.c +++ b/src/main.c @@ -217,7 +217,7 @@ struct Soma { SomaSolutionList solutions; SolveTaskCtx solveTaskCtx; uint32 puzzleDims[3]; - HandleList solutionEntities; + int32 solutionNode; }; void *executeSolve(void *ctx) { @@ -232,7 +232,7 @@ void *executeSolve(void *ctx) { void scheduleSolve(Soma *soma) { VoxelSpaceReprList mappedInputs = PushList(soma->solveTaskCtx.arena, VoxelSpaceReprList, soma->polycubeInput.length); for (EachEl(soma->polycubeInput, PolycubeInput, polycubeInput)) { - AppendList(&mappedInputs, polycubeInput->repr.space); + ListAppend(mappedInputs, polycubeInput->repr.space); } soma->solveTaskCtx.input = mappedInputs; soma->solveTaskCtx.taskStatus = SolveTaskStatus_Solving; @@ -248,9 +248,10 @@ void show(Scene *s, uint32 graphNodeHandle) { if (node->entityHandle) { getEntity(s, node->entityHandle)->flags |= EntityFlags_Visible; } - for (EachIn(node->children, i)) { - uint32 child = node->children.data[i]; - show(s, child); + int32 next = node->firstChild; + while (next) { + show(s, next); + next = getSceneGraphNode(s, next)->nextSibling; } } @@ -259,20 +260,24 @@ void hide(Scene *s, uint32 graphNodeHandle) { if (node->entityHandle) { getEntity(s, node->entityHandle)->flags &= ~EntityFlags_Visible; } - for (EachIn(node->children, i)) { - uint32 child = node->children.data[i]; - hide(s, child); + int32 next = node->firstChild; + while (next) { + hide(s, next); + next = getSceneGraphNode(s, next)->nextSibling; } } RLVector3 centreFromPolycube(Scene *scene, uint32 p) { RLVector3 centre = (RLVector3){0,0,0}; - HandleList *children = &getSceneGraphNode(scene, p)->children; - for (EachIn(*children, i)) { - uint32 child = children->data[i]; - centre = Vector3Add(centre, getSceneGraphNode(scene, child)->translation); + int32 childCount = 0; + int32 nextChild = getSceneGraphNode(scene, p)->firstChild; + while (nextChild) { + SceneGraphNode *node = getSceneGraphNode(scene, nextChild); + centre = Vector3Add(centre, node->translation); + nextChild = node->nextSibling; + childCount++; } - centre = Vector3Scale(centre, 1.0f/(getSceneGraphNode(scene, p)->children.length)); + centre = Vector3Scale(centre, 1.0f/childCount); return centre; } @@ -411,7 +416,7 @@ void processInput(Soma *soma, UI_Context *ui) { soma->state.displayedSolution += 1; } } else { - if (soma->state.displayedPolycube == 6) { + if (soma->state.displayedPolycube == soma->polycubeInput.length - 1) { soma->state.displayedPolycube = 0; } else { soma->state.displayedPolycube += 1; @@ -422,14 +427,15 @@ void processInput(Soma *soma, UI_Context *ui) { if (input->keyboard.enter && !prevInput->keyboard.enter) { if (soma->state.displayingSolutions) { soma->state.displayingSolutions = false; - } else { + soma->state.displayedSolution = -1; + } else if (soma->solveTaskCtx.taskStatus == SolveTaskStatus_Ready) { scheduleSolve(soma); } } if (input->mouse.btnLeft && ui->hotNode == 0) { uint32 currentObject = soma->state.displayingSolutions - ? soma->solutionEntities.data[soma->state.displayedSolution] + ? soma->solutionNode : soma->polycubes.data[soma->state.displayedPolycube]; SceneGraphNode *objectGraphNode = getSceneGraphNode(soma->scene, currentObject); @@ -456,7 +462,7 @@ uint32 createPolycubeFromRepr(Scene *s, VoxelSpace *repr, RLVector4 color) { polycubeSegment->color = color; polycubeSegment->mesh = &cubeMesh; polycubeSegment->tex = &wallTex; - SceneGraphNode *graphNode = getSceneGraphNode(s, polycubeSegment->graphNodeHandle); + SceneGraphNode *graphNode = getSceneGraphNodeForEntity(s, segmentEntityHandle); graphNode->translation = (RLVector3){ -((repr->dim_z - 1)/2.0f) + z, -((repr->dim_x - 1)/2.0f) + x, @@ -557,7 +563,6 @@ void updateRectangleObjectBuffers(Renderer *r) { } Renderer createRenderer(Arena *arena, Scene *scene) { - scene->sceneRoot = createSceneGraphNode(scene); return (Renderer){ .scene = scene, .rects = createRectangleObjects(arena, 1024), @@ -615,12 +620,12 @@ void renderEnd(Soma *soma, Renderer *renderer) { } void rendererPlaceRectangle(Renderer *r, real32 x, real32 y, real32 width, real32 height, RLVector4 color, real32 borderRadius, real32 borderThickness) { - AppendList(&r->rects.p0, ((RLVector2){ x, y })); - AppendList(&r->rects.p1, ((RLVector2){ x + width, y + height })); - AppendList(&r->rects.color, color); - AppendList(&r->rects.borderRadius, borderRadius); - AppendList(&r->rects.borderThickness, borderThickness); - AppendList(&r->rects.edgeSoftness, 0.0f); + ListAppend(r->rects.p0, ((RLVector2){ x, y })); + ListAppend(r->rects.p1, ((RLVector2){ x + width, y + height })); + ListAppend(r->rects.color, color); + ListAppend(r->rects.borderRadius, borderRadius); + ListAppend(r->rects.borderThickness, borderThickness); + ListAppend(r->rects.edgeSoftness, 0.0f); } bool pointInRect(RLVector2 point, UI_Rect rect) { @@ -729,68 +734,61 @@ void uiPass(Soma *soma, UI_Context *ui) { } void updatePolycubeDisplay(Arena *arena, Soma *soma) { - if (!soma->prevState.displayingSolutions && soma->state.displayingSolutions) { - if (soma->prevState.displayedPolycube < soma->polycubes.length) { - hide(soma->scene, soma->polycubes.data[soma->state.displayedPolycube]); - } - } else if (soma->prevState.displayingSolutions && !soma->state.displayingSolutions) { - if (soma->prevState.displayedSolution < soma->solutionEntities.length) { - hide(soma->scene, soma->solutionEntities.data[soma->state.displayedSolution]); + Scene *s = soma->scene; + + if (soma->state.displayingSolutions && soma->state.displayedSolution != soma->prevState.displayedSolution) { + removeSceneGraphNode(s, soma->solutionNode); + if (soma->state.displayedSolution >= 0 && soma->state.displayedSolution < soma->solutions.length) { + SomaSolution soln = soma->solutions.data[soma->state.displayedSolution]; + soma->solutionNode = createSceneGraphNode(s); + for (EachIn(soln, i)) { + uint32 polycubeGraphNodeHandle = createPolycubeFromRepr( + s, + &(VoxelSpace){ soln.data[i], 3, 3, 3 }, + colorFromIndex(i) + ); + sceneNodeAddNode(s, soma->solutionNode, polycubeGraphNodeHandle); + } + sceneNodeAddNode(s, s->sceneRoot, soma->solutionNode); } } if (soma->state.displayingSolutions) { - if (soma->solutions.length > 0) { - show(soma->scene, soma->solutionEntities.data[soma->state.displayedSolution]); - if (soma->state.displayedSolution != soma->prevState.displayedSolution) { - hide(soma->scene, soma->solutionEntities.data[soma->prevState.displayedSolution]); - } + show(s, soma->solutionNode); + if (soma->prevState.displayedPolycube >= 0 && soma->prevState.displayedPolycube < soma->polycubes.length) { + hide(s, soma->polycubes.data[soma->prevState.displayedPolycube]); } } else { - if (soma->polycubes.length > 0) { - show(soma->scene, soma->polycubes.data[soma->state.displayedPolycube]); - if (soma->state.displayedPolycube != soma->prevState.displayedPolycube) { - hide(soma->scene, soma->polycubes.data[soma->prevState.displayedPolycube]); + hide(s, soma->solutionNode); + if (soma->state.displayedPolycube >= 0 && soma->state.displayedPolycube < soma->polycubes.length) { + show(s, soma->polycubes.data[soma->state.displayedPolycube]); + } + if (soma->state.displayedPolycube != soma->prevState.displayedPolycube) { + if (soma->prevState.displayedPolycube >= 0 && soma->prevState.displayedPolycube < soma->polycubes.length) { + hide(s, soma->polycubes.data[soma->prevState.displayedPolycube]); } } } if (soma->state.polycubeDirty) { if (soma->state.displayedPolycube >= 0 && soma->state.displayedPolycube < soma->polycubes.length) { - uint32 currentPolycubeHandle = soma->polycubes.data[soma->state.displayedPolycube]; - PolycubeInput *pinput = &soma->polycubeInput.data[soma->state.displayedPolycube]; - VoxelSpace culledRepr = pinput->repr; - cullEmptySpace(&culledRepr); - uint32 newPolycubeHandle = createPolycubeFromRepr(soma->scene, &culledRepr, pinput->color); - SceneGraphNode *newPolycubeGraphNode = getSceneGraphNode(soma->scene, newPolycubeHandle); - newPolycubeGraphNode->rotation = getSceneGraphNode(soma->scene, currentPolycubeHandle)->rotation; - removeEntity(soma->scene, currentPolycubeHandle); - soma->polycubes.data[soma->state.displayedPolycube] = newPolycubeHandle; - sceneNodeAddNode(soma->scene, soma->scene->sceneRoot, newPolycubeHandle); - soma->state.polycubeDirty = false; - hide(soma->scene, currentPolycubeHandle); - show(soma->scene, newPolycubeHandle); - } - } -} + uint32 oldHandle = soma->polycubes.data[soma->state.displayedPolycube]; + Quaternion rot = getSceneGraphNode(s, oldHandle)->rotation; + removeSceneGraphNode(s, oldHandle); -void createSolutionEntities(Arena *arena, Soma *soma) { - if (soma->solutions.length > 0) { - soma->solutionEntities = PushList(arena, HandleList, soma->solutions.length); - for (EachEl(soma->solutions, SomaSolution, solution)) { - uint32 solutionGraphNodeHandle = createSceneGraphNode(soma->scene); - AppendList(&soma->solutionEntities, solutionGraphNodeHandle); - sceneNodeAddNode(soma->renderer->scene, soma->renderer->scene->sceneRoot, solutionGraphNodeHandle); - for (EachIn(*solution, soln_i)) { - uint32 polycubeGraphNodeHandle = createPolycubeFromRepr( - soma->scene, - &(VoxelSpace){ solution->data[soln_i], 3, 3, 3 }, - colorFromIndex(soln_i) - ); - sceneNodeAddNode(soma->renderer->scene, solutionGraphNodeHandle, polycubeGraphNodeHandle); - } + PolycubeInput *newInput = &soma->polycubeInput.data[soma->state.displayedPolycube]; + VoxelSpace newInputCulled = newInput->repr; + cullEmptySpace(&newInputCulled); + + uint32 newHandle = createPolycubeFromRepr(s, &newInputCulled, newInput->color); + getSceneGraphNode(s, newHandle)->rotation = rot; + + soma->polycubes.data[soma->state.displayedPolycube] = newHandle; + sceneNodeAddNode(s, s->sceneRoot, newHandle); + + soma->state.polycubeDirty = false; + show(s, newHandle); } - show(soma->scene, soma->solutionEntities.data[soma->state.displayedSolution]); } } @@ -798,7 +796,8 @@ int mainGfx() { Arena *arena = arenaAlloc(Megabytes(128)); Arena *solutionsArena = arenaAlloc(Megabytes(128)); - int winWidth = 800, winHeight = 600; + int winWidth = 800; + int winHeight = 600; GLFWwindow *windowHandle = initWindowAndGL(winWidth, winHeight); if (!windowHandle) { return 1; @@ -840,9 +839,9 @@ int mainGfx() { .taskStatus = SolveTaskStatus_Ready, }, .state = { - .displayingSolutions = false, .displayedPolycube = 0, - .displayedSolution = 0, + .displayingSolutions = false, + .displayedSolution = -1, .isInitialState = true, .light = createEntity(&mainScene), .camera = mainFrame.cam, @@ -871,10 +870,10 @@ int mainGfx() { VoxelSpace voxelSpace = { stdSoma.data[i], 3, 3, 3 }; RLVector4 color = colorFromIndex(i); PolycubeInput input = (PolycubeInput){ voxelSpace, color }; - AppendList(&soma.polycubeInput, input); + ListAppend(soma.polycubeInput, input); cullEmptySpace(&voxelSpace); uint32 polycubeGraphNodeHandle = createPolycubeFromRepr(soma.scene, &voxelSpace, color); - AppendList(&soma.polycubes, polycubeGraphNodeHandle); + ListAppend(soma.polycubes, polycubeGraphNodeHandle); sceneNodeAddNode(renderer.scene, renderer.scene->sceneRoot, polycubeGraphNodeHandle); } @@ -903,15 +902,13 @@ int mainGfx() { processInput(&soma, &ui); if (soma.solveTaskCtx.taskStatus == SolveTaskStatus_Complete) { - soma.solutions = PushFullList(solutionsArena, SomaSolutionList, soma.solveTaskCtx.solutions.length); - memcpy(soma.solutions.data, soma.solveTaskCtx.solutions.data, soma.solutions.length*sizeof(soma.solutions.data[0])); - for (EachIn(soma.solutions, i)) { - soma.solutions.data[i] = PushFullList(solutionsArena, SomaSolution, soma.solveTaskCtx.input.length); - memcpy(&soma.solutions.data[i], &soma.solveTaskCtx.solutions.data[i], soma.solveTaskCtx.input.length*sizeof(uint64)); + soma.solutions = PushList(solutionsArena, SomaSolutionList, soma.solveTaskCtx.solutions.length); + for (EachIn(soma.solveTaskCtx.solutions, i)) { + ListAppend(soma.solutions, PushListCopy(solutionsArena, SomaSolution, soma.solveTaskCtx.solutions.data[i])); } - createSolutionEntities(arena, &soma); soma.solveTaskCtx.taskStatus = SolveTaskStatus_Ready; soma.state.displayingSolutions = true; + soma.state.displayedSolution = 0; arenaFreeFrom(soma.solveTaskCtx.arena, 0); } diff --git a/src/tests.c b/src/tests.c index b87f8db..203db0f 100644 --- a/src/tests.c +++ b/src/tests.c @@ -289,15 +289,15 @@ void test() { for (int i = 0; i < 6; i++) { if (positions1.data[i] != expected_results1[i]) { MismatchData data = { i, positions1.data[i], expected_results1[i] }; - AppendList(&mismatches1, data); + ListAppend(mismatches1, data); } if (positions2.data[i] != expected_results2[i]) { MismatchData data = { i, positions2.data[i], expected_results2[i] }; - AppendList(&mismatches2, data); + ListAppend(mismatches2, data); } if (positions3.data[i] != expected_results3[i]) { MismatchData data = { i, positions3.data[i], expected_results3[i] }; - AppendList(&mismatches3, data); + ListAppend(mismatches3, data); } } Assert(mismatches1.length == 0); diff --git a/src/world/scene.c b/src/world/scene.c index 376c62a..b654403 100644 --- a/src/world/scene.c +++ b/src/world/scene.c @@ -1,44 +1,60 @@ -#include "string.h" #include "scene.h" -Entity *getEntity(Scene *s, uint32 entityHandle) { - if (entityHandle) { - return &s->entities.data[entityHandle - 1]; +Entity *getEntity(Scene *s, int32 entityHandle) { + return &s->entities.data[entityHandle]; +} + +SceneGraphNode *getSceneGraphNode(Scene *s, int32 sceneGraphNodeHandle) { + return &s->graphNodes.data[sceneGraphNodeHandle]; +} + +SceneGraphNode *getSceneGraphNodeForEntity(Scene *s, int32 entityHandle) { + return getSceneGraphNode(s, getEntity(s, entityHandle)->graphNodeHandle); +} + +int32 createSceneGraphNode(Scene *s) { + SceneGraphNode *newNode; + int32 newNodeHandle; + if (s->nextFreeNode) { + newNodeHandle = s->nextFreeNode; + newNode = getSceneGraphNode(s, newNodeHandle); + if (newNode->next) { + s->nextFreeNode = newNode->next; + } else { + s->nextFreeNode = 0; + } + newNode->next = 0; + } else { + ListAppend(s->graphNodes, (SceneGraphNode){0}); + newNodeHandle = (int32)s->graphNodes.length - 1; + newNode = getSceneGraphNode(s, newNodeHandle); + newNode->nextSibling = 0; } - return NULL; + initGraphNode(newNode); + return newNodeHandle; } -SceneGraphNode *getSceneGraphNode(Scene *s, uint32 sceneGraphNodeHandle) { - if (sceneGraphNodeHandle) { - return &s->graphNodes.data[sceneGraphNodeHandle - 1]; +int32 createEntity(Scene *s) { + Entity *newEntity; + int32 newEntityHandle; + println("%d", s->nextFreeEntity); + if (s->nextFreeEntity) { + newEntityHandle = s->nextFreeEntity; + newEntity = getEntity(s, newEntityHandle); + if (newEntity->next) { + s->nextFreeEntity = newEntity->next; + } else { + s->nextFreeEntity = 0; + } + newEntity->next = 0; + } else { + ListAppend(s->entities, (Entity){0}); + newEntityHandle = (int32)s->entities.length - 1; + newEntity = getEntity(s, newEntityHandle); } - return NULL; -} - -SceneGraphNode *getSceneGraphNodeForEntity(Scene *s, uint32 entityHandle) { - Entity *e = getEntity(s, entityHandle); - if (e) { - return getSceneGraphNode(s, e->graphNodeHandle); - } - return NULL; -} - -uint32 createSceneGraphNode(Scene *s) { - AppendList(&s->graphNodes, (SceneGraphNode){0}); - SceneGraphNode *node = &s->graphNodes.data[s->graphNodes.length - 1]; - node->children = PushList(s->arena, HandleList, 1000); - initGraphNode(node); - return (uint32)s->graphNodes.length; -} - -uint32 createEntity(Scene *s) { - AppendList(&s->entities, (Entity){0}); - uint32 graphNodeId = createSceneGraphNode(s); - s->entities.data[s->entities.length - 1].graphNodeHandle = graphNodeId; - getSceneGraphNode(s, graphNodeId)->entityHandle = (uint32)s->entities.length; - uint32 handle = (uint32)s->entities.length; - uint32 graphNodeHandle = (uint32)s->graphNodes.length; - return handle; + newEntity->graphNodeHandle = createSceneGraphNode(s); + getSceneGraphNodeForEntity(s, newEntityHandle)->entityHandle = newEntityHandle; + return newEntityHandle; } void initGraphNode(SceneGraphNode *n) { @@ -49,32 +65,32 @@ void initGraphNode(SceneGraphNode *n) { n->world = n->local; } -void recalcGraphNode(SceneGraphNode *n) { - n->local = MatrixCompose(n->translation, n->rotation, n->scale); -} - Scene createScene(Arena *arena) { Scene result = { - .arena = arena, - .entities = PushList(arena, EntityList, 100000), - .graphNodes = PushList(arena, SceneGraphNodeList, 100000), + .entities = PushListZero(arena, EntityList, 100000), + .nextFreeEntity = 0, + .graphNodes = PushListZero(arena, SceneGraphNodeList, 100000), + .nextFreeNode = 0, }; + int32 handle = createEntity(&result); // Intialise the "zero" nodes + getEntity(&result, handle)->flags = EntityFlags_None | EntityFlags_Dead; + result.sceneRoot = createSceneGraphNode(&result); return result; } -void recalcSceneGraphNode(Scene *s, uint32 parentHandle) { - SceneGraphNode *node = getSceneGraphNode(s, parentHandle); - if (node->entityHandle) { - getEntity(s, node->entityHandle)->flags |= EntityFlags_Render; - } - for (EachIn(node->children, i)) { - uint32 nodeId = node->children.data[i]; - SceneGraphNode *graphNode = getSceneGraphNode(s, nodeId); - graphNode->parentHandle = parentHandle; - recalcGraphNode(graphNode); - graphNode->world = MatrixMultiply(graphNode->local, node->world); - recalcSceneGraphNode(s, nodeId); +void recalcSceneGraphNode(Scene *s, int32 parentHandle) { + if (!parentHandle) return; + SceneGraphNode *parentNode = getSceneGraphNode(s, parentHandle); + getEntity(s, parentNode->entityHandle)->flags |= EntityFlags_Render; + int32 nextChild = parentNode->firstChild; + while (nextChild) { + SceneGraphNode *childNode = getSceneGraphNode(s, nextChild); + childNode->parentHandle = parentHandle; + childNode->local = MatrixCompose(childNode->translation, childNode->rotation, childNode->scale); + childNode->world = MatrixMultiply(childNode->local, parentNode->world); + recalcSceneGraphNode(s, nextChild); + nextChild = childNode->nextSibling; } } @@ -82,31 +98,73 @@ void recalcScene(Scene *s) { recalcSceneGraphNode(s, s->sceneRoot); } -void removeEntity(Scene *s, uint32 entityHandle) { - Entity *entity = getEntity(s, entityHandle); - entity->flags |= EntityFlags_Dead; - SceneGraphNode *graphNode = getSceneGraphNode(s, entity->graphNodeHandle); - if (graphNode != NULL && graphNode->parentHandle) { +function void removeSceneGraphNodeRecursive(Scene *s, int32 graphNodeHandle, bool deletingParent) { + if (!graphNodeHandle) return; + SceneGraphNode *graphNode = getSceneGraphNode(s, graphNodeHandle); + + int32 nextChild = graphNode->firstChild; + while (nextChild) { + int32 sibling = getSceneGraphNode(s, nextChild)->nextSibling; + removeSceneGraphNodeRecursive(s, nextChild, true); + nextChild = sibling; + } + + if (graphNode->entityHandle) { + Entity *entity = getEntity(s, graphNode->entityHandle); + *entity = (Entity){0}; + if (s->nextFreeEntity) { + entity->next = s->nextFreeEntity; + } + s->nextFreeEntity = graphNode->entityHandle; + } + + if (s->nextFreeNode) { + graphNode->next = s->nextFreeNode; + } + s->nextFreeNode = graphNodeHandle; + + if (!deletingParent && graphNode->parentHandle) { SceneGraphNode *parentNode = getSceneGraphNode(s, graphNode->parentHandle); - if (parentNode != NULL) { - for (EachIn(parentNode->children, i)) { - if (parentNode->children.data[i] == entity->graphNodeHandle) { - memcpy(parentNode->children.data + i, parentNode->children.data + i + 1, parentNode->children.length - i - 1); - //ListRemove(&parentNode->children, i); - graphNode->parentHandle = 0; + if (parentNode->firstChild == graphNodeHandle) { + if (graphNode->nextSibling) { + parentNode->firstChild = graphNode->nextSibling; + } else { + parentNode->firstChild = 0; + } + } else { + int32 prevSibling = parentNode->firstChild; + int32 nextSibling = getSceneGraphNode(s, parentNode->firstChild)->nextSibling; + while (nextSibling) { + SceneGraphNode *siblingNode = getSceneGraphNode(s, nextSibling); + if (nextSibling == graphNodeHandle) { + SceneGraphNode *prevSiblingNode = getSceneGraphNode(s, prevSibling); + prevSiblingNode->nextSibling = graphNode->nextSibling; break; } + nextSibling = siblingNode->nextSibling; } } } + + graphNode->firstChild = 0; + graphNode->parentHandle = 0; + graphNode->entityHandle = 0; + graphNode->nextSibling = 0; } -void sceneNodeAddEntity(Scene *s, uint32 graphNodeHandle, uint32 entityHandle) { - HandleList *childList = &getSceneGraphNode(s, graphNodeHandle)->children; - AppendList(childList, getEntity(s, entityHandle)->graphNodeHandle); +void removeSceneGraphNode(Scene *s, int32 graphNodeHandle) { + removeSceneGraphNodeRecursive(s, graphNodeHandle, false); } -void sceneNodeAddNode(Scene *s, uint32 recipientNodeHandle, uint32 graphNodeHandle) { - HandleList *childList = &getSceneGraphNode(s, recipientNodeHandle)->children; - AppendList(childList, graphNodeHandle); +void removeEntity(Scene *s, int32 entityHandle) { + if (!entityHandle) return; + removeSceneGraphNode(s, getEntity(s, entityHandle)->graphNodeHandle); +} + +void sceneNodeAddNode(Scene *s, int32 parentHandle, int32 childHandle) { + SceneGraphNode *parentNode = getSceneGraphNode(s, parentHandle); + SceneGraphNode *childNode = getSceneGraphNode(s, childHandle); + childNode->nextSibling = parentNode->firstChild; + parentNode->firstChild = childHandle; + childNode->parentHandle = parentHandle; } diff --git a/src/world/scene.h b/src/world/scene.h index 812e7ee..b30e63d 100644 --- a/src/world/scene.h +++ b/src/world/scene.h @@ -1,9 +1,10 @@ #include "../gfx/gfx.h" #include "../lib/raymath.h" -DefineList(uint32, Handle); +DefineList(int32, Handle); enum EntityFlags { + EntityFlags_None=0, EntityFlags_Visible=1<<0, EntityFlags_Dead=1<<1, EntityFlags_Render=1<<2, @@ -11,11 +12,14 @@ enum EntityFlags { typedef struct Entity Entity; struct Entity { - uint32 graphNodeHandle; + int32 graphNodeHandle; uint64 flags; RLVector4 color; Mesh *mesh; Texture *tex; + + // Free list + int32 next; }; DefineList(Entity, Entity); @@ -26,30 +30,36 @@ struct SceneGraphNode { RLVector3 translation; Quaternion rotation; RLVector3 scale; - HandleList children; - uint32 entityHandle; - uint32 parentHandle; + int32 entityHandle; + int32 parentHandle; + + // Free list + int32 next; + + // Children + int32 nextSibling; + int32 firstChild; }; DefineList(SceneGraphNode, SceneGraphNode); typedef struct Scene Scene; struct Scene { - uint32 sceneRoot; + int32 sceneRoot; EntityList entities; + int32 nextFreeEntity; SceneGraphNodeList graphNodes; - Arena *arena; + int32 nextFreeNode; }; -uint32 createEntity(Scene *s); -Entity *getEntity(Scene *s, uint32 id); -SceneGraphNode *getSceneGraphNode(Scene *s, uint32 id); -uint32 createSceneGraphNode(Scene *s); +int32 createEntity(Scene *s); +Entity *getEntity(Scene *s, int32 id); +SceneGraphNode *getSceneGraphNode(Scene *s, int32 id); +int32 createSceneGraphNode(Scene *s); Scene createScene(Arena *arena); void initGraphNode(SceneGraphNode *n); -void recalcGraphNode(SceneGraphNode *n); -void recalcSceneGraphNode(Scene *s, uint32 parentHandle); +void recalcSceneGraphNode(Scene *s, int32 parentHandle); void recalcScene(Scene *s); -void removeEntity(Scene *s, uint32 entityHandle); -void sceneNodeAddNode(Scene *s, uint32 recipientNodeHandle, uint32 graphNodeHandle); -void sceneNodeAddEntity(Scene *s, uint32 graphNodeHandle, uint32 entityHandle); -SceneGraphNode *getSceneGraphNodeForEntity(Scene *s, uint32 entityHandle); +void removeEntity(Scene *s, int32 entityHandle); +void removeSceneGraphNode(Scene *s, int32 graphNodeHandle); +void sceneNodeAddNode(Scene *s, int32 recipientNodeHandle, int32 graphNodeHandle); +SceneGraphNode *getSceneGraphNodeForEntity(Scene *s, int32 entityHandle);