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