src/scene.c

changeset 95
622887f7e954
parent 90
aa8e7a38905c
--- a/src/scene.c	Thu Apr 24 18:41:42 2025 +0200
+++ b/src/scene.c	Thu Apr 24 19:53:40 2025 +0200
@@ -28,46 +28,41 @@
 #include "ascension/scene.h"
 
 #include "ascension/context.h"
-#include "ascension/utils.h"
 
 #include "ascension/2d.h"
 
+#include <cx/tree.h>
 #include <cx/linked_list.h>
 #include <cx/array_list.h>
-#include <cx/tree.h>
 #include <cx/utils.h>
 
 #include <GL/glew.h>
 
 #include <assert.h>
 
-static CxTreeIterator asc_scene_node_iterator(
-        AscSceneNode *node,
-        bool visit_on_exit
-) {
-    return cx_tree_iterator(
-            node, visit_on_exit,
-            offsetof(AscSceneNode, children),
-            offsetof(AscSceneNode, next)
-    );
+void asc_scene_init(AscScene *scene) {
+    asc_dprintf("Initialized scene %"PRIxPTR, (uintptr_t) scene);
+    // TODO: how should we initialize the camera?
+    scene->root = asc_scene_node_empty();
 }
 
-static CxTreeVisitor asc_scene_node_visitor(AscSceneNode *node) {
-    return cx_tree_visitor(node,
-            offsetof(AscSceneNode, children),
-            offsetof(AscSceneNode, next)
-    );
+void asc_scene_destroy(AscScene *scene) {
+    asc_dprintf("Destroyed scene %"PRIxPTR, (uintptr_t) scene);
+    asc_scene_node_free(scene->root);
 }
 
-void asc_scene_draw(AscSceneNode *root, asc_recti viewport, const AscCamera *camera) {
+void asc_scene_draw(AscScene *scene, asc_recti viewport) {
     // create render groups
     CxList *render_group[ASC_RENDER_GROUP_COUNT];
     cx_for_n(i, ASC_RENDER_GROUP_COUNT) {
         render_group[i] = cxArrayListCreateSimple(CX_STORE_POINTERS, 32);
     }
 
-    // skip the root node deliberately, we know it's just the container
-    CxTreeVisitor iter = asc_scene_node_visitor(root);
+    // skip the root node deliberately; we know it's just the container
+    CxTreeVisitor iter = cx_tree_visitor(scene->root,
+            offsetof(AscSceneNode, children),
+            offsetof(AscSceneNode, next)
+    );
     cxIteratorNext(iter);
 
     // update the children and add them to the render groups
@@ -116,7 +111,9 @@
         }
 
         // add to render group
-        cxListAdd(render_group[node->render_group], node);
+        if (node->render_group >= 0) {
+            cxListAdd(render_group[node->render_group], node);
+        }
     }
 
     // set the viewport (in OpenGL we need to invert the Y axis)
@@ -145,9 +142,9 @@
         AscShaderProgram *shader = &ASC_SHADER_SPRITE->program;
         glUseProgram(shader->id);
         glUniformMatrix4fv(shader->projection, 1,
-                           GL_FALSE, camera->projection);
+                           GL_FALSE, scene->camera.projection);
         glUniformMatrix4fv(shader->view, 1,
-                               GL_FALSE, camera->view);
+                               GL_FALSE, scene->camera.view);
 
         // render opaque sprites from front to back
         glDisable(GL_BLEND);
@@ -171,92 +168,10 @@
     }
 }
 
-AscSceneNode *asc_scene_node_empty(void) {
-    AscSceneNode *node = calloc(1, sizeof(AscSceneNode));
-    node->free_func = (asc_scene_free_func) free;
-    node->scale.x = node->scale.y = node->scale.z = 1;
-    asc_transform_identity(node->transform);
-    asc_transform_identity(node->world_transform);
-    return node;
-}
-
-void asc_scene_node_free(AscSceneNode *node) {
-    if (node == NULL) return;
-
-    // remove this node from its parent
-    asc_scene_node_unlink(node);
-
-    // free the entire subtree
-    CxTreeIterator iter = asc_scene_node_iterator(node, true);
-    cx_foreach(AscSceneNode*, child, iter) {
-        if (!iter.exiting) continue;
-        if (child->behaviors != NULL) {
-            cxListFree(child->behaviors);
-        }
-        if (child->free_func != NULL) {
-            child->free_func(child);
-        } else {
-            free(child);
-        }
-    }
-}
-
-void asc_scene_node_link(AscSceneNode * restrict parent, AscSceneNode * restrict node) {
-    cx_tree_link(
-            parent, node,
-            offsetof(AscSceneNode, parent),
-            offsetof(AscSceneNode, children),
-            offsetof(AscSceneNode, last_child),
-            offsetof(AscSceneNode, prev),
-            offsetof(AscSceneNode, next)
-    );
+void asc_scene_add_node(AscScene *scene, AscSceneNode *node) {
+    asc_scene_node_link(scene->root, node);
 }
 
-void asc_scene_node_unlink(AscSceneNode *node) {
-    cx_tree_unlink(
-            node,
-            offsetof(AscSceneNode, parent),
-            offsetof(AscSceneNode, children),
-            offsetof(AscSceneNode, last_child),
-            offsetof(AscSceneNode, prev),
-            offsetof(AscSceneNode, next)
-    );
-}
-
-void asc_scene_add_behavior(
-        AscSceneNode *node,
-        asc_scene_update_func behavior
-) {
-    if (node->behaviors == NULL) {
-        node->behaviors = cxLinkedListCreateSimple(CX_STORE_POINTERS);
-    }
-    cxListAdd(node->behaviors, behavior);
+void asc_scene_remove_node(AscSceneNode *node) {
+    asc_scene_node_unlink(node);
 }
-
-void asc_scene_remove_behavior(
-        AscSceneNode *node,
-        asc_scene_update_func behavior
-) {
-    if (node->behaviors != NULL) {
-        cxListFindRemove(node->behaviors, behavior);
-    }
-}
-
-void asc_node_update(AscSceneNode *node) {
-    asc_set_flag(node->flags, ASC_SCENE_NODE_UPDATE_GRAPHICS);
-}
-
-void asc_node_update_transform(AscSceneNode *node) {
-    // fast skip if node is already marked
-    if (asc_test_flag(node->flags, ASC_SCENE_NODE_UPDATE_TRANSFORM)) {
-        return;
-    }
-
-    CxTreeIterator iter = asc_scene_node_iterator(node, false);
-    cx_foreach(AscSceneNode*, n, iter) {
-        if (asc_test_flag(n->flags, ASC_SCENE_NODE_UPDATE_TRANSFORM)) {
-            cxTreeIteratorContinue(iter);
-        }
-        asc_set_flag(n->flags, ASC_SCENE_NODE_UPDATE_TRANSFORM);
-    }
-}

mercurial