minor changes (bounds lazy eval state)
[laserbrain_demo] / src / snode.cc
1 #include <float.h>
2 #include <assert.h>
3 #include <algorithm>
4 #include "snode.h"
5 #include "objmesh.h"
6 #include "dbg_gui.h"
7
8 SceneNode::SceneNode()
9         : scale(1, 1, 1)
10 {
11         scene = 0;
12         parent = 0;
13         name = 0;
14         bvol_valid = false;
15 }
16
17 SceneNode::SceneNode(Object *obj)
18         : scale(1, 1, 1)
19 {
20         scene = 0;
21         parent = 0;
22         name = 0;
23         bvol_valid = false;
24         add_object(obj);
25 }
26
27 SceneNode::~SceneNode()
28 {
29         delete [] name;
30 }
31
32 void SceneNode::set_name(const char *s)
33 {
34         delete [] name;
35         name = new char[strlen(s) + 1];
36         strcpy(name, s);
37 }
38
39 const char *SceneNode::get_name() const
40 {
41         return name;
42 }
43
44 void SceneNode::add_child(SceneNode *node)
45 {
46         if(!node) return;
47
48         if(node->parent) {
49                 if(node->parent == this) {
50                         return;
51                 }
52                 node->parent->remove_child(node);
53         }
54
55         children.push_back(node);
56         node->parent = this;
57         node->scene = scene;
58
59         bvol_valid = false;
60 }
61
62 bool SceneNode::remove_child(SceneNode *node)
63 {
64         if(!node) return false;
65
66         auto it = std::find(children.begin(), children.end(), node);
67         if(it != children.end()) {
68                 assert(node->parent == this);
69                 node->parent = 0;
70                 node->scene = 0;
71                 children.erase(it);
72
73                 bvol_valid = false;
74                 return true;
75         }
76         return false;
77 }
78
79 int SceneNode::get_num_children() const
80 {
81         return (int)children.size();
82 }
83
84 SceneNode *SceneNode::get_child(int idx) const
85 {
86         return children[idx];
87 }
88
89 SceneNode *SceneNode::get_parent() const
90 {
91         return parent;
92 }
93
94 void SceneNode::add_object(Object *obj)
95 {
96         if(obj->node == this) return;
97
98         if(obj->node) {
99                 obj->node->remove_object(obj);
100         }
101
102         this->obj.push_back(obj);
103         obj->node = this;
104
105         bvol_valid = false;
106 }
107
108 bool SceneNode::remove_object(Object *o)
109 {
110         if(o->node != this) {
111                 return false;
112         }
113         o->node = 0;
114
115         auto it = std::find(obj.begin(), obj.end(), o);
116         if(it == obj.end()) {
117                 return false;
118         }
119         obj.erase(it);
120
121         bvol_valid = false;
122         return true;
123 }
124
125 int SceneNode::get_num_objects() const
126 {
127         return (int)obj.size();
128 }
129
130 Object *SceneNode::get_object(int idx) const
131 {
132         return obj[idx];
133 }
134
135 void SceneNode::set_position(const Vec3 &pos)
136 {
137         this->pos = pos;
138 }
139
140 void SceneNode::set_rotation(const Quat &rot)
141 {
142         this->rot = rot;
143 }
144
145 void SceneNode::set_scaling(const Vec3 &scale)
146 {
147         this->scale = scale;
148 }
149
150
151 const Vec3 &SceneNode::get_node_position() const
152 {
153         return pos;
154 }
155
156 const Quat &SceneNode::get_node_rotation() const
157 {
158         return rot;
159 }
160
161 const Vec3 &SceneNode::get_node_scaling() const
162 {
163         return scale;
164 }
165
166
167 Vec3 SceneNode::get_position() const
168 {
169         return xform * Vec3(0, 0, 0);
170 }
171
172 Quat SceneNode::get_rotation() const
173 {
174         return rot;     // TODO
175 }
176
177 Vec3 SceneNode::get_scaling() const
178 {
179         return scale;   // TODO
180 }
181
182 const Mat4 &SceneNode::get_matrix() const
183 {
184         return xform;
185 }
186
187 const Mat4 &SceneNode::get_inv_matrix() const
188 {
189         return inv_xform;
190 }
191
192
193 void SceneNode::update_node(float dt)
194 {
195         xform = Mat4::identity;
196         xform.pre_translate(pos);
197         xform.pre_rotate(rot);
198         xform.pre_scale(scale);
199
200         if(parent) {
201                 xform = xform * parent->xform;
202         }
203         inv_xform = inverse(xform);
204 }
205
206 void SceneNode::update(float dt)
207 {
208         bool expanded = false;
209
210         if(debug_gui) {
211                 if(parent_expanded) {
212                         int flags = children.empty() ? ImGuiTreeNodeFlags_Leaf : 0;
213                         expanded = ImGui::TreeNodeEx(name ? name : "<nameless node>", flags);
214                 }
215         }
216
217         update_node(dt);
218
219         int num = children.size();
220         for(int i=0; i<num; i++) {
221                 parent_expanded = expanded;
222                 children[i]->update(dt);
223         }
224
225         if(debug_gui && expanded) {
226                 ImGui::TreePop();
227         }
228 }
229
230 void SceneNode::apply_xform()
231 {
232         update_node();
233
234         // apply post-order to make sure we don't affect the children xform by our reset
235
236         int nchild = children.size();
237         for(int i=0; i<nchild; i++) {
238                 children[i]->apply_xform();
239         }
240
241         int nobj = obj.size();
242         for(int i=0; i<nobj; i++) {
243                 if(obj[i]->get_type() == OBJ_MESH) {
244                         ObjMesh *om = (ObjMesh*)obj[i];
245                         if(om->mesh) {
246                                 om->mesh->apply_xform(xform);
247                         }
248                 }
249         }
250
251         pos = Vec3(0, 0, 0);
252         rot = Quat::identity;
253         scale = Vec3(1, 1, 1);
254 }
255
256 bool SceneNode::intersect(const Ray &ray, HitPoint *hit) const
257 {
258         Ray local_ray = inv_xform * ray;
259
260         HitPoint nearest;
261         nearest.dist = FLT_MAX;
262         for(size_t i=0; i<obj.size(); i++) {
263                 if(obj[i]->intersect(local_ray, hit)) {
264                         if(!hit) return true;
265                         if(hit->dist < nearest.dist) {
266                                 nearest = *hit;
267                                 nearest.data = (void*)this;
268                                 nearest.local_ray = local_ray;
269                         }
270                 }
271         }
272
273         for(size_t i=0; i<children.size(); i++) {
274                 if(children[i]->intersect(ray, hit)) {
275                         if(!hit) return true;
276                         if(hit->dist < nearest.dist) {
277                                 nearest = *hit;
278                         }
279                 }
280         }
281
282         if(nearest.dist < FLT_MAX) {
283                 *hit = nearest;
284                 hit->ray = ray;
285                 return true;
286         }
287         return false;
288 }
289
290 const Box &SceneNode::calc_bounds()
291 {
292         // TODO
293 }
294
295 const Box &SceneNode::get_bounds() const
296 {
297         if(!bvol_valid) {
298                 return ((SceneNode*)this)->calc_bounds();
299         }
300         return bvol;
301 }