metadata, walk polygons, stuff...
[laserbrain_demo] / src / scene.cc
1 #include <regex>
2 #include "scene.h"
3 #include "objmesh.h"
4
5 static void destroy_node_tree(SceneNode *n);
6
7 Scene::Scene(TextureSet *tset)
8 {
9         nodes = 0;
10
11         walk_mesh = 0;
12
13         if(tset) {
14                 texset = tset;
15                 own_texset = false;
16         } else {
17                 texset = new TextureSet;
18                 own_texset = true;
19         }
20 }
21
22 Scene::~Scene()
23 {
24         destroy();
25 }
26
27 void Scene::destroy()
28 {
29         destroy_node_tree(nodes);
30         nodes = 0;
31
32         for(int i=0; i<(int)meshes.size(); i++) {
33                 delete meshes[i];
34         }
35         meshes.clear();
36
37         delete walk_mesh;
38         walk_mesh = 0;
39
40         for(int i=0; i<(int)objects.size(); i++) {
41                 delete objects[i];
42         }
43         objects.clear();
44
45         if(own_texset) {
46                 delete texset;
47         }
48         texset = 0;
49 }
50
51 static void destroy_node_tree(SceneNode *n)
52 {
53         if(!n) return;
54
55         int nsub = n->get_num_children();
56         for(int i=0; i<nsub; i++) {
57                 destroy_node_tree(n->get_child(i));
58         }
59         delete n;
60 }
61
62 // Scene::load defined in sceneload.cc
63
64 void Scene::add_object(Object *obj)
65 {
66         objects.push_back(obj);
67 }
68
69 bool Scene::remove_object(Object *obj)
70 {
71         std::vector<Object*>::iterator it = std::find(objects.begin(), objects.end(), obj);
72         if(it != objects.end()) {
73                 objects.erase(it);
74                 return true;
75         }
76         return false;
77 }
78
79 bool Scene::have_object(Object *obj) const
80 {
81         return std::find(objects.begin(), objects.end(), obj) != objects.end();
82 }
83
84 void Scene::add_mesh(Mesh *m)
85 {
86         meshes.push_back(m);
87 }
88
89 bool Scene::remove_mesh(Mesh *m)
90 {
91         std::vector<Mesh*>::iterator it = std::find(meshes.begin(), meshes.end(), m);
92         if(it != meshes.end()) {
93                 meshes.erase(it);
94                 return true;
95         }
96         return false;
97 }
98
99 bool Scene::have_mesh(Mesh *m) const
100 {
101         return std::find(meshes.begin(), meshes.end(), m) != meshes.end();
102 }
103
104 void Scene::add_node(SceneNode *n)
105 {
106         // we always want to have a dedicated root node
107         if(!nodes) {
108                 nodes = new SceneNode;
109                 nodes->scene = this;
110                 nodes->set_name("root");
111         }
112
113         nodes->add_child(n);
114 }
115
116 bool Scene::remove_node(SceneNode *n)
117 {
118         SceneNode *par;
119         if(!n || !(par = n->get_parent())) {
120                 return false;
121         }
122
123         int nsub = n->get_num_children();
124         for(int i=0; i<nsub; i++) {
125                 SceneNode *c = n->get_child(i);
126                 n->remove_child(c);
127                 par->add_child(c);
128         }
129
130         return par->remove_child(n);
131 }
132
133 bool Scene::have_node(SceneNode *n) const
134 {
135         return n->scene == this;
136 }
137
138 static void find_nodes_rec(std::list<SceneNode*> *res, SceneNode *tree, const std::regex &re)
139 {
140         if(std::regex_match(tree->get_name(), re)) {
141                 res->push_back(tree);
142         }
143
144         int num = tree->get_num_children();
145         for(int i=0; i<num; i++) {
146                 find_nodes_rec(res, tree->get_child(i), re);
147         }
148 }
149
150 Scene *Scene::extract_nodes(const char *qstr)
151 {
152         std::regex re{qstr};
153
154         std::list<SceneNode*> nodelist;
155         find_nodes_rec(&nodelist, nodes, re);
156         if(nodelist.empty()) {
157                 return 0;
158         }
159
160         Scene *res = new Scene(texset);
161
162         for(SceneNode *n : nodelist) {
163
164                 int nobj = n->get_num_objects();
165                 for(int i=0; i<nobj; i++) {
166                         Object *obj = n->get_object(i);
167                         if(obj->get_type() == OBJ_MESH) {
168                                 // XXX this assumes that meshes aren't shared between objects.
169                                 // maybe we'll have to refcount them at some point, and copy if nref>1
170                                 ObjMesh *om = (ObjMesh*)obj;
171                                 remove_mesh(om->mesh);
172                                 res->add_mesh(om->mesh);
173                         }
174
175                         remove_object(obj);
176                         res->add_object(obj);
177                 }
178
179                 remove_node(n);
180                 res->add_node(n);
181         }
182         return res;
183 }
184
185 void Scene::apply_xform()
186 {
187         nodes->apply_xform();
188 }
189
190 void Scene::update(float dt)
191 {
192         if(nodes) {
193                 nodes->update(dt);
194         }
195
196         int nobj = objects.size();
197         for(int i=0; i<nobj; i++) {
198                 if(!objects[i]->node) {
199                         // only update objects which don't belong to a scenegraph node
200                         // to avoid updating objects twice
201                         objects[i]->update(dt);
202                 }
203         }
204 }
205
206 void Scene::draw() const
207 {
208         if(!objects.empty()) {
209                 int nobj = objects.size();
210                 for(int i=0; i<nobj; i++) {
211                         objects[i]->draw();
212                 }
213         } else {
214                 int nmesh = meshes.size();
215                 for(int i=0; i<nmesh; i++) {
216                         meshes[i]->draw();
217                 }
218         }
219 }