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