fixed bounding volume issue
authorJohn Tsiombikas <nuclear@member.fsf.org>
Fri, 12 Jan 2018 06:13:04 +0000 (08:13 +0200)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Fri, 12 Jan 2018 06:13:04 +0000 (08:13 +0200)
12 files changed:
src/app.cc
src/app.h
src/blob_exhibit.h
src/exhibit.cc
src/exhibit.h
src/geom.cc
src/geom.h
src/geomdraw.cc [new file with mode: 0644]
src/geomdraw.h [new file with mode: 0644]
src/object.cc
src/object.h
src/snode.cc

index 869af78..615366a 100644 (file)
@@ -39,6 +39,8 @@ SceneSet sceneman;
 
 unsigned int sdr_ltmap, sdr_ltmap_notex;
 
+int fpexcept_enabled;
+
 static Avatar avatar;
 
 static float cam_dist = 0.0;
@@ -82,6 +84,7 @@ bool app_init(int argc, char **argv)
        char *env = getenv("FPEXCEPT");
        if(env && atoi(env)) {
                info_log("enabling floating point exceptions\n");
+               fpexcept_enabled = 1;
                enable_fpexcept();
        }
 
index 83680ec..fe06daf 100644 (file)
--- a/src/app.h
+++ b/src/app.h
@@ -15,6 +15,8 @@ extern SceneSet sceneman;
 
 extern unsigned int sdr_ltmap, sdr_ltmap_notex;
 
+extern int fpexcept_enabled;   // int so that C modules may fwd-delcare and use it
+
 enum {
        MOD_SHIFT       = 1,
        MOD_ALT         = 2,
index 001047a..be279e6 100644 (file)
@@ -18,6 +18,8 @@ public:
 
        void update(float dt);
        void draw() const;
+
+       const AABox &get_aabox() const;
 };
 
 #endif // BLOB_EXHIBIT_H_
index eaa2251..c525f77 100644 (file)
@@ -1,6 +1,7 @@
 #include "exhibit.h"
 #include "snode.h"
 #include "scene.h"
+#include "geomdraw.h"
 
 class ExhibitPriv {
 public:
@@ -92,5 +93,17 @@ void Exhibit::post_draw() const
        if(node) {
                glMatrixMode(GL_MODELVIEW);
                glPopMatrix();
+
+               const AABox &bvol = get_aabox();
+               debug_log("bvol (%g %g %g) -> (%g %g %g)\n", bvol.min.x, bvol.min.y, bvol.min.z,
+                               bvol.max.x, bvol.max.y, bvol.max.z);
+               draw_geom_object(&bvol);
        }
 }
+
+
+const AABox &Exhibit::get_aabox() const
+{
+       aabb = node->get_bounds();
+       return aabb;
+}
index 0f98b05..f2c521b 100644 (file)
@@ -71,11 +71,13 @@ public:
        virtual ExSelection select(const Ray &ray) const;
        virtual ExSelection select(const Sphere &sph) const;
 
-       virtual void update(float dt = 0.0f);
+       virtual void update(float dt = 0.0f) override;
 
        virtual void pre_draw() const;
-       virtual void draw() const;
+       virtual void draw() const override;
        virtual void post_draw() const;
+
+       virtual const AABox &get_aabox() const override;
 };
 
 #endif // EXHIBIT_H_
index 0a82566..5fc3dce 100644 (file)
@@ -1,6 +1,7 @@
 #include <algorithm>
 #include <float.h>
 #include "geom.h"
+#include "app.h"
 
 #define SPHERE(ptr)    ((Sphere*)ptr)
 #define AABOX(ptr)     ((AABox*)ptr)
@@ -16,6 +17,15 @@ GeomObject::~GeomObject()
 {
 }
 
+bool GeomObject::valid() const
+{
+       return true;
+}
+
+void GeomObject::invalidate()
+{
+}
+
 
 Sphere::Sphere()
 {
@@ -30,6 +40,17 @@ Sphere::Sphere(const Vec3 &cent, float radius)
        this->radius = radius;
 }
 
+bool Sphere::valid() const
+{
+       return radius >= 0.0f;
+}
+
+void Sphere::invalidate()
+{
+       center = Vec3(0, 0, 0);
+       radius = -1;
+}
+
 bool Sphere::intersect(const Ray &ray, HitPoint *hit) const
 {
        float a = dot(ray.dir, ray.dir);
@@ -94,19 +115,41 @@ AABox::AABox(const Vec3 &vmin, const Vec3 &vmax)
        type = GOBJ_AABOX;
 }
 
