simple ubershader system, reflection debugging
[laserbrain_demo] / src / scene.cc
index 27be807..10304f6 100644 (file)
@@ -1,10 +1,20 @@
+#include <regex>
 #include "scene.h"
+#include "objmesh.h"
+#include "app.h"
+#include "dbg_gui.h"
 
 static void destroy_node_tree(SceneNode *n);
 
 Scene::Scene()
 {
+       metascn = 0;
        nodes = 0;
+
+       walk_mesh = 0;
+
+       texset = 0;
+       loader_data = 0;
 }
 
 Scene::~Scene()
@@ -14,12 +24,272 @@ Scene::~Scene()
 
 void Scene::destroy()
 {
+       clear();
+
+       metascn = 0;
+       texset = 0;
+       loader_data = 0;
+
+       datamap.clear();
+}
+
+void Scene::clear()
+{
        destroy_node_tree(nodes);
        nodes = 0;
+
+       for(int i=0; i<(int)meshes.size(); i++) {
+               delete meshes[i];
+       }
+       meshes.clear();
+
+       delete walk_mesh;
+       walk_mesh = 0;
+
+       for(int i=0; i<(int)objects.size(); i++) {
+               delete objects[i];
+       }
+       objects.clear();
+}
+
+static void destroy_node_tree(SceneNode *n)
+{
+       if(!n) return;
+
+       int nsub = n->get_num_children();
+       for(int i=0; i<nsub; i++) {
+               destroy_node_tree(n->get_child(i));
+       }
+       delete n;
 }
 
 // Scene::load defined in sceneload.cc
 
