started implementing intersection functions and the main renderer data
[cyberay] / src / geom.c
diff --git a/src/geom.c b/src/geom.c
new file mode 100644 (file)
index 0000000..221a660
--- /dev/null
@@ -0,0 +1,94 @@
+#include <float.h>
+#include "geom.h"
+
+int ray_triangle(cgm_ray *ray, struct triangle *tri, float tmax, struct rayhit *hit)
+{
+       float t, ndotdir;
+       cgm_vec3 vdir, bc;
+
+       if(fabs(ndotdir = cgm_vdot(&ray->dir, &tri->norm)) <= 1e-6) {
+               return 0;
+       }
+
+       vdir = tri->v[0].pos;
+       cgm_vsub(&vdir, &ray->origin);
+
+       if((t = cgm_vdot(&ray->dir, &vdir) / ndotdir) <= 1e-6 || t > tmax) {
+               return 0;
+       }
+
+       if(hit) {
+               hit->t = t;
+               hit->ray = *ray;
+               hit->mtl = tri->mtl;
+
+               cgm_raypos(&hit->v.pos, ray, t);
+               cgm_bary(&bc, &tri->v[0].pos, &tri->v[1].pos, &tri->v[2].pos, &hit->v.pos);
+
+               hit->v.norm.x = tri->v[0].norm.x * bc.x + tri->v[1].norm.x * bc.y + tri->v[2].norm.x * bc.z;
+               hit->v.norm.y = tri->v[0].norm.y * bc.x + tri->v[1].norm.y * bc.y + tri->v[2].norm.y * bc.z;
+               hit->v.norm.z = tri->v[0].norm.z * bc.x + tri->v[1].norm.z * bc.y + tri->v[2].norm.z * bc.z;
+
+               hit->v.tex.x = tri->v[0].tex.x * bc.x + tri->v[1].tex.x * bc.y + tri->v[2].tex.x * bc.z;
+               hit->v.tex.y = tri->v[0].tex.y * bc.x + tri->v[1].tex.y * bc.y + tri->v[2].tex.y * bc.z;
+       }
+       return 1;
+}
+
+#define SLABCHECK(dim) \
+       do { \
+               min = box->p.dim - box->r.dim;  \
+               max = box->p.dim + box->r.dim;  \
+               invdir = 1.0f / ray->dir.dim;   \
+               t0 = (min - ray->origin.dim) * invdir;  \
+               t1 = (max - ray->origin.dim) * invdir;  \
+               if(invdir < 0.0f) {     \
+                       tmp = t0;       \
+                       t0 = t1;        \
+                       t1 = tmp;       \
+               }       \
+               tmin = t0 > tmin ? t0 : tmin;   \
+               tmax = t1 < tmax ? t1 : tmax;   \
+               if(tmax <= tmin) return 0; \
+       } while(0)
+
+int ray_aabox_any(cgm_ray *ray, struct aabox *box, float tmax)
+{
+       float invdir, t0, t1, tmp;
+       float min, max, tmin = 0.0f;
+
+       SLABCHECK(x);
+       SLABCHECK(y);
+       SLABCHECK(z);
+
+       return 1;
+}
+
+int ray_bvhnode(cgm_ray *ray, struct bvhnode *bn, float tmax, struct rayhit *hit)
+{
+       int i, res = 0;
+       struct rayhit hit0;
+
+       if(!ray_aabox_any(ray, &bn->aabb, tmax)) {
+               return 0;
+       }
+
+       if(!hit) {
+               for(i=0; i<bn->num_faces; i++) {
+                       if(ray_triangle(ray, bn->faces[i], tmax, 0)) {
+                               return 1;
+                       }
+               }
+               return 0;
+       }
+
+       hit0.t = FLT_MAX;
+       for(i=0; i<bn->num_faces; i++) {
+               if(ray_triangle(ray, bn->faces[i], tmax, hit) && hit->t < hit0.t) {
+                       hit0 = *hit;
+                       res = 1;
+               }
+       }
+       *hit = hit0;
+       return res;
+}