484310f855b2a840112be2acff5534ee89bf7899
[laserbrain_demo] / src / scene.cc
1 #include <regex>
2 #include "scene.h"
3 #include "objmesh.h"
4 #include "app.h"
5
6 static void destroy_node_tree(SceneNode *n);
7
8 Scene::Scene()
9 {
10         metascn = 0;
11         nodes = 0;
12
13         walk_mesh = 0;
14
15         texset = 0;
16         loader_data = 0;
17 }
18
19 Scene::~Scene()
20 {
21         destroy();
22 }
23
24 void Scene::destroy()
25 {
26         clear();
27
28         metascn = 0;
29         texset = 0;
30         loader_data = 0;
31
32         datamap.clear();
33 }
34
35 void Scene::clear()
36 {
37         destroy_node_tree(nodes);
38         nodes = 0;
39
40         for(int i=0; i<(int)meshes.size(); i++) {
41                 delete meshes[i];
42         }
43         meshes.clear();
44
45         delete walk_mesh;
46         walk_mesh = 0;
47
48         for(int i=0; i<(int)objects.size(); i++) {
49                 delete objects[i];
50         }
51         objects.clear();
52 }
53
54 static void destroy_node_tree(SceneNode *n)
55 {
56         if(!n) return;
57
58         int nsub = n->get_num_children();
59         for(int i=0; i<nsub; i++) {
60                 destroy_node_tree(n->get_child(i));
61         }
62         delete n;
63 }
64
65 // Scene::load defined in sceneload.cc
66
67 bool Scene::merge(Scene *scn)
68 {
69         if(walk_mesh) {
70                 if(scn->walk_mesh) {
71                         walk_mesh->append(*scn->walk_mesh);
72                         delete scn->walk_mesh;
73                         scn->walk_mesh = 0;
74                 }
75         } else {
76                 walk_mesh = scn->walk_mesh;
77                 scn->walk_mesh = 0;
78         }
79
80         int nmeshes = scn->meshes.size();
81         for(int i=0; i<nmeshes; i++) {
82                 meshes.push_back(scn->meshes[i]);
83         }
84         scn->meshes.clear();
85
86         int nobj = scn->objects.size();
87         for(int i=0; i<nobj; i++) {
88                 objects.push_back(scn->objects[i]);
89         }
90         scn->objects.clear();
91
92         if(nodes) {
93                 int nchildren = scn->nodes ? scn->nodes->get_num_children() : 0;
94                 for(int i=0; i<nchildren; i++) {
95                         SceneNode *n = scn->nodes->get_child(i);
96                         scn->nodes->remove_child(n);
97                         nodes->add_child(n);
98                 }
99                 if(scn->nodes && scn->nodes->get_num_objects() > 0) {
100                         warning_log("merging with scene which has objects in its root node. these objects will not be merged!\n");
101                 }
102                 delete scn->nodes;
103         } else {
104                 nodes = scn->nodes;
105         }
106         scn->nodes = 0;
107
108         return true;
109 }
110
111 void Scene::add_object(Object *obj)
112 {
113         objects.push_back(obj);
114 }
115
116 bool Scene::remove_object(Object *obj)
117 {
118         std::vector<Object*>::iterator it = std::find(objects.begin(), objects.end(), obj);
119         if(it != objects.end()) {
120                 objects.erase(it);
121                 return true;
122         }
123         return false;
124 }
125
126 bool Scene::have_object(Object *obj) const
127 {
128         return std::find(objects.begin(), objects.end(), obj) != objects.end();
129 }
130
131 void Scene::add_mesh(Mesh *m)
132 {
133         meshes.push_back(m);
134 }
135
136 bool Scene::remove_mesh(Mesh *m)
137 {
138         std::vector<Mesh*>::iterator it = std::find(meshes.begin(), meshes.end(), m);
139         if(it != meshes.end()) {
140                 meshes.erase(it);
141                 return true;
142         }
143         return false;
144 }
145
146 bool Scene::have_mesh(Mesh *m) const
147 {
148         return std::find(meshes.begin(), meshes.end(), m) != meshes.end();
149 }
150
151 void Scene::add_node(SceneNode *n)
152 {
153         // we always want to have a dedicated root node
154         if(!nodes) {
155                 nodes = new SceneNode;
156                 nodes->scene = this;
157                 nodes->set_name("root");
158         }
159
160         nodes->add_child(n);
161 }
162
163 bool Scene::remove_node(SceneNode *n)
164 {
165         SceneNode *par;
166         if(!n || !(par = n->get_parent())) {
167                 return false;
168         }
169
170         int nsub = n->get_num_children();
171         for(int i=0; i<nsub; i++) {
172                 SceneNode *c = n->get_child(i);
173                 n->remove_child(c);
174                 par->add_child(c);
175         }
176
177         return par->remove_child(n);
178 }
179
180 bool Scene::have_node(SceneNode *n) const
181 {
182         return n->scene == this;
183 }
184
185 /* traverse scene graph and find node by name */
186 static SceneNode *find_node_rec(SceneNode *tree, const char *name)
187 {
188         if(strcmp(tree->get_name(), name) == 0) {
189                 return tree;
190         }
191
192         int num = tree->get_num_children();
193         for(int i=0; i<num; i++) {
194                 SceneNode *n = find_node_rec(tree->get_child(i), name);
195                 if(n) return n;
196         }
197         return 0;
198 }
199
200 static SceneNode *find_node_rec(SceneNode *tree, const std::regex &re)
201 {
202         if(std::regex_match(tree->get_name(), re)) {
203                 return tree;
204         }
205
206         int num = tree->get_num_children();
207         for(int i=0; i<num; i++) {
208                 SceneNode *n = find_node_rec(tree, re);
209                 if(n) return n;
210         }
211         return 0;
212 }
213
214 static void find_nodes_rec(std::list<SceneNode*> *res, SceneNode *tree, const std::regex &re)
215 {
216         if(std::regex_match(tree->get_name(), re)) {
217                 res->push_back(tree);
218         }
219
220         int num = tree->get_num_children();
221         for(int i=0; i<num; i++) {
222                 find_nodes_rec(res, tree->get_child(i), re);
223         }
224 }
225
226 SceneNode *Scene::find_node(const char *name) const
227 {
228         if(!nodes) return 0;
229         return find_node_rec(nodes, name);
230 }
231
232 SceneNode *Scene::match_node(const char *qstr) const
233 {
234         if(!nodes) return 0;
235
236         std::regex re{qstr};
237         return find_node_rec(nodes, re);
238 }
239
240 std::list<SceneNode*> Scene::match_nodes(const char *qstr) const
241 {
242         std::list<SceneNode*> res;
243         if(nodes) {
244                 std::regex re{qstr};
245                 find_nodes_rec(&res, nodes, re);
246         }
247         return std::move(res);
248 }
249
250 Scene *Scene::extract_nodes(const char *qstr)
251 {
252         if(!nodes) return 0;
253
254         std::regex re{qstr};
255
256         std::list<SceneNode*> nodelist;
257         find_nodes_rec(&nodelist, nodes, re);
258         if(nodelist.empty()) {
259                 return 0;
260         }
261
262         Scene *res = new Scene;
263
264         for(SceneNode *n : nodelist) {
265
266                 int nobj = n->get_num_objects();
267                 for(int i=0; i<nobj; i++) {
268                         Object *obj = n->get_object(i);
269                         if(obj->get_type() == OBJ_MESH) {
270                                 // XXX this assumes that meshes aren't shared between objects.
271                                 // maybe we'll have to refcount them at some point, and copy if nref>1
272                                 ObjMesh *om = (ObjMesh*)obj;
273                                 remove_mesh(om->mesh);
274                                 res->add_mesh(om->mesh);
275                         }
276
277                         remove_object(obj);
278                         res->add_object(obj);
279                 }
280
281                 remove_node(n);
282                 res->add_node(n);
283         }
284         return res;
285 }
286
287 void Scene::apply_xform()
288 {
289         nodes->apply_xform();
290 }
291
292 void Scene::update(float dt)
293 {
294         if(nodes) {
295                 nodes->update(dt);
296         }
297
298         int nobj = objects.size();
299         for(int i=0; i<nobj; i++) {
300                 if(!objects[i]->node) {
301                         // only update objects which don't belong to a scenegraph node
302                         // to avoid updating objects twice
303                         objects[i]->update(dt);
304                 }
305         }
306 }
307
308 void Scene::draw() const
309 {
310         if(!objects.empty()) {
311                 int nobj = objects.size();
312                 for(int i=0; i<nobj; i++) {
313                         objects[i]->draw();
314                 }
315         } else {
316                 int nmesh = meshes.size();
317                 for(int i=0; i<nmesh; i++) {
318                         meshes[i]->draw();
319                 }
320         }
321 }