15 local_bvol_valid = false;
18 SceneNode::SceneNode(Object *obj)
25 local_bvol_valid = false;
29 SceneNode::~SceneNode()
34 void SceneNode::set_name(const char *s)
37 name = new char[strlen(s) + 1];
41 const char *SceneNode::get_name() const
46 void SceneNode::add_child(SceneNode *node)
51 if(node->parent == this) {
54 node->parent->remove_child(node);
57 children.push_back(node);
62 bool SceneNode::remove_child(SceneNode *node)
64 if(!node) return false;
66 auto it = std::find(children.begin(), children.end(), node);
67 if(it != children.end()) {
68 assert(node->parent == this);
77 int SceneNode::get_num_children() const
79 return (int)children.size();
82 SceneNode *SceneNode::get_child(int idx) const
87 SceneNode *SceneNode::get_parent() const
92 void SceneNode::add_object(Object *obj)
94 if(obj->node == this) return;
97 obj->node->remove_object(obj);
100 this->obj.push_back(obj);
103 local_bvol_valid = false;
106 bool SceneNode::remove_object(Object *o)
108 if(o->node != this) {
113 auto it = std::find(obj.begin(), obj.end(), o);
114 if(it == obj.end()) {
119 local_bvol_valid = false;
123 int SceneNode::get_num_objects() const
125 return (int)obj.size();
128 Object *SceneNode::get_object(int idx) const
133 void SceneNode::set_position(const Vec3 &pos)
138 void SceneNode::set_rotation(const Quat &rot)
143 void SceneNode::set_scaling(const Vec3 &scale)
149 const Vec3 &SceneNode::get_node_position() const
154 const Quat &SceneNode::get_node_rotation() const
159 const Vec3 &SceneNode::get_node_scaling() const
165 Vec3 SceneNode::get_position() const
167 return xform.get_translation();
170 Quat SceneNode::get_rotation() const
172 return xform.get_rotation();
175 Vec3 SceneNode::get_scaling() const
177 return xform.get_scaling();
180 const Mat4 &SceneNode::get_matrix() const
185 const Mat4 &SceneNode::get_inv_matrix() const
191 void SceneNode::update_node(float dt)
193 xform = Mat4::identity;
194 xform.pre_translate(pos);
195 xform.pre_rotate(rot);
196 xform.pre_scale(scale);
199 xform = xform * parent->xform;
201 inv_xform = inverse(xform);
204 void SceneNode::update(float dt)
206 bool expanded = false;
209 if(parent_expanded) {
211 ImGui::AlignTextToFramePadding();
213 int flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick;
214 if(children.empty()) flags |= ImGuiTreeNodeFlags_Leaf;
215 if(dbg_sel_node == this) flags |= ImGuiTreeNodeFlags_Selected;
216 expanded = ImGui::TreeNodeEx(name ? name : "<nameless node>", flags);
217 if(ImGui::IsItemClicked()) {
222 ImGui::Checkbox("##vis", &visible);
224 if(ImGui::Button("xform")) {
225 ImGui::OpenPopup("xform_popup");
227 if(ImGui::BeginPopup("xform_popup")) {
228 ImGui::Text("Local transform");
229 Vec3 p = get_node_position();
230 ImGui::BulletText("P: %g %g %g", p.x, p.y, p.z);
231 Quat q = get_node_rotation();
232 ImGui::BulletText("R: %g %g %g %g", q.x, q.y, q.z, q.w);
233 Vec3 s = get_node_scaling();
234 ImGui::BulletText("S: %g %g %g", s.x, s.y, s.z);
237 ImGui::Text("Global transform");
239 ImGui::BulletText("P: %g %g %g", p.x, p.y, p.z);
241 ImGui::BulletText("R: %g %g %g %g", q.x, q.y, q.z, q.w);
243 ImGui::BulletText("S: %g %g %g", s.x, s.y, s.z);
245 const Mat4 &mat = get_matrix();
246 ImGui::BulletText("| %3.3f %3.3f %3.3f %3.3f |", mat[0][0], mat[0][1], mat[0][2], mat[0][3]);
247 ImGui::BulletText("| %3.3f %3.3f %3.3f %3.3f |", mat[1][0], mat[1][1], mat[1][2], mat[1][3]);
248 ImGui::BulletText("| %3.3f %3.3f %3.3f %3.3f |", mat[2][0], mat[2][1], mat[2][2], mat[2][3]);
249 ImGui::BulletText("| %3.3f %3.3f %3.3f %3.3f |", mat[3][0], mat[3][1], mat[3][2], mat[3][3]);
260 int num = children.size();
261 for(int i=0; i<num; i++) {
262 parent_expanded = expanded;
263 children[i]->update(dt);
266 if(debug_gui && expanded) {
271 void SceneNode::apply_xform()
275 // apply post-order to make sure we don't affect the children xform by our reset
277 int nchild = children.size();
278 for(int i=0; i<nchild; i++) {
279 children[i]->apply_xform();
282 int nobj = obj.size();
283 for(int i=0; i<nobj; i++) {
284 if(obj[i]->get_type() == OBJ_MESH) {
285 ObjMesh *om = (ObjMesh*)obj[i];
287 om->mesh->apply_xform(xform);
293 rot = Quat::identity;
294 scale = Vec3(1, 1, 1);
297 bool SceneNode::intersect(const Ray &ray, HitPoint *hit) const
299 Ray local_ray = inv_xform * ray;
302 nearest.dist = FLT_MAX;
303 for(size_t i=0; i<obj.size(); i++) {
304 if(obj[i]->intersect(local_ray, hit)) {
305 if(!hit) return true;
306 if(hit->dist < nearest.dist) {
308 nearest.data = (void*)this;
309 nearest.local_ray = local_ray;
314 for(size_t i=0; i<children.size(); i++) {
315 if(children[i]->intersect(ray, hit)) {
316 if(!hit) return true;
317 if(hit->dist < nearest.dist) {
323 if(nearest.dist < FLT_MAX) {
331 const AABox &SceneNode::calc_local_bounds()
333 local_bvol = AABox(Vec3(FLT_MAX, FLT_MAX, FLT_MAX), Vec3(-FLT_MAX, -FLT_MAX, -FLT_MAX));
335 // calculate the axis-aligned bounding box of all objects in this node
336 int nobj = obj.size();
337 for(int i=0; i<nobj; i++) {
338 AABox tmp = obj[i]->get_aabox();
339 calc_bounding_aabox(&local_bvol, &local_bvol, &tmp);
342 local_bvol_valid = true;
346 const AABox &SceneNode::get_local_bounds() const
348 if(!local_bvol_valid) {
349 ((SceneNode*)this)->calc_local_bounds();
354 AABox SceneNode::get_node_bounds() const
356 get_local_bounds(); // validate local_bvol
358 // calculate the transformed local_bvol
359 Box node_bbox = Box(local_bvol, xform);
361 // then calculate the axis-aligned bounding box
363 calc_bounding_aabox(&aabox, &node_bbox);
367 AABox SceneNode::get_bounds() const
369 AABox sub_aabb = AABox(Vec3(FLT_MAX, FLT_MAX, FLT_MAX), Vec3(-FLT_MAX, -FLT_MAX, -FLT_MAX));
371 // calculate the bounding box of all children
372 int nchild = children.size();
373 for(int i=0; i<nchild; i++) {
374 AABox tmp = children[i]->get_bounds();
375 calc_bounding_aabox(&sub_aabb, &sub_aabb, &tmp);
378 AABox aabb = get_node_bounds();
379 calc_bounding_aabox(&aabb, &aabb, &sub_aabb);