+bool AABox::valid() const
+{
+       return min.x <= max.x && min.y <= max.y && min.z <= max.z;
+}
+
+void AABox::invalidate()
+{
+       min = Vec3(FLT_MAX, FLT_MAX, FLT_MAX);
+       max = Vec3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
+}
+
 Vec3 AABox::get_corner(int idx) const
 {
-       static const Vec3 v[] = {
-               Vec3(-0.5, -0.5, -0.5), Vec3(0.5, -0.5, -0.5), Vec3(0.5, -0.5, 0.5), Vec3(-0.5, -0.5, 0.5),
-               Vec3(-0.5, 0.5, -0.5), Vec3(0.5, 0.5, -0.5), Vec3(0.5, 0.5, 0.5), Vec3(-0.5, 0.5, 0.5)
-       };
-       return v[idx] * Vec3(max - min);
+       Vec3 v[] = {min, max};
+       static const int xidx[] = {0, 1, 1, 0, 0, 1, 1, 0};
+       static const int yidx[] = {0, 0, 0, 0, 1, 1, 1, 1};
+       static const int zidx[] = {0, 0, 1, 1, 0, 0, 1, 1};
+       return Vec3(v[xidx[idx]].x, v[yidx[idx]].y, v[zidx[idx]].z);
 }
 
 bool AABox::intersect(const Ray &ray, HitPoint *hit) const
 {
        Vec3 param[2] = {min, max};
+#ifndef NDEBUG
+       Vec3 inv_dir;
+       if(fpexcept_enabled) {
+               inv_dir.x = ray.dir.x == 0.0f ? 1.0f : 1.0f / ray.dir.x;
+               inv_dir.y = ray.dir.y == 0.0f ? 1.0f : 1.0f / ray.dir.y;
+               inv_dir.z = ray.dir.z == 0.0f ? 1.0f : 1.0f / ray.dir.z;
+       } else {
+               inv_dir = Vec3(1.0 / ray.dir.x, 1.0 / ray.dir.y, 1.0 / ray.dir.z);
+       }
+#else
        Vec3 inv_dir(1.0 / ray.dir.x, 1.0 / ray.dir.y, 1.0 / ray.dir.z);
+#endif
        int sign[3] = {inv_dir.x < 0, inv_dir.y < 0, inv_dir.z < 0};
 
        float tmin = (param[sign[0]].x - ray.origin.x) * inv_dir.x;
@@ -186,28 +229,39 @@ float AABox::signed_distance(const Vec3 &v) const
 
 Box::Box()
 {
+       type = GOBJ_BOX;
 }
 
 Box::Box(const AABox &aabox, const Mat4 &xform)
        : xform(xform)
 {
+       type = GOBJ_BOX;
        min = aabox.min;
        max = aabox.max;
 }
 
+void Box::invalidate()
+{
+       AABox::invalidate();
+       xform = Mat4::identity;
+}
+
 Box::Box(const Vec3 &min, const Vec3 &max)
        : AABox(min, max)
 {
+       type = GOBJ_BOX;
 }
 
 Box::Box(const Vec3 &min, const Vec3 &max, const Mat4 &xform)
        : AABox(min, max), xform(xform)
 {
+       type = GOBJ_BOX;
 }
 
 // XXX all this shit is completely untested
 Box::Box(const Vec3 &pos, const Vec3 &vi, const Vec3 &vj, const Vec3 &vk)
 {
+       type = GOBJ_BOX;
        float ilen = length(vi);
        float jlen = length(vj);
        float klen = length(vk);
@@ -225,17 +279,13 @@ Box::Box(const Vec3 &pos, const Vec3 &vi, const Vec3 &vj, const Vec3 &vk)
 
 Box::Box(const Vec3 *varr, int vcount)
 {
+       type = GOBJ_BOX;
        calc_bounding_aabox(this, varr, vcount);
 }
 
 Vec3 Box::get_corner(int idx) const
 {
-       static const Vec3 v[] = {
-               Vec3(-0.5, -0.5, -0.5), Vec3(0.5, -0.5, -0.5), Vec3(0.5, -0.5, 0.5), Vec3(-0.5, -0.5, 0.5),
-               Vec3(-0.5, 0.5, -0.5), Vec3(0.5, 0.5, -0.5), Vec3(0.5, 0.5, 0.5), Vec3(-0.5, 0.5, 0.5)
-       };
-
-       return xform * (v[idx] * Vec3(max - min));
+       return xform * AABox::get_corner(idx);
 }
 
 bool Box::intersect(const Ray &ray, HitPoint *hit) const
@@ -274,22 +324,26 @@ float Box::signed_distance(const Vec3 &v) const
 Plane::Plane()
        : normal(0.0, 1.0, 0.0)
 {
+       type = GOBJ_PLANE;
 }
 
 Plane::Plane(const Vec3 &p, const Vec3 &norm)
        : pt(p)
 {
+       type = GOBJ_PLANE;
        normal = normalize(norm);
 }
 
 Plane::Plane(const Vec3 &p1, const Vec3 &p2, const Vec3 &p3)
        : pt(p1)
 {
+       type = GOBJ_PLANE;
        normal = normalize(cross(p2 - p1, p3 - p1));
 }
 
 Plane::Plane(const Vec3 &normal, float dist)
 {
+       type = GOBJ_PLANE;
        this->normal = normalize(normal);
        pt = this->normal * dist;
 }
@@ -331,21 +385,34 @@ float Plane::signed_distance(const Vec3 &v) const
 
 Disc::Disc()
 {
+       type = GOBJ_DISC;
        radius = 1.0;
 }
 
 Disc::Disc(const Vec3 &pt, const Vec3 &normal, float rad)
        : Plane(pt, normal)
 {
+       type = GOBJ_DISC;
        radius = rad;
 }
 
 Disc::Disc(const Vec3 &normal, float dist, float rad)
        : Plane(normal, dist)
 {
+       type = GOBJ_DISC;
        radius = rad;
 }
 
+bool Disc::valid() const
+{
+       return radius >= 0.0f;
+}
+
+void Disc::invalidate()
+{
+       radius = -1;
+}
+
 bool Disc::intersect(const Ray &ray, HitPoint *hit) const
 {
        HitPoint phit;
@@ -385,6 +452,11 @@ Vec3 proj_point_plane(const Vec3 &pt, const Plane &plane)
 
 bool calc_bounding_sphere(Sphere *sph, const GeomObject *obj)
 {
+       if(!obj->valid()) {
+               sph->invalidate();
+               return true;
+       }
+
        switch(obj->type) {
        case GOBJ_SPHERE:
                *sph = *(Sphere*)obj;
@@ -466,6 +538,11 @@ bool calc_bounding_sphere(Sphere *sph, const Vec3 *v, int num, const Mat4 &xform
 
 bool calc_bounding_aabox(AABox *box, const GeomObject *obj)
 {
+       if(!obj->valid()) {
+               box->invalidate();
+               return true;
+       }
+
        switch(obj->type) {
        case GOBJ_AABOX:
                *box = *(AABox*)obj;
@@ -545,6 +622,11 @@ bool calc_bounding_aabox(AABox *box, const Vec3 *v, int num, const Mat4 &xform)
 
 bool calc_bounding_box(Box *box, const GeomObject *obj)
 {
+       if(!obj->valid()) {
+               box->invalidate();
+               return true;
+       }
+
        switch(obj->type) {
        case GOBJ_BOX:
                *box = *(Box*)obj;
index f28f878..5db1996 100644 (file)
@@ -12,7 +12,8 @@ enum GeomObjectType {
        GOBJ_SPHERE,
        GOBJ_AABOX,
        GOBJ_BOX,
-       GOBJ_PLANE
+       GOBJ_PLANE,
+       GOBJ_DISC
 };
 
 class GeomObject;
@@ -33,6 +34,9 @@ public:
        GeomObject();
        virtual ~GeomObject();
 
+       virtual bool valid() const;
+       virtual void invalidate();
+
        virtual bool intersect(const Ray &ray, HitPoint *hit = 0) const = 0;
        virtual bool contains(const Vec3 &pt) const = 0;
 
@@ -48,6 +52,9 @@ public:
        Sphere();
        Sphere(const Vec3 &center, float radius);
 
+       virtual bool valid() const;
+       virtual void invalidate();
+
        virtual bool intersect(const Ray &ray, HitPoint *hit = 0) const;
        virtual bool contains(const Vec3 &pt) const;
 
@@ -62,6 +69,9 @@ public:
        AABox();
        AABox(const Vec3 &min, const Vec3 &max);
 
+       virtual bool valid() const;
+       virtual void invalidate();
+
        virtual Vec3 get_corner(int idx) const;
 
        virtual bool intersect(const Ray &ray, HitPoint *hit = 0) const;
@@ -82,6 +92,8 @@ public:
        Box(const Vec3 &pos, const Vec3 &vi, const Vec3 &vj, const Vec3 &vk);
        Box(const Vec3 *varr, int vcount);
 
+       virtual void invalidate();
+
        virtual Vec3 get_corner(int idx) const;
 
        virtual bool intersect(const Ray &ray, HitPoint *hit = 0) const;
@@ -116,6 +128,9 @@ public:
        Disc(const Vec3 &pt, const Vec3 &normal, float rad);
        Disc(const Vec3 &normal, float dist, float rad);
 
+       virtual bool valid() const;
+       virtual void invalidate();
+
        virtual bool intersect(const Ray &ray, HitPoint *hit = 0) const;
        //! true if the projection of pt to the plane is contained within the disc radius
        virtual bool contains(const Vec3 &pt) const;
diff --git a/src/geomdraw.cc b/src/geomdraw.cc
new file mode 100644 (file)
index 0000000..b348f87
--- /dev/null
@@ -0,0 +1,80 @@
+#include "geomdraw.h"
+#include "opengl.h"
+#include "logger.h"
+#include "shader.h"
+
+static void draw_sphere(const Sphere *sph);
+static void draw_box(const Box *box);
+static void draw_plane(const Plane *plane);
+
+void draw_geom_object(const GeomObject *gobj)
+{
+       switch(gobj->type) {
+       case GOBJ_SPHERE:
+               draw_sphere((Sphere*)gobj);
+               break;
+
+       case GOBJ_AABOX:
+               {
+                       Box box = Box(*(AABox*)gobj, Mat4::identity);
+                       draw_box(&box);
+               }
+               break;
+
+       case GOBJ_BOX:
+               draw_box((Box*)gobj);
+               break;
+
+       case GOBJ_PLANE:
+               draw_plane((Plane*)gobj);
+               break;
+
+       default:
+               break;
+       }
+}
+
+static void draw_sphere(const Sphere *sph)
+{
+       // TODO
+       warning_log("draw_sphere unimplemented\n");
+}
+
+static void draw_box(const Box *box)
+{
+       static const int edges[][2] = {
+               {0, 1}, {1, 2}, {2, 3}, {3, 0},
+               {4, 5}, {5, 6}, {6, 7}, {7, 4},
+               {0, 4}, {1, 5}, {2, 6}, {3, 7}
+       };
+
+       bind_shader(0);
+
+       glPushAttrib(GL_ENABLE_BIT);
+       glDisable(GL_LIGHTING);
+       glDisable(GL_TEXTURE_2D);
+
+       glMatrixMode(GL_MODELVIEW);
+       glPushMatrix();
+       glMultMatrixf(box->xform[0]);
+
+       glBegin(GL_LINES);
+       glColor3f(1, 1, 0);
+       for(int i=0; i<12; i++) {
+               Vec3 a = box->get_corner(edges[i][0]);
+               Vec3 b = box->get_corner(edges[i][1]);
+
+               glVertex3f(a.x, a.y, a.z);
+               glVertex3f(b.x, b.y, b.z);
+       }
+       glEnd();
+
+       glPopMatrix();
+       glPopAttrib();
+}
+
+static void draw_plane(const Plane *plane)
+{
+       // TODO
+       warning_log("draw_plane unimplemented\n");
+}
diff --git a/src/geomdraw.h b/src/geomdraw.h
new file mode 100644 (file)
index 0000000..05e86e6
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef GEOMDRAW_H_
+#define GEOMDRAW_H_
+
+#include "geom.h"
+
+void draw_geom_object(const GeomObject *gobj);
+
+#endif
index 3318660..2bc8b79 100644 (file)
@@ -38,6 +38,5 @@ void Object::draw() const
 
 const AABox &Object::get_aabox() const
 {
-       static AABox null_box;
-       return null_box;
+       return aabb;
 }
index 65c39e1..3ffec1f 100644 (file)
@@ -12,12 +12,12 @@ class SceneNode;
 enum ObjType { OBJ_NULL, OBJ_MESH };
 
 class Object {
-private:
+protected:
        std::string name;
+       mutable AABox aabb;
 
 public:
        Material mtl;
-       //GeomObject *bvol;
        SceneNode *node;
 
        Object();
index eee5fce..fd37f24 100644 (file)
@@ -330,7 +330,7 @@ AABox SceneNode::get_bounds() const
                calc_bounding_aabox(&sub_aabb, &sub_aabb, &tmp);
        }
 
-       AABox aabb;
-       calc_bounding_aabox(&aabb, &local_bvol, &sub_aabb);
+       AABox aabb = get_node_bounds();
+       calc_bounding_aabox(&aabb, &aabb, &sub_aabb);
        return aabb;
 }