+#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()
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) {
}
}
}
-
-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;
-}