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");
228 if(ImGui::Button("bbox")) {
229 ImGui::OpenPopup("bbox_popup");
231 if(ImGui::BeginPopup("xform_popup")) {
232 ImGui::Text("Local transform");
233 Vec3 p = get_node_position();
234 ImGui::BulletText("P: %g %g %g", p.x, p.y, p.z);
235 Quat q = get_node_rotation();
236 ImGui::BulletText("R: %g %g %g %g", q.x, q.y, q.z, q.w);
237 Vec3 s = get_node_scaling();
238 ImGui::BulletText("S: %g %g %g", s.x, s.y, s.z);
241 ImGui::Text("Global transform");
243 ImGui::BulletText("P: %g %g %g", p.x, p.y, p.z);
245 ImGui::BulletText("R: %g %g %g %g", q.x, q.y, q.z, q.w);
247 ImGui::BulletText("S: %g %g %g", s.x, s.y, s.z);
249 const Mat4 &mat = get_matrix();
250 ImGui::BulletText("| %3.3f %3.3f %3.3f %3.3f |", mat[0][0], mat[0][1], mat[0][2], mat[0][3]);
251 ImGui::BulletText("| %3.3f %3.3f %3.3f %3.3f |", mat[1][0], mat[1][1], mat[1][2], mat[1][3]);
252 ImGui::BulletText("| %3.3f %3.3f %3.3f %3.3f |", mat[2][0], mat[2][1], mat[2][2], mat[2][3]);
253 ImGui::BulletText("| %3.3f %3.3f %3.3f %3.3f |", mat[3][0], mat[3][1], mat[3][2], mat[3][3]);
257 if(ImGui::BeginPopup("bbox_popup")) {
258 AABox bloc = get_local_bounds();
259 ImGui::Text("Local bounds:");
260 if(bloc.max.x < bloc.min.x || bloc.max.y < bloc.min.y || bloc.max.z < bloc.min.z) {
261 ImGui::BulletText("invalid");
263 ImGui::BulletText("X: %f - %f", bloc.min.x, bloc.max.x);
264 ImGui::BulletText("Y: %f - %f", bloc.min.y, bloc.max.y);
265 ImGui::BulletText("Z: %f - %f", bloc.min.z, bloc.max.z);
268 AABox bbox = get_bounds();
269 ImGui::Text("Global bounds:");
270 if(bbox.max.x < bbox.min.x || bbox.max.y < bbox.min.y || bbox.max.z < bbox.min.z) {
271 ImGui::BulletText("invalid");
273 ImGui::BulletText("X: %f - %f", bbox.min.x, bbox.max.x);
274 ImGui::BulletText("Y: %f - %f", bbox.min.y, bbox.max.y);
275 ImGui::BulletText("Z: %f - %f", bbox.min.z, bbox.max.z);
286 int num = children.size();
287 for(int i=0; i<num; i++) {
288 parent_expanded = expanded;
289 children[i]->update(dt);
292 if(debug_gui && expanded) {
297 void SceneNode::apply_xform()
301 // apply post-order to make sure we don't affect the children xform by our reset
303 int nchild = children.size();
304 for(int i=0; i<nchild; i++) {
305 children[i]->apply_xform();
308 int nobj = obj.size();
309 for(int i=0; i<nobj; i++) {
310 if(obj[i]->get_type() == OBJ_MESH) {
311 ObjMesh *om = (ObjMesh*)obj[i];
313 om->mesh->apply_xform(xform);
319 rot = Quat::identity;
320 scale = Vec3(1, 1, 1);
323 bool SceneNode::intersect(const Ray &ray, HitPoint *hit) const
325 Ray local_ray = inv_xform * ray;
328 nearest.dist = FLT_MAX;
329 for(size_t i=0; i<obj.size(); i++) {
330 if(obj[i]->intersect(local_ray, hit)) {
331 if(!hit) return true;
332 if(hit->dist < nearest.dist) {
334 nearest.data = (void*)this;
335 nearest.local_ray = local_ray;
340 for(size_t i=0; i<children.size(); i++) {
341 if(children[i]->intersect(ray, hit)) {
342 if(!hit) return true;
343 if(hit->dist < nearest.dist) {
349 if(nearest.dist < FLT_MAX) {
357 const AABox &SceneNode::calc_local_bounds()
359 local_bvol = AABox(Vec3(FLT_MAX, FLT_MAX, FLT_MAX), Vec3(-FLT_MAX, -FLT_MAX, -FLT_MAX));
361 // calculate the axis-aligned bounding box of all objects in this node
362 int nobj = obj.size();
363 for(int i=0; i<nobj; i++) {
364 AABox tmp = obj[i]->get_aabox();
365 calc_bounding_aabox(&local_bvol, &local_bvol, &tmp);
368 local_bvol_valid = true;
372 const AABox &SceneNode::get_local_bounds() const
374 if(!local_bvol_valid) {
375 ((SceneNode*)this)->calc_local_bounds();
380 AABox SceneNode::get_node_bounds() const
382 get_local_bounds(); // validate local_bvol
384 // calculate the transformed local_bvol
385 Box node_bbox = Box(local_bvol, xform);
387 // then calculate the axis-aligned bounding box
389 calc_bounding_aabox(&aabox, &node_bbox);
393 AABox SceneNode::get_bounds() const
395 AABox sub_aabb = AABox(Vec3(FLT_MAX, FLT_MAX, FLT_MAX), Vec3(-FLT_MAX, -FLT_MAX, -FLT_MAX));
397 // calculate the bounding box of all children
398 int nchild = children.size();
399 for(int i=0; i<nchild; i++) {
400 AABox tmp = children[i]->get_bounds();
401 calc_bounding_aabox(&sub_aabb, &sub_aabb, &tmp);
404 AABox aabb = get_node_bounds();
405 calc_bounding_aabox(&aabb, &aabb, &sub_aabb);