reflection geometry finally correct
[laserbrain_demo] / src / snode.cc
index 101fe62..2484e6e 100644 (file)
@@ -2,19 +2,27 @@
 #include <assert.h>
 #include <algorithm>
 #include "snode.h"
+#include "objmesh.h"
+#include "dbg_gui.h"
 
 SceneNode::SceneNode()
        : scale(1, 1, 1)
 {
+       scene = 0;
        parent = 0;
        name = 0;
+       visible = true;
+       local_bvol_valid = false;
 }
 
 SceneNode::SceneNode(Object *obj)
        : scale(1, 1, 1)
 {
+       scene = 0;
        parent = 0;
        name = 0;
+       visible = true;
+       local_bvol_valid = false;
        add_object(obj);
 }
 
@@ -48,6 +56,7 @@ void SceneNode::add_child(SceneNode *node)
 
        children.push_back(node);
        node->parent = this;
+       node->scene = scene;
 }
 
 bool SceneNode::remove_child(SceneNode *node)
@@ -58,6 +67,8 @@ bool SceneNode::remove_child(SceneNode *node)
        if(it != children.end()) {
                assert(node->parent == this);
                node->parent = 0;
+               node->scene = 0;
+               children.erase(it);
                return true;
        }
        return false;
@@ -88,6 +99,8 @@ void SceneNode::add_object(Object *obj)
 
        this->obj.push_back(obj);
        obj->node = this;
+
+       local_bvol_valid = false;
 }
 
 bool SceneNode::remove_object(Object *o)
@@ -102,6 +115,8 @@ bool SceneNode::remove_object(Object *o)
                return false;
        }
        obj.erase(it);
+
+       local_bvol_valid = false;
        return true;
 }
 
@@ -149,17 +164,17 @@ const Vec3 &SceneNode::get_node_scaling() const
 
 Vec3 SceneNode::get_position() const
 {
-       return xform * Vec3(0, 0, 0);
+       return xform.get_translation();
 }
 
 Quat SceneNode::get_rotation() const
 {
-       return rot;     // TODO
+       return xform.get_rotation();
 }
 
 Vec3 SceneNode::get_scaling() const
 {
-       return scale;   // TODO
+       return xform.get_scaling();
 }
 
 const Mat4 &SceneNode::get_matrix() const