+bool Scene::merge(Scene *scn)
+{
+       if(walk_mesh) {
+               if(scn->walk_mesh) {
+                       walk_mesh->append(*scn->walk_mesh);
+                       delete scn->walk_mesh;
+                       scn->walk_mesh = 0;
+               }
+       } else {
+               walk_mesh = scn->walk_mesh;
+               scn->walk_mesh = 0;
+       }
+
+       int nmeshes = scn->meshes.size();
+       for(int i=0; i<nmeshes; i++) {
+               meshes.push_back(scn->meshes[i]);
+       }
+       scn->meshes.clear();
+
+       int nobj = scn->objects.size();
+       for(int i=0; i<nobj; i++) {
+               objects.push_back(scn->objects[i]);
+       }
+       scn->objects.clear();
+
+       if(nodes) {
+               int nchildren = scn->nodes ? scn->nodes->get_num_children() : 0;
+               for(int i=0; i<nchildren; i++) {
+                       SceneNode *n = scn->nodes->get_child(i);
+                       scn->nodes->remove_child(n);
+                       nodes->add_child(n);
+               }
+               if(scn->nodes && scn->nodes->get_num_objects() > 0) {
+                       warning_log("merging with scene which has objects in its root node. these objects will not be merged!\n");
+               }
+               delete scn->nodes;
+       } else {
+               nodes = scn->nodes;
+       }
+       scn->nodes = 0;
+
+       return true;
+}
+
+void Scene::add_object(Object *obj)
+{
+       objects.push_back(obj);
+}
+
+bool Scene::remove_object(Object *obj)
+{
+       std::vector<Object*>::iterator it = std::find(objects.begin(), objects.end(), obj);
+       if(it != objects.end()) {
+               objects.erase(it);
+               return true;
+       }
+       return false;
+}
+
+bool Scene::have_object(Object *obj) const
+{
+       return std::find(objects.begin(), objects.end(), obj) != objects.end();
+}
+
+void Scene::add_mesh(Mesh *m)
+{
+       meshes.push_back(m);
+}
+
+bool Scene::remove_mesh(Mesh *m)
+{
+       std::vector<Mesh*>::iterator it = std::find(meshes.begin(), meshes.end(), m);
+       if(it != meshes.end()) {
+               meshes.erase(it);
+               return true;
+       }
+       return false;
+}
+
+bool Scene::have_mesh(Mesh *m) const
+{
+       return std::find(meshes.begin(), meshes.end(), m) != meshes.end();
+}
+
+void Scene::add_node(SceneNode *n)
+{
+       // we always want to have a dedicated root node
+       if(!nodes) {
+               nodes = new SceneNode;
+               nodes->scene = this;
+               nodes->set_name("root");
+       }
+
+       nodes->add_child(n);
+}
+
+bool Scene::remove_node(SceneNode *n)
+{
+       SceneNode *par;
+       if(!n || !(par = n->get_parent())) {
+               return false;
+       }
+
+       int nsub = n->get_num_children();
+       for(int i=0; i<nsub; i++) {
+               SceneNode *c = n->get_child(i);
+               n->remove_child(c);
+               par->add_child(c);
+       }
+
+       return par->remove_child(n);
+}
+
+bool Scene::have_node(SceneNode *n) const
+{
+       return n->scene == this;
+}
+
+/* traverse scene graph and find node by name */
+static SceneNode *find_node_rec(SceneNode *tree, const char *name)
+{
+       if(strcmp(tree->get_name(), name) == 0) {
+               return tree;
+       }
+
+       int num = tree->get_num_children();
+       for(int i=0; i<num; i++) {
+               SceneNode *n = find_node_rec(tree->get_child(i), name);
+               if(n) return n;
+       }
+       return 0;
+}
+
+static SceneNode *find_node_rec(SceneNode *tree, const std::regex &re)
+{
+       if(std::regex_match(tree->get_name(), re)) {
+               return tree;
+       }
+
+       int num = tree->get_num_children();
+       for(int i=0; i<num; i++) {
+               SceneNode *n = find_node_rec(tree->get_child(i), re);
+               if(n) return n;
+       }
+       return 0;
+}
+
+static void find_nodes_rec(std::list<SceneNode*> *res, SceneNode *tree, const std::regex &re)
+{
+       if(std::regex_match(tree->get_name(), re)) {
+               res->push_back(tree);
+       }
+
+       int num = tree->get_num_children();
+       for(int i=0; i<num; i++) {
+               find_nodes_rec(res, tree->get_child(i), re);
+       }
+}
+
+SceneNode *Scene::find_node(const char *name) const
+{
+       if(!nodes) return 0;
+       return find_node_rec(nodes, name);
+}
+
+SceneNode *Scene::match_node(const char *qstr) const
+{
+       if(!nodes) return 0;
+
+       std::regex re{qstr};
+       return find_node_rec(nodes, re);
+}
+
+std::list<SceneNode*> Scene::match_nodes(const char *qstr) const
+{
+       std::list<SceneNode*> res;
+       if(nodes) {
+               std::regex re{qstr};
+               find_nodes_rec(&res, nodes, re);
+       }
+       return res;
+}
+
+Scene *Scene::extract_nodes(const char *qstr)
+{
+       if(!nodes) return 0;
+
+       std::regex re{qstr};
+
+       std::list<SceneNode*> nodelist;
+       find_nodes_rec(&nodelist, nodes, re);
+       if(nodelist.empty()) {
+               return 0;
+       }
+
+       Scene *res = new Scene;
+
+       for(SceneNode *n : nodelist) {
+
+               int nobj = n->get_num_objects();
+               for(int i=0; i<nobj; i++) {
+                       Object *obj = n->get_object(i);
+                       if(obj->get_type() == OBJ_MESH) {
+                               // XXX this assumes that meshes aren't shared between objects.
+                               // maybe we'll have to refcount them at some point, and copy if nref>1
+                               ObjMesh *om = (ObjMesh*)obj;
+                               remove_mesh(om->mesh);
+                               res->add_mesh(om->mesh);
+                       }
+
+                       remove_object(obj);
+                       res->add_object(obj);
+               }
+
+               remove_node(n);
+               res->add_node(n);
+       }
+       return res;
+}
+
+void Scene::apply_xform()
+{
+       nodes->apply_xform();
+}
+
 void Scene::update(float dt)
 {
        if(nodes) {
@@ -50,14 +320,3 @@ void Scene::draw() const
                }
        }
 }
-
-static void destroy_node_tree(SceneNode *n)
-{
-       if(!n) return;
-
-       int nsub = n->get_num_children();
-       for(int i=0; i<nsub; i++) {
-               destroy_node_tree(n->get_child(i));
-       }
-       delete n;
-}