implemented metascene spawn point/rot
[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         if(!nodes) return 0;
186
187         std::regex re{qstr};
188
189         std::list<SceneNode*> nodelist;
190         find_nodes_rec(&nodelist, nodes, re);
191         if(nodelist.empty()) {
192                 return 0;
193         }
194
195         Scene *res = new Scene;
196
197         for(SceneNode *n : nodelist) {
198
199                 int nobj = n->get_num_objects();
200                 for(int i=0; i<nobj; i++) {
201                         Object *obj = n->get_object(i);
202                         if(obj->get_type() == OBJ_MESH) {
203                                 // XXX this assumes that meshes aren't shared between objects.
204                                 // maybe we'll have to refcount them at some point, and copy if nref>1
205                                 ObjMesh *om = (ObjMesh*)obj;
206                                 remove_mesh(om->mesh);
207                                 res->add_mesh(om->mesh);
208                         }
209
210                         remove_object(obj);
211                         res->add_object(obj);
212                 }
213
214                 remove_node(n);
215                 res->add_node(n);
216         }
217         return res;
218 }
219
220 void Scene::apply_xform()
221 {
222         nodes->apply_xform();
223 }
224
225 void Scene::update(float dt)
226 {
227         if(nodes) {
228                 nodes->update(dt);
229         }
230
231         int nobj = objects.size();
232         for(int i=0; i<nobj; i++) {
233                 if(!objects[i]->node) {
234                         // only update objects which don't belong to a scenegraph node
235                         // to avoid updating objects twice
236                         objects[i]->update(dt);
237                 }
238         }
239 }
240
241 void Scene::draw() const
242 {
243         if(!objects.empty()) {
244                 int nobj = objects.size();
245                 for(int i=0; i<nobj; i++) {
246                         objects[i]->draw();
247                 }
248         } else {
249                 int nmesh = meshes.size();
250                 for(int i=0; i<nmesh; i++) {
251                         meshes[i]->draw();
252                 }
253         }
254 }