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