proper scene graph
[laserbrain_demo] / src / snode.cc
1 #include <float.h>
2 #include <assert.h>
3 #include <algorithm>
4 #include "snode.h"
5
6 SceneNode::SceneNode()
7         : scale(1, 1, 1)
8 {
9         parent = 0;
10         name = 0;
11 }
12
13 SceneNode::SceneNode(Object *obj)
14         : scale(1, 1, 1)
15 {
16         parent = 0;
17         name = 0;
18         add_object(obj);
19 }
20
21 SceneNode::~SceneNode()
22 {
23         delete [] name;
24 }
25
26 void SceneNode::set_name(const char *s)
27 {
28         delete [] name;
29         name = new char[strlen(s) + 1];
30         strcpy(name, s);
31 }
32
33 const char *SceneNode::get_name() const
34 {
35         return name;
36 }
37
38 void SceneNode::add_child(SceneNode *node)
39 {
40         if(!node) return;
41
42         if(node->parent) {
43                 if(node->parent == this) {
44                         return;
45                 }
46                 node->parent->remove_child(node);
47         }
48
49         children.push_back(node);
50         node->parent = this;
51 }
52
53 bool SceneNode::remove_child(SceneNode *node)
54 {
55         if(!node) return false;
56
57         auto it = std::find(children.begin(), children.end(), node);
58         if(it != children.end()) {
59                 assert(node->parent == this);
60                 node->parent = 0;
61                 return true;
62         }
63         return false;
64 }
65
66 int SceneNode::get_num_children() const
67 {
68         return (int)children.size();
69 }
70
71 SceneNode *SceneNode::get_child(int idx) const
72 {
73         return children[idx];
74 }
75
76 SceneNode *SceneNode::get_parent() const
77 {
78         return parent;
79 }
80
81 void SceneNode::add_object(Object *obj)
82 {
83         if(obj->node == this) return;
84
85         if(obj->node) {
86                 obj->node->remove_object(obj);
87         }
88
89         this->obj.push_back(obj);
90         obj->node = this;
91 }
92
93 bool SceneNode::remove_object(Object *o)
94 {
95         if(o->node != this) {
96                 return false;
97         }
98         o->node = 0;
99
100         auto it = std::find(obj.begin(), obj.end(), o);
101         if(it == obj.end()) {
102                 return false;
103         }
104         obj.erase(it);
105         return true;
106 }
107
108 int SceneNode::get_num_objects() const
109 {
110         return (int)obj.size();
111 }
112
113 Object *SceneNode::get_object(int idx) const
114 {
115         return obj[idx];
116 }
117
118 void SceneNode::set_position(const Vec3 &pos)
119 {
120         this->pos = pos;
121 }
122
123 void SceneNode::set_rotation(const Quat &rot)
124 {
125         this->rot = rot;
126 }
127
128 void SceneNode::set_scaling(const Vec3 &scale)
129 {
130         this->scale = scale;
131 }
132
133
134 const Vec3 &SceneNode::get_node_position() const
135 {
136         return pos;
137 }
138
139 const Quat &SceneNode::get_node_rotation() const
140 {
141         return rot;
142 }
143
144 const Vec3 &SceneNode::get_node_scaling() const
145 {
146         return scale;
147 }
148
149
150 Vec3 SceneNode::get_position() const
151 {
152         return xform * Vec3(0, 0, 0);
153 }
154
155 Quat SceneNode::get_rotation() const
156 {
157         return rot;     // TODO
158 }
159
160 Vec3 SceneNode::get_scaling() const
161 {
162         return scale;   // TODO
163 }
164
165 const Mat4 &SceneNode::get_matrix() const
166 {
167         return xform;
168 }
169
170 const Mat4 &SceneNode::get_inv_matrix() const
171 {
172         return inv_xform;
173 }
174
175
176 void SceneNode::update_node(float dt)
177 {
178         xform = Mat4::identity;
179         xform.pre_translate(pos);
180         xform.pre_rotate(rot);
181         xform.pre_scale(scale);
182
183         if(parent) {
184                 xform = xform * parent->xform;
185         }
186         inv_xform = inverse(xform);
187 }
188
189 void SceneNode::update(float dt)
190 {
191         update_node(dt);
192
193         for(size_t i=0; i<children.size(); i++) {
194                 children[i]->update(dt);
195         }
196 }
197
198
199 bool SceneNode::intersect(const Ray &ray, HitPoint *hit) const
200 {
201         Ray local_ray = inv_xform * ray;
202
203         HitPoint nearest;
204         nearest.dist = FLT_MAX;
205         for(size_t i=0; i<obj.size(); i++) {
206                 if(obj[i]->intersect(local_ray, hit)) {
207                         if(!hit) return true;
208                         if(hit->dist < nearest.dist) {
209                                 nearest = *hit;
210                                 nearest.data = (void*)this;
211                                 nearest.local_ray = local_ray;
212                         }
213                 }
214         }
215
216         for(size_t i=0; i<children.size(); i++) {
217                 if(children[i]->intersect(ray, hit)) {
218                         if(!hit) return true;
219                         if(hit->dist < nearest.dist) {
220                                 nearest = *hit;
221                         }
222                 }
223         }
224
225         if(nearest.dist < FLT_MAX) {
226                 *hit = nearest;
227                 hit->ray = ray;
228                 return true;
229         }
230         return false;
231 }