diff --git a/src/SomaSolve.c b/src/SomaSolve.c index 3e0f1f8..099505c 100644 --- a/src/SomaSolve.c +++ b/src/SomaSolve.c @@ -220,13 +220,13 @@ uint64 factorial(int n) { return result; } -SomaSolutionList solve(VoxelSpaceReprList reprsInput, int dims[3]) { - Arena *arena = arenaAlloc(Megabytes(64)); +SomaSolutionList solveSoma(Arena *solutionsArena, VoxelSpaceReprList reprsInput, int dims[3]) { + Arena *generalArena = arenaAlloc(Megabytes(64)); Arena *permsArena = arenaAlloc(Megabytes(128)); - OffsetList offsets = PushList(arena, OffsetList, reprsInput.length + 1); + OffsetList offsets = PushList(generalArena, OffsetList, reprsInput.length + 1); - VoxelSpaceReprList polycubes = PushList(arena, VoxelSpaceReprList, 0); + VoxelSpaceReprList polycubes = PushList(generalArena, VoxelSpaceReprList, 0); VoxelSpace emptyVoxelSpace = { 0, @@ -245,7 +245,7 @@ SomaSolutionList solve(VoxelSpaceReprList reprsInput, int dims[3]) { cullEmptySpace(&voxelSpace); VoxelSpaceReprList positions = getAllPositionsInPrism(permsArena, &voxelSpace, dims); possibleCombos += positions.length; - VoxelSpaceReprList_underlying *insertion = PushArray(arena, uint64, positions.capacity); + VoxelSpaceReprList_underlying *insertion = PushArray(generalArena, uint64, positions.capacity); polycubes.capacity += positions.capacity; polycubes.length += positions.length; memcpy(insertion, positions.data, positions.capacity * ListElementSize(VoxelSpaceReprList)); @@ -258,7 +258,7 @@ SomaSolutionList solve(VoxelSpaceReprList reprsInput, int dims[3]) { cullEmptySpace(&space); VoxelSpaceReprList perms = getAllPermutationsInPrism(permsArena, &space, dims); possibleCombos *= perms.length; - VoxelSpaceReprList_underlying *insertion = PushArray(arena, VoxelSpaceReprList_underlying, perms.capacity); + VoxelSpaceReprList_underlying *insertion = PushArray(generalArena, VoxelSpaceReprList_underlying, perms.capacity); polycubes.capacity += perms.capacity; polycubes.length += perms.length; memcpy(insertion, perms.data, perms.capacity * ListElementSize(VoxelSpaceReprList)); @@ -277,14 +277,19 @@ SomaSolutionList solve(VoxelSpaceReprList reprsInput, int dims[3]) { backtrackSolve(permsArena, &solver, 0, 0); - return filterUnique(permsArena, solver.solutions, dims); + SomaSolutionList uniqueSolns = filterUnique(solutionsArena, solver.solutions, dims); + + arenaFree(permsArena); + arenaFree(generalArena); + + return uniqueSolns; } void interactiveCmdLineSolveSoma() { //get_dims_input(dims); //std::cout << '\n'; //std::vector reprs = get_reprs_input(dims[0]*dims[1]*dims[2]); - print("Great. Calculating solutions...\n"); - SomaSolutionList solutions = solve(AsList(VoxelSpaceReprList, STD_SOMA), (int[]){ 3, 3, 3 }); - print("%zu solutions found.\n", solutions.length); + //print("Great. Calculating solutions...\n"); + //SomaSolutionList solutions = solveSoma(AsList(VoxelSpaceReprList, STD_SOMA), (int[]){ 3, 3, 3 }); + //print("%zu solutions found.\n", solutions.length); } diff --git a/src/SomaSolve.h b/src/SomaSolve.h index 67c5a10..2def427 100644 --- a/src/SomaSolve.h +++ b/src/SomaSolve.h @@ -5,5 +5,5 @@ typedef VoxelSpaceReprList SomaSolution; DefineList(SomaSolution, SomaSolution); -SomaSolutionList solve(VoxelSpaceReprList reprs_in, int dims[3]); -void interactive_cmd_line_solve_soma(); +SomaSolutionList solveSoma(Arena *solutionsArena, VoxelSpaceReprList reprs_in, int dims[3]); +void interactiveCmdLineSolveSoma(); diff --git a/src/main.c b/src/main.c index 3e76725..fdcaa25 100644 --- a/src/main.c +++ b/src/main.c @@ -76,14 +76,6 @@ struct Frame { Camera* cam; }; -typedef struct Polycube Polycube; -struct Polycube { - uint32 entityHandle; - VoxelSpace repr; - RLVector4 color; -}; -DefineList(Polycube, Polycube); - DefineList(RLVector2, RLVec2); DefineList(RLVector4, RLVec4); DefineList(real32, Float); @@ -154,60 +146,65 @@ typedef struct SomaState SomaState; struct SomaState { bool wireframe; bool polycubeDirty; - uint32 currentPolycube; - uint32 lastPolycubeVisible; + uint32 displayedPolycube; + size_t displayedSolution; + bool displayingSolutions; uint32 light; - PolycubeList polycubes; Camera* camera; RLVector3 rotAxisX; RLVector3 rotAxisY; - PolycubeInputList polycubeInput; + Input input; }; typedef struct Soma Soma; struct Soma { Scene *scene; Renderer *renderer; - SomaState state; - Input currInput; - Input prevInput; struct { GLFWwindow *handle; uint32 width; uint32 height; } window; + + SomaState prevState; + SomaState state; + + PolycubeInputList polycubeInput; + HandleList polycubes; + SomaSolutionList solutions; + HandleList solutionEntities; }; -void showEntity(Scene *scene, uint32 entityHandle) { - SceneGraphNode *node = getSceneGraphNodeForEntity(scene, entityHandle); +void show(Scene *s, uint32 graphNodeHandle) { + SceneGraphNode *node = getSceneGraphNode(s, graphNodeHandle); + if (node->entityHandle) { + getEntity(s, node->entityHandle)->flags |= EntityFlags_Visible; + } for (EachIn(node->children, i)) { uint32 child = node->children.data[i]; - SceneGraphNode *subNode = getSceneGraphNode(scene, child); - if (subNode->entityHandle) { - getEntity(scene, subNode->entityHandle)->flags |= EntityFlags_Visible; - } + show(s, child); } } -void hideEntity(Scene *scene, uint32 entityHandle) { - SceneGraphNode *node = getSceneGraphNodeForEntity(scene, entityHandle); +void hide(Scene *s, uint32 graphNodeHandle) { + SceneGraphNode *node = getSceneGraphNode(s, graphNodeHandle); + if (node->entityHandle) { + getEntity(s, node->entityHandle)->flags &= ~EntityFlags_Visible; + } for (EachIn(node->children, i)) { uint32 child = node->children.data[i]; - SceneGraphNode *subNode = getSceneGraphNode(scene, child); - if (subNode->entityHandle) { - getEntity(scene, subNode->entityHandle)->flags &= ~EntityFlags_Visible; - } + hide(s, child); } } -RLVector3 centreFromPolycube(Scene *scene, Polycube *p) { +RLVector3 centreFromPolycube(Scene *scene, uint32 p) { RLVector3 centre = (RLVector3){0,0,0}; - HandleList *children = &getSceneGraphNode(scene, p->entityHandle)->children; + HandleList *children = &getSceneGraphNode(scene, p)->children; for (EachIn(*children, i)) { uint32 child = children->data[i]; centre = Vector3Add(centre, getSceneGraphNode(scene, child)->translation); } - centre = Vector3Scale(centre, 1.0f/(getSceneGraphNodeForEntity(scene, p->entityHandle)->children.length)); + centre = Vector3Scale(centre, 1.0f/(getSceneGraphNode(scene, p)->children.length)); return centre; } @@ -328,8 +325,8 @@ Input getCurrentInput(GLFWwindow *window) { } void processInput(Soma *soma) { - Input *input = &soma->currInput; - Input *prevInput = &soma->prevInput; + Input *input = &soma->state.input; + Input *prevInput = &soma->prevState.input; if (input->keyboard.escape) { glfwSetWindowShouldClose(soma->window.handle, true); @@ -347,39 +344,49 @@ void processInput(Soma *soma) { node->translation.z += 1.0 * input->keyboard.z * shiftMultiplier; if (input->keyboard.enter && !prevInput->keyboard.enter) { - if (soma->state.currentPolycube == 6) { - soma->state.currentPolycube = 0; + if (soma->state.displayingSolutions) { + if (soma->state.displayedSolution == soma->solutions.length - 1) { + soma->state.displayedSolution = 0; + } else { + soma->state.displayedSolution += 1; + } } else { - soma->state.currentPolycube += 1; + if (soma->state.displayedPolycube == 6) { + soma->state.displayedPolycube = 0; + } else { + soma->state.displayedPolycube += 1; + } } - } + } bool dragScene = false; if (input->mouse.btnLeft) { - Polycube *current_polycube = &soma->state.polycubes.data[soma->state.currentPolycube]; - SceneGraphNode *polycubeGraphNode = getSceneGraphNodeForEntity(soma->scene, current_polycube->entityHandle); + uint32 currentObject = soma->state.displayingSolutions + ? soma->solutionEntities.data[soma->state.displayedSolution] + : soma->polycubes.data[soma->state.displayedPolycube]; + SceneGraphNode *objectGraphNode = getSceneGraphNode(soma->scene, currentObject); real64 deltaX = (input->mouse.x - prevInput->mouse.x) * 0.005; if (deltaX > 0.00000001 || deltaX < -0.00000001) { - polycubeGraphNode->rotation = QuaternionMultiply(polycubeGraphNode->rotation, QuaternionFromAxisAngle(soma->state.rotAxisY, -(real32)deltaX)); + objectGraphNode->rotation = QuaternionMultiply(objectGraphNode->rotation, QuaternionFromAxisAngle(soma->state.rotAxisY, -(real32)deltaX)); } real64 deltaY = (input->mouse.y - prevInput->mouse.y) * 0.005; if (deltaY > 0.00000001 || deltaY < -0.00000001) { - polycubeGraphNode->rotation = QuaternionMultiply(QuaternionFromAxisAngle(soma->state.rotAxisX, -(real32)deltaY), polycubeGraphNode->rotation); + objectGraphNode->rotation = QuaternionMultiply(QuaternionFromAxisAngle(soma->state.rotAxisX, -(real32)deltaY), objectGraphNode->rotation); } } } -Polycube createPolycubeFromRepr(Arena *arena, Scene *s, VoxelSpace *repr, RLVector4 color) { - uint32 polycubeMainEntityHandle = createEntity(arena, s); - Entity *polycubeMainEntity = getEntity(s, polycubeMainEntityHandle); +uint32 createPolycubeFromRepr(Arena *arena, Scene *s, VoxelSpace *repr, RLVector4 color) { + uint32 mainGraphNode = createSceneGraphNode(arena, s); for (int x = 0; x < repr->dim_x; x++) { for (int y = 0; y < repr->dim_y; y++) { for (int z = 0; z < repr->dim_z; z++) { if (filledAt(repr, x, y, z)) { uint32 segmentEntityHandle = createEntity(arena, s); Entity *polycubeSegment = getEntity(s, segmentEntityHandle); + polycubeSegment->color = color; polycubeSegment->mesh = &cubeMesh; polycubeSegment->tex = &wallTex; SceneGraphNode *graphNode = getSceneGraphNode(s, polycubeSegment->graphNodeHandle); @@ -388,19 +395,15 @@ Polycube createPolycubeFromRepr(Arena *arena, Scene *s, VoxelSpace *repr, RLVect -((repr->dim_x - 1)/2.0f) + x, ((repr->dim_y - 1)/2.0f) - y }; - sceneNodeAddEntity(s, polycubeMainEntity->graphNodeHandle, segmentEntityHandle); + sceneNodeAddNode(s, mainGraphNode, polycubeSegment->graphNodeHandle); } } } } - Polycube result = {}; - result.entityHandle = polycubeMainEntityHandle; - result.color = color; - result.repr = *repr; - SceneGraphNode *graphNode = getSceneGraphNodeForEntity(s, polycubeMainEntityHandle); + SceneGraphNode *graphNode = getSceneGraphNode(s, mainGraphNode); graphNode->rotation = QuaternionMultiply(graphNode->rotation, QuaternionFromAxisAngle((RLVector3){1, 0, 0}, PI / 4)); graphNode->rotation = QuaternionMultiply(graphNode->rotation, QuaternionFromAxisAngle((RLVector3){0, 1, 0}, -PI / 4)); - return result; + return mainGraphNode; } RenderObjects_Rectangle createRectangleObjects(Arena *arena, size_t count) { @@ -491,7 +494,6 @@ Renderer createRenderer(Arena *arena, Scene *scene) { result.scene = scene; result.scene->sceneRoot = createSceneGraphNode(arena, scene); result.rects = createRectangleObjects(arena, 100); - initGraphNode(getSceneGraphNode(scene, scene->sceneRoot)); return result; } @@ -517,15 +519,15 @@ void renderEnd(Soma *soma, Renderer *renderer) { setUniform3fv(&phongShader, "light_pos", &lightGraphNode->translation); setUniform3fv(&phongShader, "camera", &soma->state.camera->pos); - Polycube *currentPolycube = &soma->state.polycubes.data[soma->state.currentPolycube]; + uint32 currentPolycube = soma->polycubes.data[soma->state.displayedPolycube]; glBindVertexArray(cubeMesh.vao); - setUniform4fv(&phongShader, "solid_color", ¤tPolycube->color); int model_uniform = getUniformLocation(&phongShader, "model"); for (EachIn(renderer->scene->entities, i)) { Entity *entity = &renderer->scene->entities.data[i]; if (entity->flags & EntityFlags_Render && entity->flags & EntityFlags_Visible) { + setUniform4fv(&phongShader, "solid_color", &entity->color); setUniformMat4fvByLoc(model_uniform, &getSceneGraphNode(renderer->scene, entity->graphNodeHandle)->world); glBindTexture(GL_TEXTURE_2D, entity->tex->tex_id); glDrawArrays(GL_TRIANGLES, 0, (GLsizei)entity->mesh->num_indices); @@ -587,7 +589,7 @@ bool ui_checkboxRect(UI_Context *ui, bool *value, UI_Rect rect) { } void uiPass(Soma *soma, UI_Context *ui, Renderer *renderer) { - PolycubeInput *currentPolycube = &soma->state.polycubeInput.data[soma->state.currentPolycube]; + PolycubeInput *currentPolycube = &soma->polycubeInput.data[soma->state.displayedPolycube]; real32 boxSize = 30; real32 padding = 20; @@ -646,10 +648,12 @@ int mainGfx() { GLFWcursor *pointerCursor = glfwCreateStandardCursor(GLFW_HAND_CURSOR); GLFWcursor *arrowCursor = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); - soma.state.currentPolycube = 0; - soma.state.lastPolycubeVisible = 6; - soma.state.polycubeInput = PushListZero(arena, PolycubeInputList, 64); - soma.state.polycubes = PushListZero(arena, PolycubeList, 64); + soma.polycubeInput = PushListZero(arena, PolycubeInputList, 64); + soma.polycubes = PushListZero(arena, HandleList, 64); + + soma.state.displayingSolutions = true; + soma.state.displayedPolycube = 0; + soma.state.displayedSolution = 0; soma.state.light = createEntity(arena, &mainScene); soma.state.camera = mainFrame.cam; @@ -678,18 +682,38 @@ int mainGfx() { VoxelSpace voxelSpace = { stdSoma.data[i], 3, 3, 3 }; RLVector4 color = colorFromIndex(i); PolycubeInput input = (PolycubeInput){ voxelSpace, color }; - AppendList(&soma.state.polycubeInput, input); + AppendList(&soma.polycubeInput, input); cullEmptySpace(&voxelSpace); - Polycube polycube = createPolycubeFromRepr(arena, soma.scene, &voxelSpace, color); - polycube.color = color; - AppendList(&soma.state.polycubes, polycube); - sceneNodeAddEntity(renderer.scene, renderer.scene->sceneRoot, polycube.entityHandle); + uint32 polycubeGraphNodeHandle = createPolycubeFromRepr(arena, soma.scene, &voxelSpace, color); + AppendList(&soma.polycubes, polycubeGraphNodeHandle); + sceneNodeAddNode(renderer.scene, renderer.scene->sceneRoot, polycubeGraphNodeHandle); } + soma.solutions = solveSoma(arena, AsList(VoxelSpaceReprList, STD_SOMA), (int[]){ 3, 3, 3 }); + soma.solutionEntities = PushList(arena, HandleList, soma.solutions.length); + for (EachEl(soma.solutions, SomaSolution, solution)) { + uint32 solutionGraphNodeHandle = createSceneGraphNode(arena, soma.scene); + AppendList(&soma.solutionEntities, solutionGraphNodeHandle); + sceneNodeAddNode(renderer.scene, renderer.scene->sceneRoot, solutionGraphNodeHandle); + for (EachIn(*solution, soln_i)) { + uint32 polycubeGraphNodeHandle = createPolycubeFromRepr( + arena, + soma.scene, + &(VoxelSpace){ solution->data[soln_i], 3, 3, 3 }, + colorFromIndex(soln_i) + ); + sceneNodeAddNode(renderer.scene, solutionGraphNodeHandle, polycubeGraphNodeHandle); + } + } + show(soma.scene, soma.solutionEntities.data[soma.state.displayedSolution]); + + print("%zu\n", soma.scene->entities.length); + print("%zu\n", soma.scene->graphNodes.length); + soma.state.camera->pos = (RLVector3){0.0f, 0.0f, 8.0f}; cameraLookAt(soma.state.camera, 0.0f, 0.0f, 0.0f); - SceneGraphNode *reference_polycube_gn = getSceneGraphNodeForEntity(soma.scene, soma.state.polycubes.data[0].entityHandle); + SceneGraphNode *reference_polycube_gn = getSceneGraphNode(soma.scene, soma.polycubes.data[0]); Matrix worldInverse = MatrixInvert(reference_polycube_gn->world); soma.state.rotAxisY = Vector3Normalize((RLVector3){worldInverse.m4, worldInverse.m5, worldInverse.m6}); RLVector3 eyes = Vector3Normalize(Vector3Subtract(soma.state.camera->pos, reference_polycube_gn->translation)); @@ -702,27 +726,35 @@ int mainGfx() { real64 frameStart = glfwGetTime(); glfwPollEvents(); - soma.currInput = getCurrentInput(soma.window.handle); + soma.state.input = getCurrentInput(soma.window.handle); processInput(&soma); + /* if (soma.state.lastPolycubeVisible != soma.state.currentPolycube) { - hideEntity(soma.scene, soma.state.polycubes.data[soma.state.lastPolycubeVisible].entityHandle); - showEntity(soma.scene, soma.state.polycubes.data[soma.state.currentPolycube].entityHandle); + hide(soma.scene, soma.state.polycubes.data[soma.state.lastPolycubeVisible].graphNodeHandle); + show(soma.scene, soma.state.polycubes.data[soma.state.currentPolycube].graphNodeHandle); soma.state.lastPolycubeVisible = soma.state.currentPolycube; } + */ + + if (soma.state.displayedSolution != soma.prevState.displayedSolution) { + show(soma.scene, soma.solutionEntities.data[soma.state.displayedSolution]); + hide(soma.scene, soma.solutionEntities.data[soma.prevState.displayedSolution]); + } + if (soma.state.polycubeDirty) { - Polycube *currentPolycube = &soma.state.polycubes.data[soma.state.currentPolycube]; - PolycubeInput *pinput = &soma.state.polycubeInput.data[soma.state.currentPolycube]; - removeEntity(soma.scene, currentPolycube->entityHandle); + uint32 currentPolycube = soma.polycubes.data[soma.state.displayedPolycube]; + PolycubeInput *pinput = &soma.polycubeInput.data[soma.state.displayedPolycube]; + removeEntity(soma.scene, currentPolycube); VoxelSpace culledRepr = pinput->repr; cullEmptySpace(&culledRepr); - Polycube newPolycube = createPolycubeFromRepr(arena, soma.scene, &culledRepr, pinput->color); - SceneGraphNode *graphNode = getSceneGraphNodeForEntity(soma.scene, newPolycube.entityHandle); - graphNode->rotation = getSceneGraphNodeForEntity(soma.scene, currentPolycube->entityHandle)->rotation; - soma.state.polycubes.data[soma.state.currentPolycube] = newPolycube; - sceneNodeAddEntity(soma.scene, soma.scene->sceneRoot, newPolycube.entityHandle); + uint32 newPolycube = createPolycubeFromRepr(arena, soma.scene, &culledRepr, pinput->color); + SceneGraphNode *graphNode = getSceneGraphNode(soma.scene, newPolycube); + graphNode->rotation = getSceneGraphNode(soma.scene, currentPolycube)->rotation; + soma.polycubes.data[soma.state.displayedPolycube] = newPolycube; + sceneNodeAddNode(soma.scene, soma.scene->sceneRoot, newPolycube); soma.state.polycubeDirty = false; - showEntity(soma.scene, newPolycube.entityHandle); + show(soma.scene, newPolycube); } updateViewportFromFrame(soma.window.width, soma.window.height, &mainFrame); @@ -731,8 +763,8 @@ int mainGfx() { renderBegin(&renderer); ui.cursorIsPointer = false; - ui.prevInput = &soma.prevInput; - ui.input = &soma.currInput; + ui.prevInput = &soma.prevState.input; + ui.input = &soma.state.input; ui.renderer = &renderer; uiPass(&soma, &ui, &renderer); if (ui.cursorIsPointer) { @@ -750,7 +782,7 @@ int mainGfx() { glfwSwapBuffers(soma.window.handle); - soma.prevInput = soma.currInput; + soma.prevState = soma.state; } glfwTerminate(); @@ -759,6 +791,6 @@ int mainGfx() { int main() { initialiseDjStdCore(); - return mainCmd(); + return mainGfx(); } diff --git a/src/world/scene.c b/src/world/scene.c index 1b1b725..e7c7c62 100644 --- a/src/world/scene.c +++ b/src/world/scene.c @@ -15,7 +15,9 @@ SceneGraphNode *getSceneGraphNode(Scene *s, uint32 sceneGraphNodeHandle) { uint32 createSceneGraphNode(Arena *arena, Scene *s) { AppendList(&s->graphNodes, (SceneGraphNode){0}); - s->graphNodes.data[s->graphNodes.length - 1].children = PushList(arena, HandleList, 64); + SceneGraphNode *node = &s->graphNodes.data[s->graphNodes.length - 1]; + node->children = PushList(arena, HandleList, 1000); + initGraphNode(node); return (uint32)s->graphNodes.length; } @@ -26,7 +28,6 @@ uint32 createEntity(Arena *arena, Scene *s) { getSceneGraphNode(s, graphNodeId)->entityHandle = (uint32)s->entities.length; uint32 handle = (uint32)s->entities.length; uint32 graphNodeHandle = (uint32)s->graphNodes.length; - initGraphNode(getSceneGraphNode(s, graphNodeHandle)); return handle; } @@ -44,8 +45,8 @@ void recalcGraphNode(SceneGraphNode *n) { Scene createScene(Arena *arena) { Scene result = {}; - result.entities = PushList(arena, EntityList, 1024); - result.graphNodes = PushList(arena, SceneGraphNodeList, 1024); + result.entities = PushList(arena, EntityList, 100000); + result.graphNodes = PushList(arena, SceneGraphNodeList, 100000); result.sceneRoot = createSceneGraphNode(arena, &result); return result; } @@ -90,3 +91,8 @@ void sceneNodeAddEntity(Scene *s, uint32 graphNodeHandle, uint32 entityHandle) { HandleList *childList = &getSceneGraphNode(s, graphNodeHandle)->children; AppendList(childList, getEntity(s, entityHandle)->graphNodeHandle); } + +void sceneNodeAddNode(Scene *s, uint32 recipientNodeHandle, uint32 graphNodeHandle) { + HandleList *childList = &getSceneGraphNode(s, recipientNodeHandle)->children; + AppendList(childList, graphNodeHandle); +} diff --git a/src/world/scene.h b/src/world/scene.h index 3d83d3b..29c03dd 100644 --- a/src/world/scene.h +++ b/src/world/scene.h @@ -11,10 +11,11 @@ enum EntityFlags { typedef struct Entity Entity; struct Entity { - Mesh *mesh; - Texture *tex; uint32 graphNodeHandle; uint64 flags; + RLVector4 color; + Mesh *mesh; + Texture *tex; }; DefineList(Entity, Entity); @@ -48,5 +49,6 @@ void recalcGraphNode(SceneGraphNode *n); void recalcSceneGraphNode(Scene *s, uint32 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);