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 SceneNode *SceneNode::find_object_node() const
94 if(!obj.empty()) return (SceneNode*)this;
96 int numc = get_num_children();
97 for(int i=0; i<numc; i++) {
98 SceneNode *n = get_child(i)->find_object_node();
104 void SceneNode::add_object(Object *obj)
106 if(obj->node == this) return;
109 obj->node->remove_object(obj);
112 this->obj.push_back(obj);
115 local_bvol_valid = false;
118 bool SceneNode::remove_object(Object *o)
120 if(o->node != this) {
125 auto it = std::find(obj.begin(), obj.end(), o);
126 if(it == obj.end()) {
131 local_bvol_valid = false;
135 int SceneNode::get_num_objects() const
137 return (int)obj.size();
140 Object *SceneNode::get_object(int idx) const
145 void SceneNode::set_position(const Vec3 &pos)
150 void SceneNode::set_rotation(const Quat &rot)
155 void SceneNode::set_scaling(const Vec3 &scale)
161 const Vec3 &SceneNode::get_node_position() const
166 const Quat &SceneNode::get_node_rotation() const
171 const Vec3 &SceneNode::get_node_scaling() const
177 Vec3 SceneNode::get_position() const
179 return xform.get_translation();
182 Quat SceneNode::get_rotation() const
184 return xform.get_rotation();
187 Vec3 SceneNode::get_scaling() const
189 return xform.get_scaling();
192 const Mat4 &SceneNode::get_matrix() const
197 const Mat4 &SceneNode::get_inv_matrix() const
203 void SceneNode::update_node(float dt)
205 xform = Mat4::identity;
206 xform.pre_translate(pos);
207 xform.pre_rotate(rot);
208 xform.pre_scale(scale);
211 xform = xform * parent->xform;
213 inv_xform = inverse(xform);
216 void SceneNode::update(float dt)
218 bool expanded = false;
221 if(parent_expanded) {
223 ImGui::AlignTextToFramePadding();
225 int flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick;
226 if(children.empty()) flags |= ImGuiTreeNodeFlags_Leaf;
227 if(dbg_sel_node == this) flags |= ImGuiTreeNodeFlags_Selected;
228 expanded = ImGui::TreeNodeEx(name ? name : "<nameless node>", flags);
229 if(ImGui::IsItemClicked()) {
234 ImGui::Checkbox("##vis", &visible);
236 if(ImGui::Button("xform")) {
237 ImGui::OpenPopup("xform_popup");
240 if(ImGui::Button("bbox")) {
241 ImGui::OpenPopup("bbox_popup");
243 if(ImGui::BeginPopup("xform_popup")) {
244 ImGui::Text("Local transform");
245 Vec3 p = get_node_position();
246 ImGui::BulletText("P: %g %g %g", p.x, p.y, p.z);
247 Quat q = get_node_rotation();
248 ImGui::BulletText("R: %g %g %g %g", q.x, q.y, q.z, q.w);
249 Vec3 s = get_node_scaling();
250 ImGui::BulletText("S: %g %g %g", s.x, s.y, s.z);
253 ImGui::Text("Global transform");
255 ImGui::BulletText("P: %g %g %g", p.x, p.y, p.z);
257 ImGui::BulletText("R: %g %g %g %g", q.x, q.y, q.z, q.w);
259 ImGui::BulletText("S: %g %g %g", s.x, s.y, s.z);
261 const Mat4 &mat = get_matrix();
262 ImGui::BulletText("| %3.3f %3.3f %3.3f %3.3f |", mat[0][0], mat[0][1], mat[0][2], mat[0][3]);
263 ImGui::BulletText("| %3.3f %3.3f %3.3f %3.3f |", mat[1][0], mat[1][1], mat[1][2], mat[1][3]);
264 ImGui::BulletText("| %3.3f %3.3f %3.3f %3.3f |", mat[2][0], mat[2][1], mat[2][2], mat[2][3]);
265 ImGui::BulletText("| %3.3f %3.3f %3.3f %3.3f |", mat[3][0], mat[3][1], mat[3][2], mat[3][3]);
269 if(ImGui::BeginPopup("bbox_popup")) {
270 AABox bloc = get_local_bounds();
271 ImGui::Text("Local bounds:");
272 if(bloc.max.x < bloc.min.x || bloc.max.y < bloc.min.y || bloc.max.z < bloc.min.z) {
273 ImGui::BulletText("invalid");
275 ImGui::BulletText("X: %f - %f", bloc.min.x, bloc.max.x);
276 ImGui::BulletText("Y: %f - %f", bloc.min.y, bloc.max.y);
277 ImGui::BulletText("Z: %f - %f", bloc.min.z, bloc.max.z);
280 AABox bbox = get_bounds();
281 ImGui::Text("Global bounds:");
282 if(bbox.max.x < bbox.min.x || bbox.max.y < bbox.min.y || bbox.max.z < bbox.min.z) {
283 ImGui::BulletText("invalid");
285 ImGui::BulletText("X: %f - %f", bbox.min.x, bbox.max.x);
286 ImGui::BulletText("Y: %f - %f", bbox.min.y, bbox.max.y);
287 ImGui::BulletText("Z: %f - %f", bbox.min.z, bbox.max.z);
298 int num = children.size();
299 for(int i=0; i<num; i++) {
300 parent_expanded = expanded;
301 children[i]->update(dt);
304 if(debug_gui && expanded) {
309 void SceneNode::apply_xform()
313 // apply post-order to make sure we don't affect the children xform by our reset
315 int nchild = children.size();
316 for(int i=0; i<nchild; i++) {
317 children[i]->apply_xform();
320 int nobj = obj.size();
321 for(int i=0; i<nobj; i++) {
322 if(obj[i]->get_type() == OBJ_MESH) {
323 ObjMesh *om = (ObjMesh*)obj[i];
325 om->mesh->apply_xform(xform);
331 rot = Quat::identity;
332 scale = Vec3(1, 1, 1);
335 bool SceneNode::intersect(const Ray &ray, HitPoint *hit) const
337 Ray local_ray = inv_xform * ray;
340 nearest.dist = FLT_MAX;
341 for(size_t i=0; i<obj.size(); i++) {
342 if(obj[i]->intersect(local_ray, hit)) {
343 if(!hit) return true;
344 if(hit->dist < nearest.dist) {
346 nearest.data = (void*)this;
347 nearest.local_ray = local_ray;
352 for(size_t i=0; i<children.size(); i++) {
353 if(children[i]->intersect(ray, hit)) {
354 if(!hit) return true;
355 if(hit->dist < nearest.dist) {
361 if(nearest.dist < FLT_MAX) {
369 const AABox &SceneNode::calc_local_bounds()
371 local_bvol = AABox(Vec3(FLT_MAX, FLT_MAX, FLT_MAX), Vec3(-FLT_MAX, -FLT_MAX, -FLT_MAX));
373 // calculate the axis-aligned bounding box of all objects in this node
374 int nobj = obj.size();
375 for(int i=0; i<nobj; i++) {
376 AABox tmp = obj[i]->get_aabox();
377 calc_bounding_aabox(&local_bvol, &local_bvol, &tmp);
380 local_bvol_valid = true;
384 const AABox &SceneNode::get_local_bounds() const
386 if(!local_bvol_valid) {
387 ((SceneNode*)this)->calc_local_bounds();
392 AABox SceneNode::get_node_bounds() const
394 get_local_bounds(); // validate local_bvol
396 // calculate the transformed local_bvol
397 Box node_bbox = Box(local_bvol, xform);
399 // then calculate the axis-aligned bounding box
401 calc_bounding_aabox(&aabox, &node_bbox);
405 AABox SceneNode::get_bounds() const
407 AABox sub_aabb = AABox(Vec3(FLT_MAX, FLT_MAX, FLT_MAX), Vec3(-FLT_MAX, -FLT_MAX, -FLT_MAX));
409 // calculate the bounding box of all children
410 int nchild = children.size();
411 for(int i=0; i<nchild; i++) {
412 AABox tmp = children[i]->get_bounds();
413 calc_bounding_aabox(&sub_aabb, &sub_aabb, &tmp);
416 AABox aabb = get_node_bounds();
417 calc_bounding_aabox(&aabb, &aabb, &sub_aabb);