#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);
}
void SceneNode::add_child(SceneNode *node)
{
+ if(!node) return;
+
if(node->parent) {
if(node->parent == this) {
return;
children.push_back(node);
node->parent = this;
+ node->scene = scene;
}
bool SceneNode::remove_child(SceneNode *node)
{
+ if(!node) return false;
+
auto it = std::find(children.begin(), children.end(), node);
if(it != children.end()) {
assert(node->parent == this);
node->parent = 0;
+ node->scene = 0;
+ children.erase(it);
return true;
}
return false;
this->obj.push_back(obj);
obj->node = this;
+
+ local_bvol_valid = false;
}
bool SceneNode::remove_object(Object *o)
return false;
}
obj.erase(it);
+
+ local_bvol_valid = false;
return true;
}
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
xform.pre_scale(scale);
if(parent) {
- xform = parent->xform * xform;
+ xform = xform * parent->xform;
}
inv_xform = inverse(xform);
}
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
{
}
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;
+}