This commit is contained in:
2026-02-01 22:29:58 +01:00
parent e25004f59c
commit e71ba138c0
8 changed files with 252 additions and 185 deletions

4
build
View File

@@ -10,6 +10,8 @@ else
time clang -O2 $COMMON_FLAGS ./src/main.c -o ./target/somaesque $LIB_INCLUDE time clang -O2 $COMMON_FLAGS ./src/main.c -o ./target/somaesque $LIB_INCLUDE
fi fi
echo [Target built] echo [Target built]
if [ "$1" == "run" ]; then
./target/somaesque ./target/somaesque
fi

View File

@@ -139,7 +139,7 @@ void backtrackSolve(Arena *arena, Solver *solver, uint64 working_solution, size_
VoxelSpaceReprList last_soln_copy = PushList(arena, VoxelSpaceReprList, last_soln.length); VoxelSpaceReprList last_soln_copy = PushList(arena, VoxelSpaceReprList, last_soln.length);
last_soln_copy.length = last_soln.length; last_soln_copy.length = last_soln.length;
memcpy(last_soln_copy.data, last_soln.data, last_soln.length * ListElementSize(VoxelSpaceReprList)); memcpy(last_soln_copy.data, last_soln.data, last_soln.length * ListElementSize(VoxelSpaceReprList));
AppendList(solutions, last_soln_copy); ListAppend(*solutions, last_soln_copy);
return; return;
} else { } else {
backtrackSolve(arena, solver, new_working_solution, curr_piece + 1); 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); VoxelSpaceList pieceRotations = getAllRotations(arena, &space);
for (EachIn(pieceRotations, rot_i)) { 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; return result;
@@ -204,7 +204,7 @@ SomaSolutionList filterUnique(Arena *arena, SomaSolutionList *solutions, int dim
solutionCopy.capacity = solution->length; solutionCopy.capacity = solution->length;
solutionCopy.length = solution->length; solutionCopy.length = solution->length;
memcpy(solutionCopy.data, solution->data, ListElementSize(SomaSolutionList) * solution->length); memcpy(solutionCopy.data, solution->data, ListElementSize(SomaSolutionList) * solution->length);
AppendList(&uniqueSolns, solutionCopy); ListAppend(uniqueSolns, solutionCopy);
} }
} }
return uniqueSolns; return uniqueSolns;
@@ -233,7 +233,7 @@ SomaSolutionList solveSoma(Arena *solutionsArena, VoxelSpaceReprList reprsInput,
dims[2], dims[2],
}; };
AppendList(&offsets, 0); ListAppend(offsets, 0);
uint64 possibleCombos = 0; uint64 possibleCombos = 0;
@@ -250,7 +250,7 @@ SomaSolutionList solveSoma(Arena *solutionsArena, VoxelSpaceReprList reprsInput,
}; };
for (size_t i = 1; i < reprsInput.length; i++) { for (size_t i = 1; i < reprsInput.length; i++) {
AppendList(&offsets, polycubes.capacity); ListAppend(offsets, polycubes.capacity);
VoxelSpace space = emptyVoxelSpace; VoxelSpace space = emptyVoxelSpace;
space.space = reprsInput.data[i]; space.space = reprsInput.data[i];
cullEmptySpace(&space); cullEmptySpace(&space);
@@ -262,10 +262,10 @@ SomaSolutionList solveSoma(Arena *solutionsArena, VoxelSpaceReprList reprsInput,
memcpy(insertion, perms.data, perms.capacity * ListElementSize(VoxelSpaceReprList)); 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))); 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 = { Solver solver = {
&polycubes, &polycubes,

View File

@@ -177,7 +177,7 @@ void pushNewUniqueSpins(VoxelSpaceList *existingSpaces, VoxelSpace* spaceToSpin)
} }
} }
if (!matchFound) { 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; VoxelSpace refSpace = *spaceToSpin;
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
rotate90X(&refSpace); rotate90X(&refSpace);
AppendList(existingSpaces, refSpace); ListAppend(*existingSpaces, refSpace);
} }
} }

View File

