X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=laserbrain_demo;a=blobdiff_plain;f=src%2Fgeom.cc;h=1813eea03af3f08dd7e173489e69dcda12bbe783;hp=0a82566b756e8acbcd8356c2739bfa5692fe0ec5;hb=2f5ee2007d258d947f2efab3bf3460479fe34813;hpb=ad052fc67fe4e76d2f4a01b2381a738da1708cdb diff --git a/src/geom.cc b/src/geom.cc index 0a82566..1813eea 100644 --- a/src/geom.cc +++ b/src/geom.cc @@ -1,6 +1,8 @@ -#include +#include #include +#include #include "geom.h" +#include "app.h" #define SPHERE(ptr) ((Sphere*)ptr) #define AABOX(ptr) ((AABox*)ptr) @@ -16,6 +18,24 @@ GeomObject::~GeomObject() { } +bool GeomObject::valid() const +{ + return true; +} + +void GeomObject::invalidate() +{ +} + +float GeomObject::distance(const Vec3 &v) const +{ + return sqrt(distance_sq(v)); +} + +float GeomObject::signed_distance(const Vec3 &v) const +{ + return sqrt(signed_distance_sq(v)); +} Sphere::Sphere() { @@ -30,6 +50,17 @@ Sphere::Sphere(const Vec3 ¢, 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); @@ -73,14 +104,14 @@ bool Sphere::contains(const Vec3 &pt) const return length_sq(pt - center) <= radius * radius; } -float Sphere::distance(const Vec3 &v) const +float Sphere::distance_sq(const Vec3 &v) const { - return std::max(length(v - center) - radius, 0.0f); + return std::max(length_sq(v - center) - radius * radius, 0.0f); } -float Sphere::signed_distance(const Vec3 &v) const +float Sphere::signed_distance_sq(const Vec3 &v) const { - return length(v - center) - radius; + return length_sq(v - center) - radius * radius; } AABox::AABox() @@ -94,19 +125,63 @@ 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); +} + +Plane AABox::get_plane(int pidx) const +{ + switch(pidx) { + case AABOX_PLANE_PX: + return Plane(Vec3(max.x, 0, 0), Vec3(1, 0, 0)); + case AABOX_PLANE_NX: + return Plane(Vec3(min.x, 0, 0), Vec3(-1, 0, 0)); + case AABOX_PLANE_PY: + return Plane(Vec3(0, max.x, 0), Vec3(0, 1, 0)); + case AABOX_PLANE_NY: + return Plane(Vec3(0, min.x, 0), Vec3(0, -1, 0)); + case AABOX_PLANE_PZ: + return Plane(Vec3(0, 0, max.z), Vec3(0, 0, 1)); + case AABOX_PLANE_NZ: + return Plane(Vec3(0, 0, min.z), Vec3(0, 0, -1)); + default: + break; + } + abort(); + return Plane(); } 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; @@ -174,40 +249,68 @@ bool AABox::contains(const Vec3 &v) const v.x <= max.x && v.y <= max.y && v.z <= max.z; } -float AABox::distance(const Vec3 &v) const +#define SQ(x) ((x) * (x)) +float AABox::distance_sq(const Vec3 &v) const { - return 0.0; // TODO + float dsq = 0.0f; + + for(int i=0; i<3; i++) { + if(v[i] < min[i]) dsq += SQ(min[i] - v[i]); + if(v[i] > max[i]) dsq += SQ(v[i] - max[i]); + } + return dsq; } -float AABox::signed_distance(const Vec3 &v) const +float AABox::signed_distance_sq(const Vec3 &v) const { - return 0.0; // TODO + if(!contains(v)) { + return distance_sq(v); + } + + float dsq = 0.0f; + for(int i=0; i<3; i++) { + float dmin = v[i] - min[i]; + float dmax = max[i] - v[i]; + dsq -= dmin < dmax ? SQ(dmin) : SQ(dmax); + } + return dsq; } 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 +328,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 @@ -261,12 +360,12 @@ bool Box::contains(const Vec3 &pt) const return AABox::contains(inverse(xform) * pt); } -float Box::distance(const Vec3 &v) const +float Box::distance_sq(const Vec3 &v) const { return 0.0f; // TODO } -float Box::signed_distance(const Vec3 &v) const +float Box::signed_distance_sq(const Vec3 &v) const { return 0.0f; // TODO } @@ -274,22 +373,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; } @@ -328,24 +431,49 @@ float Plane::signed_distance(const Vec3 &v) const return dot(v - pt, normal); } +float Plane::distance_sq(const Vec3 &v) const +{ + float d = distance(v); + return d * d; +} + +float Plane::signed_distance_sq(const Vec3 &v) const +{ + float d = distance(v); + return dot(v, normal) >= 0.0f ? d * d : -(d * d); +} + 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; @@ -364,12 +492,12 @@ bool Disc::contains(const Vec3 &pt) const return length_sq(pj - this->pt) <= radius * radius; } -float Disc::distance(const Vec3 &v) const +float Disc::distance_sq(const Vec3 &v) const { return 0.0; // TODO } -float Disc::signed_distance(const Vec3 &v) const +float Disc::signed_distance_sq(const Vec3 &v) const { return 0.0; // TODO } @@ -385,6 +513,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 +599,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 +683,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; @@ -621,3 +764,8 @@ bool intersect_aabox_aabox(AABox *res, const AABox &a, const AABox &b) } return res->min.x != res->max.x && res->min.y != res->max.y && res->min.z != res->max.z; } + +bool collision_sphere_aabox(const Sphere &s, const AABox &b) +{ + return b.distance_sq(s.center) <= s.radius * s.radius; +}