#include "../../core.h" #include "scene.h" 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; } initGraphNode(newNode); return newNodeHandle; } int32 createEntity(Scene *s) { Entity *newEntity; int32 newEntityHandle; 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); } newEntity->graphNodeHandle = createSceneGraphNode(s); getSceneGraphNodeForEntity(s, newEntityHandle)->entityHandle = newEntityHandle; return newEntityHandle; } void initGraphNode(SceneGraphNode *n) { n->scale = (Vec3){1.0f, 1.0f, 1.0f}; n->translation = (Vec3){0.0f, 0.0f, 0.0f}; n->rotation = (Quaternion){1.0f, 0.0f, 0.0f, 0.0f}; n->local = MatrixIdentity(); n->world = n->local; } Scene createScene(Arena *arena) { Scene result = { .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, 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; } } void recalcScene(Scene *s) { recalcSceneGraphNode(s, s->sceneRoot); } static void removeSceneGraphNodeRecursive(Scene *s, int32 deletedNodeHandle, bool deletingParent) { if (!deletedNodeHandle) return; SceneGraphNode *deletedNode = getSceneGraphNode(s, deletedNodeHandle); int32 nextChild = deletedNode->firstChild; while (nextChild) { int32 sibling = getSceneGraphNode(s, nextChild)->nextSibling; removeSceneGraphNodeRecursive(s, nextChild, true); nextChild = sibling; } if (deletedNode->entityHandle) { Entity *entity = getEntity(s, deletedNode->entityHandle); *entity = (Entity){0}; if (s->nextFreeEntity) { entity->next = s->nextFreeEntity; } s->nextFreeEntity = deletedNode->entityHandle; } if (s->nextFreeNode) { deletedNode->next = s->nextFreeNode; } s->nextFreeNode = deletedNodeHandle; if (!deletingParent && deletedNode->parentHandle) { SceneGraphNode *parentNode = getSceneGraphNode(s, deletedNode->parentHandle); if (parentNode->firstChild == deletedNodeHandle) { if (deletedNode->nextSibling) { parentNode->firstChild = deletedNode->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 == deletedNodeHandle) { SceneGraphNode *prevSiblingNode = getSceneGraphNode(s, prevSibling); prevSiblingNode->nextSibling = deletedNode->nextSibling; break; } prevSibling = nextSibling; nextSibling = siblingNode->nextSibling; } } } deletedNode->firstChild = 0; deletedNode->parentHandle = 0; deletedNode->entityHandle = 0; deletedNode->nextSibling = 0; } void removeSceneGraphNode(Scene *s, int32 graphNodeHandle) { removeSceneGraphNodeRecursive(s, graphNodeHandle, false); } 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; } void show(Scene *s, uint32 graphNodeHandle) { SceneGraphNode *node = getSceneGraphNode(s, graphNodeHandle); if (node->entityHandle) { getEntity(s, node->entityHandle)->flags |= EntityFlags_Visible; } int32 next = node->firstChild; while (next) { show(s, next); next = getSceneGraphNode(s, next)->nextSibling; } } void hide(Scene *s, uint32 graphNodeHandle) { SceneGraphNode *node = getSceneGraphNode(s, graphNodeHandle); if (node->entityHandle) { getEntity(s, node->entityHandle)->flags &= ~EntityFlags_Visible; } int32 next = node->firstChild; while (next) { hide(s, next); next = getSceneGraphNode(s, next)->nextSibling; } }