@@ -217,7 +217,7 @@ struct Soma {
SomaSolutionList solutions; SomaSolutionList solutions;
SolveTaskCtx solveTaskCtx; SolveTaskCtx solveTaskCtx;
uint32 puzzleDims[3]; uint32 puzzleDims[3];
HandleList solutionEntities; int32 solutionNode;
}; };
void *executeSolve(void *ctx) { void *executeSolve(void *ctx) {
@@ -232,7 +232,7 @@ void *executeSolve(void *ctx) {
void scheduleSolve(Soma *soma) { void scheduleSolve(Soma *soma) {
VoxelSpaceReprList mappedInputs = PushList(soma->solveTaskCtx.arena, VoxelSpaceReprList, soma->polycubeInput.length); VoxelSpaceReprList mappedInputs = PushList(soma->solveTaskCtx.arena, VoxelSpaceReprList, soma->polycubeInput.length);
for (EachEl(soma->polycubeInput, PolycubeInput, polycubeInput)) { for (EachEl(soma->polycubeInput, PolycubeInput, polycubeInput)) {
AppendList(&mappedInputs, polycubeInput->repr.space); ListAppend(mappedInputs, polycubeInput->repr.space);
} }
soma->solveTaskCtx.input = mappedInputs; soma->solveTaskCtx.input = mappedInputs;
soma->solveTaskCtx.taskStatus = SolveTaskStatus_Solving; soma->solveTaskCtx.taskStatus = SolveTaskStatus_Solving;
@@ -248,9 +248,10 @@ void show(Scene *s, uint32 graphNodeHandle) {
if (node->entityHandle) { if (node->entityHandle) {
getEntity(s, node->entityHandle)->flags |= EntityFlags_Visible; getEntity(s, node->entityHandle)->flags |= EntityFlags_Visible;
} }
for (EachIn(node->children, i)) { int32 next = node->firstChild;
uint32 child = node->children.data[i]; while (next) {
show(s, child); show(s, next);
next = getSceneGraphNode(s, next)->nextSibling;
} }
} }
@@ -259,20 +260,24 @@ void hide(Scene *s, uint32 graphNodeHandle) {
if (node->entityHandle) { if (node->entityHandle) {
getEntity(s, node->entityHandle)->flags &= ~EntityFlags_Visible; getEntity(s, node->entityHandle)->flags &= ~EntityFlags_Visible;
} }
for (EachIn(node->children, i)) { int32 next = node->firstChild;
uint32 child = node->children.data[i]; while (next) {
hide(s, child); hide(s, next);
next = getSceneGraphNode(s, next)->nextSibling;
} }
} }
RLVector3 centreFromPolycube(Scene *scene, uint32 p) { RLVector3 centreFromPolycube(Scene *scene, uint32 p) {
RLVector3 centre = (RLVector3){0,0,0}; RLVector3 centre = (RLVector3){0,0,0};
HandleList *children = &getSceneGraphNode(scene, p)->children; int32 childCount = 0;
for (EachIn(*children, i)) { int32 nextChild = getSceneGraphNode(scene, p)->firstChild;
uint32 child = children->data[i]; while (nextChild) {
centre = Vector3Add(centre, getSceneGraphNode(scene, child)->translation); 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; return centre;
} }
@@ -411,7 +416,7 @@ void processInput(Soma *soma, UI_Context *ui) {
soma->state.displayedSolution += 1; soma->state.displayedSolution += 1;
} }
} else { } else {
if (soma->state.displayedPolycube == 6) { if (soma->state.displayedPolycube == soma->polycubeInput.length - 1) {
soma->state.displayedPolycube = 0; soma->state.displayedPolycube = 0;
} else { } else {
soma->state.displayedPolycube += 1; soma->state.displayedPolycube += 1;
@@ -422,14 +427,15 @@ void processInput(Soma *soma, UI_Context *ui) {
if (input->keyboard.enter && !prevInput->keyboard.enter) { if (input->keyboard.enter && !prevInput->keyboard.enter) {
if (soma->state.displayingSolutions) { if (soma->state.displayingSolutions) {
soma->state.displayingSolutions = false; soma->state.displayingSolutions = false;
} else { soma->state.displayedSolution = -1;
} else if (soma->solveTaskCtx.taskStatus == SolveTaskStatus_Ready) {
scheduleSolve(soma); scheduleSolve(soma);
} }
} }
if (input->mouse.btnLeft && ui->hotNode == 0) { if (input->mouse.btnLeft && ui->hotNode == 0) {
uint32 currentObject = soma->state.displayingSolutions uint32 currentObject = soma->state.displayingSolutions
? soma->solutionEntities.data[soma->state.displayedSolution] ? soma->solutionNode
: soma->polycubes.data[soma->state.displayedPolycube]; : soma->polycubes.data[soma->state.displayedPolycube];
SceneGraphNode *objectGraphNode = getSceneGraphNode(soma->scene, currentObject); SceneGraphNode *objectGraphNode = getSceneGraphNode(soma->scene, currentObject);
@@ -456,7 +462,7 @@ uint32 createPolycubeFromRepr(Scene *s, VoxelSpace *repr, RLVector4 color) {
polycubeSegment->color = color; polycubeSegment->color = color;
polycubeSegment->mesh = &cubeMesh; polycubeSegment->mesh = &cubeMesh;
polycubeSegment->tex = &wallTex; polycubeSegment->tex = &wallTex;
SceneGraphNode *graphNode = getSceneGraphNode(s, polycubeSegment->graphNodeHandle); SceneGraphNode *graphNode = getSceneGraphNodeForEntity(s, segmentEntityHandle);
graphNode->translation = (RLVector3){ graphNode->translation = (RLVector3){
-((repr->dim_z - 1)/2.0f) + z, -((repr->dim_z - 1)/2.0f) + z,
-((repr->dim_x - 1)/2.0f) + x, -((repr->dim_x - 1)/2.0f) + x,
@@ -557,7 +563,6 @@ void updateRectangleObjectBuffers(Renderer *r) {
} }
Renderer createRenderer(Arena *arena, Scene *scene) { Renderer createRenderer(Arena *arena, Scene *scene) {
scene->sceneRoot = createSceneGraphNode(scene);
return (Renderer){ return (Renderer){
.scene = scene, .scene = scene,
.rects = createRectangleObjects(arena, 1024), .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) { 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 })); ListAppend(r->rects.p0, ((RLVector2){ x, y }));
AppendList(&r->rects.p1, ((RLVector2){ x + width, y + height })); ListAppend(r->rects.p1, ((RLVector2){ x + width, y + height }));
AppendList(&r->rects.color, color); ListAppend(r->rects.color, color);
AppendList(&r->rects.borderRadius, borderRadius); ListAppend(r->rects.borderRadius, borderRadius);
AppendList(&r->rects.borderThickness, borderThickness); ListAppend(r->rects.borderThickness, borderThickness);
AppendList(&r->rects.edgeSoftness, 0.0f); ListAppend(r->rects.edgeSoftness, 0.0f);
} }
bool pointInRect(RLVector2 point, UI_Rect rect) { bool pointInRect(RLVector2 point, UI_Rect rect) {
@@ -729,76 +734,70 @@ void uiPass(Soma *soma, UI_Context *ui) {
} }
void updatePolycubeDisplay(Arena *arena, Soma *soma) { void updatePolycubeDisplay(Arena *arena, Soma *soma) {
if (!soma->prevState.displayingSolutions && soma->state.displayingSolutions) { Scene *s = soma->scene;
if (soma->prevState.displayedPolycube < soma->polycubes.length) {
hide(soma->scene, soma->polycubes.data[soma->state.displayedPolycube]); 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);
} }
} else if (soma->prevState.displayingSolutions && !soma->state.displayingSolutions) { sceneNodeAddNode(s, s->sceneRoot, soma->solutionNode);
if (soma->prevState.displayedSolution < soma->solutionEntities.length) {
hide(soma->scene, soma->solutionEntities.data[soma->state.displayedSolution]);
} }
} }
if (soma->state.displayingSolutions) { if (soma->state.displayingSolutions) {
if (soma->solutions.length > 0) { show(s, soma->solutionNode);
show(soma->scene, soma->solutionEntities.data[soma->state.displayedSolution]); if (soma->prevState.displayedPolycube >= 0 && soma->prevState.displayedPolycube < soma->polycubes.length) {
if (soma->state.displayedSolution != soma->prevState.displayedSolution) { hide(s, soma->polycubes.data[soma->prevState.displayedPolycube]);
hide(soma->scene, soma->solutionEntities.data[soma->prevState.displayedSolution]);
}
} }
} else { } else {
if (soma->polycubes.length > 0) { hide(s, soma->solutionNode);
show(soma->scene, soma->polycubes.data[soma->state.displayedPolycube]); 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->state.displayedPolycube != soma->prevState.displayedPolycube) {
hide(soma->scene, soma->polycubes.data[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.polycubeDirty) {
if (soma->state.displayedPolycube >= 0 && soma->state.displayedPolycube < soma->polycubes.length) { if (soma->state.displayedPolycube >= 0 && soma->state.displayedPolycube < soma->polycubes.length) {
uint32 currentPolycubeHandle = soma->polycubes.data[soma->state.displayedPolycube]; uint32 oldHandle = soma->polycubes.data[soma->state.displayedPolycube];
PolycubeInput *pinput = &soma->polycubeInput.data[soma->state.displayedPolycube]; Quaternion rot = getSceneGraphNode(s, oldHandle)->rotation;
VoxelSpace culledRepr = pinput->repr; removeSceneGraphNode(s, oldHandle);
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);
}
}
}
void createSolutionEntities(Arena *arena, Soma *soma) { PolycubeInput *newInput = &soma->polycubeInput.data[soma->state.displayedPolycube];
if (soma->solutions.length > 0) { VoxelSpace newInputCulled = newInput->repr;
soma->solutionEntities = PushList(arena, HandleList, soma->solutions.length); cullEmptySpace(&newInputCulled);
for (EachEl(soma->solutions, SomaSolution, solution)) {
uint32 solutionGraphNodeHandle = createSceneGraphNode(soma->scene); uint32 newHandle = createPolycubeFromRepr(s, &newInputCulled, newInput->color);
AppendList(&soma->solutionEntities, solutionGraphNodeHandle); getSceneGraphNode(s, newHandle)->rotation = rot;
sceneNodeAddNode(soma->renderer->scene, soma->renderer->scene->sceneRoot, solutionGraphNodeHandle);
for (EachIn(*solution, soln_i)) { soma->polycubes.data[soma->state.displayedPolycube] = newHandle;
uint32 polycubeGraphNodeHandle = createPolycubeFromRepr( sceneNodeAddNode(s, s->sceneRoot, newHandle);
soma->scene,
&(VoxelSpace){ solution->data[soln_i], 3, 3, 3 }, soma->state.polycubeDirty = false;
colorFromIndex(soln_i) show(s, newHandle);
);
sceneNodeAddNode(soma->renderer->scene, solutionGraphNodeHandle, polycubeGraphNodeHandle);
} }
} }
show(soma->scene, soma->solutionEntities.data[soma->state.displayedSolution]);
}
} }
int mainGfx() { int mainGfx() {
Arena *arena = arenaAlloc(Megabytes(128)); Arena *arena = arenaAlloc(Megabytes(128));
Arena *solutionsArena = arenaAlloc(Megabytes(128)); Arena *solutionsArena = arenaAlloc(Megabytes(128));
int winWidth = 800, winHeight = 600; int winWidth = 800;
int winHeight = 600;
GLFWwindow *windowHandle = initWindowAndGL(winWidth, winHeight); GLFWwindow *windowHandle = initWindowAndGL(winWidth, winHeight);
if (!windowHandle) { if (!windowHandle) {
return 1; return 1;
@@ -840,9 +839,9 @@ int mainGfx() {
.taskStatus = SolveTaskStatus_Ready, .taskStatus = SolveTaskStatus_Ready,
}, },
.state = { .state = {
.displayingSolutions = false,
.displayedPolycube = 0, .displayedPolycube = 0,
.displayedSolution = 0, .displayingSolutions = false,
.displayedSolution = -1,
.isInitialState = true, .isInitialState = true,
.light = createEntity(&mainScene), .light = createEntity(&mainScene),
.camera = mainFrame.cam, .camera = mainFrame.cam,
@@ -871,10 +870,10 @@ int mainGfx() {
VoxelSpace voxelSpace = { stdSoma.data[i], 3, 3, 3 }; VoxelSpace voxelSpace = { stdSoma.data[i], 3, 3, 3 };
RLVector4 color = colorFromIndex(i); RLVector4 color = colorFromIndex(i);
PolycubeInput input = (PolycubeInput){ voxelSpace, color }; PolycubeInput input = (PolycubeInput){ voxelSpace, color };
AppendList(&soma.polycubeInput, input); ListAppend(soma.polycubeInput, input);
cullEmptySpace(&voxelSpace); cullEmptySpace(&voxelSpace);
uint32 polycubeGraphNodeHandle = createPolycubeFromRepr(soma.scene, &voxelSpace, color); uint32 polycubeGraphNodeHandle = createPolycubeFromRepr(soma.scene, &voxelSpace, color);
AppendList(&soma.polycubes, polycubeGraphNodeHandle); ListAppend(soma.polycubes, polycubeGraphNodeHandle);
sceneNodeAddNode(renderer.scene, renderer.scene->sceneRoot, polycubeGraphNodeHandle); sceneNodeAddNode(renderer.scene, renderer.scene->sceneRoot, polycubeGraphNodeHandle);
} }
@@ -903,15 +902,13 @@ int mainGfx() {
processInput(&soma, &ui); processInput(&soma, &ui);
if (soma.solveTaskCtx.taskStatus == SolveTaskStatus_Complete) { if (soma.solveTaskCtx.taskStatus == SolveTaskStatus_Complete) {
soma.solutions = PushFullList(solutionsArena, SomaSolutionList, soma.solveTaskCtx.solutions.length); soma.solutions = PushList(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.solveTaskCtx.solutions, i)) {
for (EachIn(soma.solutions, i)) { ListAppend(soma.solutions, PushListCopy(solutionsArena, SomaSolution, soma.solveTaskCtx.solutions.data[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));
} }
createSolutionEntities(arena, &soma);
soma.solveTaskCtx.taskStatus = SolveTaskStatus_Ready; soma.solveTaskCtx.taskStatus = SolveTaskStatus_Ready;
soma.state.displayingSolutions = true; soma.state.displayingSolutions = true;
soma.state.displayedSolution = 0;
arenaFreeFrom(soma.solveTaskCtx.arena, 0); arenaFreeFrom(soma.solveTaskCtx.arena, 0);
} }

View File

@@ -289,15 +289,15 @@ void test() {
for (int i = 0; i < 6; i++) { for (int i = 0; i < 6; i++) {
if (positions1.data[i] != expected_results1[i]) { if (positions1.data[i] != expected_results1[i]) {
MismatchData data = { i, 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]) { if (positions2.data[i] != expected_results2[i]) {
MismatchData data = { i, 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]) { if (positions3.data[i] != expected_results3[i]) {
MismatchData data = { i, 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); Assert(mismatches1.length == 0);

View File

@@ -1,44 +1,60 @@
#include "string.h"
#include "scene.h" #include "scene.h"
Entity *getEntity(Scene *s, uint32 entityHandle) { Entity *getEntity(Scene *s, int32 entityHandle) {
if (entityHandle) { return &s->entities.data[entityHandle];
return &s->entities.data[entityHandle - 1]; }
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;
} }
return NULL; newNode->next = 0;
} } else {
ListAppend(s->graphNodes, (SceneGraphNode){0});
SceneGraphNode *getSceneGraphNode(Scene *s, uint32 sceneGraphNodeHandle) { newNodeHandle = (int32)s->graphNodes.length - 1;
if (sceneGraphNodeHandle) { newNode = getSceneGraphNode(s, newNodeHandle);
return &s->graphNodes.data[sceneGraphNodeHandle - 1]; newNode->nextSibling = 0;
} }
return NULL; initGraphNode(newNode);
return newNodeHandle;
} }
SceneGraphNode *getSceneGraphNodeForEntity(Scene *s, uint32 entityHandle) { int32 createEntity(Scene *s) {
Entity *e = getEntity(s, entityHandle); Entity *newEntity;
if (e) { int32 newEntityHandle;
return getSceneGraphNode(s, e->graphNodeHandle); 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;
} }
return NULL; newEntity->next = 0;
} } else {
ListAppend(s->entities, (Entity){0});
uint32 createSceneGraphNode(Scene *s) { newEntityHandle = (int32)s->entities.length - 1;
AppendList(&s->graphNodes, (SceneGraphNode){0}); newEntity = getEntity(s, newEntityHandle);
SceneGraphNode *node = &s->graphNodes.data[s->graphNodes.length - 1]; }
node->children = PushList(s->arena, HandleList, 1000); newEntity->graphNodeHandle = createSceneGraphNode(s);
initGraphNode(node); getSceneGraphNodeForEntity(s, newEntityHandle)->entityHandle = newEntityHandle;
return (uint32)s->graphNodes.length; return newEntityHandle;
}
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;
} }
void initGraphNode(SceneGraphNode *n) { void initGraphNode(SceneGraphNode *n) {
@@ -49,32 +65,32 @@ void initGraphNode(SceneGraphNode *n) {
n->world = n->local; n->world = n->local;
} }
void recalcGraphNode(SceneGraphNode *n) {
n->local = MatrixCompose(n->translation, n->rotation, n->scale);
}
Scene createScene(Arena *arena) { Scene createScene(Arena *arena) {
Scene result = { Scene result = {
.arena = arena, .entities = PushListZero(arena, EntityList, 100000),
.entities = PushList(arena, EntityList, 100000), .nextFreeEntity = 0,
.graphNodes = PushList(arena, SceneGraphNodeList, 100000), .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); result.sceneRoot = createSceneGraphNode(&result);
return result; return result;
} }
void recalcSceneGraphNode(Scene *s, uint32 parentHandle) { void recalcSceneGraphNode(Scene *s, int32 parentHandle) {
SceneGraphNode *node = getSceneGraphNode(s, parentHandle); if (!parentHandle) return;
if (node->entityHandle) { SceneGraphNode *parentNode = getSceneGraphNode(s, parentHandle);
getEntity(s, node->entityHandle)->flags |= EntityFlags_Render; getEntity(s, parentNode->entityHandle)->flags |= EntityFlags_Render;
} int32 nextChild = parentNode->firstChild;
for (EachIn(node->children, i)) { while (nextChild) {
uint32 nodeId = node->children.data[i]; SceneGraphNode *childNode = getSceneGraphNode(s, nextChild);
SceneGraphNode *graphNode = getSceneGraphNode(s, nodeId); childNode->parentHandle = parentHandle;
graphNode->parentHandle = parentHandle; childNode->local = MatrixCompose(childNode->translation, childNode->rotation, childNode->scale);
recalcGraphNode(graphNode); childNode->world = MatrixMultiply(childNode->local, parentNode->world);
graphNode->world = MatrixMultiply(graphNode->local, node->world); recalcSceneGraphNode(s, nextChild);
recalcSceneGraphNode(s, nodeId); nextChild = childNode->nextSibling;
} }
} }
@@ -82,31 +98,73 @@ void recalcScene(Scene *s) {
recalcSceneGraphNode(s, s->sceneRoot); recalcSceneGraphNode(s, s->sceneRoot);
} }
void removeEntity(Scene *s, uint32 entityHandle) { function void removeSceneGraphNodeRecursive(Scene *s, int32 graphNodeHandle, bool deletingParent) {
Entity *entity = getEntity(s, entityHandle); if (!graphNodeHandle) return;
entity->flags |= EntityFlags_Dead; SceneGraphNode *graphNode = getSceneGraphNode(s, graphNodeHandle);
SceneGraphNode *graphNode = getSceneGraphNode(s, entity->graphNodeHandle);
if (graphNode != NULL && graphNode->parentHandle) { 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); SceneGraphNode *parentNode = getSceneGraphNode(s, graphNode->parentHandle);
if (parentNode != NULL) { if (parentNode->firstChild == graphNodeHandle) {
for (EachIn(parentNode->children, i)) { if (graphNode->nextSibling) {
if (parentNode->children.data[i] == entity->graphNodeHandle) { parentNode->firstChild = graphNode->nextSibling;
memcpy(parentNode->children.data + i, parentNode->children.data + i + 1, parentNode->children.length - i - 1); } else {
//ListRemove(&parentNode->children, i); parentNode->firstChild = 0;
graphNode->parentHandle = 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; break;
} }
nextSibling = siblingNode->nextSibling;
} }
} }
} }
graphNode->firstChild = 0;
graphNode->parentHandle = 0;
graphNode->entityHandle = 0;
graphNode->nextSibling = 0;
} }
void sceneNodeAddEntity(Scene *s, uint32 graphNodeHandle, uint32 entityHandle) { void removeSceneGraphNode(Scene *s, int32 graphNodeHandle) {
HandleList *childList = &getSceneGraphNode(s, graphNodeHandle)->children; removeSceneGraphNodeRecursive(s, graphNodeHandle, false);
AppendList(childList, getEntity(s, entityHandle)->graphNodeHandle);
} }
void sceneNodeAddNode(Scene *s, uint32 recipientNodeHandle, uint32 graphNodeHandle) { void removeEntity(Scene *s, int32 entityHandle) {
HandleList *childList = &getSceneGraphNode(s, recipientNodeHandle)->children; if (!entityHandle) return;
AppendList(childList, graphNodeHandle); 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;
} }

View File

@@ -1,9 +1,10 @@
#include "../gfx/gfx.h" #include "../gfx/gfx.h"
#include "../lib/raymath.h" #include "../lib/raymath.h"
DefineList(uint32, Handle); DefineList(int32, Handle);
enum EntityFlags { enum EntityFlags {
EntityFlags_None=0,
EntityFlags_Visible=1<<0, EntityFlags_Visible=1<<0,
EntityFlags_Dead=1<<1, EntityFlags_Dead=1<<1,
EntityFlags_Render=1<<2, EntityFlags_Render=1<<2,
@@ -11,11 +12,14 @@ enum EntityFlags {
typedef struct Entity Entity; typedef struct Entity Entity;
struct Entity { struct Entity {
uint32 graphNodeHandle; int32 graphNodeHandle;
uint64 flags; uint64 flags;
RLVector4 color; RLVector4 color;
Mesh *mesh; Mesh *mesh;
Texture *tex; Texture *tex;
// Free list
int32 next;
}; };
DefineList(Entity, Entity); DefineList(Entity, Entity);
@@ -26,30 +30,36 @@ struct SceneGraphNode {
RLVector3 translation; RLVector3 translation;
Quaternion rotation; Quaternion rotation;
RLVector3 scale; RLVector3 scale;
HandleList children; int32 entityHandle;
uint32 entityHandle; int32 parentHandle;
uint32 parentHandle;
// Free list
int32 next;
// Children
int32 nextSibling;
int32 firstChild;
}; };
DefineList(SceneGraphNode, SceneGraphNode); DefineList(SceneGraphNode, SceneGraphNode);
typedef struct Scene Scene; typedef struct Scene Scene;
struct Scene { struct Scene {
uint32 sceneRoot; int32 sceneRoot;
EntityList entities; EntityList entities;
int32 nextFreeEntity;
SceneGraphNodeList graphNodes; SceneGraphNodeList graphNodes;
Arena *arena; int32 nextFreeNode;
}; };
uint32 createEntity(Scene *s); int32 createEntity(Scene *s);
Entity *getEntity(Scene *s, uint32 id); Entity *getEntity(Scene *s, int32 id);
SceneGraphNode *getSceneGraphNode(Scene *s, uint32 id); SceneGraphNode *getSceneGraphNode(Scene *s, int32 id);
uint32 createSceneGraphNode(Scene *s); int32 createSceneGraphNode(Scene *s);
Scene createScene(Arena *arena); Scene createScene(Arena *arena);
void initGraphNode(SceneGraphNode *n); void initGraphNode(SceneGraphNode *n);
void recalcGraphNode(SceneGraphNode *n); void recalcSceneGraphNode(Scene *s, int32 parentHandle);
void recalcSceneGraphNode(Scene *s, uint32 parentHandle);
void recalcScene(Scene *s); void recalcScene(Scene *s);
void removeEntity(Scene *s, uint32 entityHandle); void removeEntity(Scene *s, int32 entityHandle);
void sceneNodeAddNode(Scene *s, uint32 recipientNodeHandle, uint32 graphNodeHandle); void removeSceneGraphNode(Scene *s, int32 graphNodeHandle);
void sceneNodeAddEntity(Scene *s, uint32 graphNodeHandle, uint32 entityHandle); void sceneNodeAddNode(Scene *s, int32 recipientNodeHandle, int32 graphNodeHandle);
SceneGraphNode *getSceneGraphNodeForEntity(Scene *s, uint32 entityHandle); SceneGraphNode *getSceneGraphNodeForEntity(Scene *s, int32 entityHandle);