@@ -188,13 +203,122 @@ void SceneNode::update_node(float dt)
 
 void SceneNode::update(float dt)
 {
+       bool expanded = false;
+
+       if(debug_gui) {
+               if(parent_expanded) {
+                       ImGui::PushID(this);
+                       ImGui::AlignTextToFramePadding();
+
+                       int flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick;
+                       if(children.empty()) flags |= ImGuiTreeNodeFlags_Leaf;
+                       if(dbg_sel_node == this) flags |= ImGuiTreeNodeFlags_Selected;
+                       expanded = ImGui::TreeNodeEx(name ? name : "<nameless node>", flags);
+                       if(ImGui::IsItemClicked()) {
+                               dbg_sel_node = this;
+                       }
+
+                       ImGui::NextColumn();
+                       ImGui::Checkbox("##vis", &visible);
+                       ImGui::SameLine();
+                       if(ImGui::Button("xform")) {
+                               ImGui::OpenPopup("xform_popup");
+                       }
+                       ImGui::SameLine();
+                       if(ImGui::Button("bbox")) {
+                               ImGui::OpenPopup("bbox_popup");
+                       }
+                       if(ImGui::BeginPopup("xform_popup")) {
+                               ImGui::Text("Local transform");
+                               Vec3 p = get_node_position();
+                               ImGui::BulletText("P: %g %g %g", p.x, p.y, p.z);
+                               Quat q = get_node_rotation();
+                               ImGui::BulletText("R: %g %g %g %g", q.x, q.y, q.z, q.w);
+                               Vec3 s = get_node_scaling();
+                               ImGui::BulletText("S: %g %g %g", s.x, s.y, s.z);
+
+                               ImGui::Separator();
+                               ImGui::Text("Global transform");
+                               p = get_position();
+                               ImGui::BulletText("P: %g %g %g", p.x, p.y, p.z);
+                               q = get_rotation();
+                               ImGui::BulletText("R: %g %g %g %g", q.x, q.y, q.z, q.w);
+                               s = get_scaling();
+                               ImGui::BulletText("S: %g %g %g", s.x, s.y, s.z);
+
+                               const Mat4 &mat = get_matrix();
+                               ImGui::BulletText("| %3.3f %3.3f %3.3f %3.3f |", mat[0][0], mat[0][1], mat[0][2], mat[0][3]);
+                               ImGui::BulletText("| %3.3f %3.3f %3.3f %3.3f |", mat[1][0], mat[1][1], mat[1][2], mat[1][3]);
+                               ImGui::BulletText("| %3.3f %3.3f %3.3f %3.3f |", mat[2][0], mat[2][1], mat[2][2], mat[2][3]);
+                               ImGui::BulletText("| %3.3f %3.3f %3.3f %3.3f |", mat[3][0], mat[3][1], mat[3][2], mat[3][3]);
+
+                               ImGui::EndPopup();
+                       }
+                       if(ImGui::BeginPopup("bbox_popup")) {
+                               AABox bloc = get_local_bounds();
+                               ImGui::Text("Local bounds:");
+                               if(bloc.max.x < bloc.min.x || bloc.max.y < bloc.min.y || bloc.max.z < bloc.min.z) {
+                                       ImGui::BulletText("invalid");
+                               } else {
+                                       ImGui::BulletText("X: %f - %f", bloc.min.x, bloc.max.x);
+                                       ImGui::BulletText("Y: %f - %f", bloc.min.y, bloc.max.y);
+                                       ImGui::BulletText("Z: %f - %f", bloc.min.z, bloc.max.z);
+                               }
+                               ImGui::Separator();
+                               AABox bbox = get_bounds();
+                               ImGui::Text("Global bounds:");
+                               if(bbox.max.x < bbox.min.x || bbox.max.y < bbox.min.y || bbox.max.z < bbox.min.z) {
+                                       ImGui::BulletText("invalid");
+                               } else {
+                                       ImGui::BulletText("X: %f - %f", bbox.min.x, bbox.max.x);
+                                       ImGui::BulletText("Y: %f - %f", bbox.min.y, bbox.max.y);
+                                       ImGui::BulletText("Z: %f - %f", bbox.min.z, bbox.max.z);
+                               }
+                               ImGui::EndPopup();
+                       }
+                       ImGui::NextColumn();
+                       ImGui::PopID();
+               }
+       }
+
        update_node(dt);
 
-       for(size_t i=0; i<children.size(); i++) {
+       int num = children.size();
+       for(int i=0; i<num; i++) {
+               parent_expanded = expanded;
                children[i]->update(dt);
        }
+
+       if(debug_gui && expanded) {
+               ImGui::TreePop();
+       }
 }
 
+void SceneNode::apply_xform()
+{
+       update_node();
+
+       // apply post-order to make sure we don't affect the children xform by our reset
+
+       int nchild = children.size();
+       for(int i=0; i<nchild; i++) {
+               children[i]->apply_xform();
+       }
+
+       int nobj = obj.size();
+       for(int i=0; i<nobj; i++) {
+               if(obj[i]->get_type() == OBJ_MESH) {
+                       ObjMesh *om = (ObjMesh*)obj[i];
+                       if(om->mesh) {
+                               om->mesh->apply_xform(xform);
+                       }
+               }
+       }
+
+       pos = Vec3(0, 0, 0);
+       rot = Quat::identity;
+       scale = Vec3(1, 1, 1);
+}
 
 bool SceneNode::intersect(const Ray &ray, HitPoint *hit) const
 {
@@ -229,3 +353,55 @@ bool SceneNode::intersect(const Ray &ray, HitPoint *hit) const
        }
        return false;
 }
+
+const AABox &SceneNode::calc_local_bounds()
+{
+       local_bvol = AABox(Vec3(FLT_MAX, FLT_MAX, FLT_MAX), Vec3(-FLT_MAX, -FLT_MAX, -FLT_MAX));
+
+       // calculate the axis-aligned bounding box of all objects in this node
+       int nobj = obj.size();
+       for(int i=0; i<nobj; i++) {
+               AABox tmp = obj[i]->get_aabox();
+               calc_bounding_aabox(&local_bvol, &local_bvol, &tmp);
+       }
+
+       local_bvol_valid = true;
+       return local_bvol;
+}
+
+const AABox &SceneNode::get_local_bounds() const
+{
+       if(!local_bvol_valid) {
+               ((SceneNode*)this)->calc_local_bounds();
+       }
+       return local_bvol;
+}
+
+AABox SceneNode::get_node_bounds() const
+{
+       get_local_bounds();     // validate local_bvol
+
+       // calculate the transformed local_bvol
+       Box node_bbox = Box(local_bvol, xform);
+
+       // then calculate the axis-aligned bounding box
+       AABox aabox;
+       calc_bounding_aabox(&aabox, &node_bbox);
+       return aabox;
+}
+
+AABox SceneNode::get_bounds() const
+{
+       AABox sub_aabb = AABox(Vec3(FLT_MAX, FLT_MAX, FLT_MAX), Vec3(-FLT_MAX, -FLT_MAX, -FLT_MAX));
+
+       // calculate the bounding box of all children
+       int nchild = children.size();
+       for(int i=0; i<nchild; i++) {
+               AABox tmp = children[i]->get_bounds();
+               calc_bounding_aabox(&sub_aabb, &sub_aabb, &tmp);
+       }
+
+       AABox aabb = get_node_bounds();
+       calc_bounding_aabox(&aabb, &aabb, &sub_aabb);
+       return aabb;
+}