197 lines
6.6 KiB
C
197 lines
6.6 KiB
C
#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;
|
|
}
|
|
}
|
|
|