fixed missing last tile, and changed bvh node to binary
[cyberay] / src / geom.c
1 #include <float.h>
2 #include "geom.h"
3
4 void free_bvh_tree(struct bvhnode *tree)
5 {
6         struct bvhnode *node, *tmp;
7
8         free(tree->faces);
9
10         free_bvh_tree(tree->left);
11         free_bvh_tree(tree->right);
12         free(tree);
13 }
14
15 int ray_triangle(cgm_ray *ray, struct triangle *tri, float tmax, struct rayhit *hit)
16 {
17         float t, ndotdir;
18         cgm_vec3 vdir, bc, pos;
19
20         if(fabs(ndotdir = cgm_vdot(&ray->dir, &tri->norm)) <= 1e-6) {
21                 return 0;
22         }
23
24         vdir = tri->v[0].pos;
25         cgm_vsub(&vdir, &ray->origin);
26
27         if((t = cgm_vdot(&tri->norm, &vdir) / ndotdir) <= 1e-6 || t > tmax) {
28                 return 0;
29         }
30
31         cgm_raypos(&pos, ray, t);
32         cgm_bary(&bc, &tri->v[0].pos, &tri->v[1].pos, &tri->v[2].pos, &pos);
33
34         if(bc.x < 0.0f || bc.x > 1.0f) return 0;
35         if(bc.y < 0.0f || bc.y > 1.0f) return 0;
36         if(bc.z < 0.0f || bc.z > 1.0f) return 0;
37
38         if(hit) {
39                 hit->t = t;
40                 hit->ray = *ray;
41                 hit->mtl = tri->mtl;
42
43                 hit->v.pos = pos;
44
45                 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;
46                 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;
47                 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;
48
49                 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;
50                 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;
51         }
52         return 1;
53 }
54
55 #define SLABCHECK(dim)  \
56         do { \
57                 invdir = 1.0f / ray->dir.dim;   \
58                 t0 = (box->vmin.dim - ray->origin.dim) * invdir;        \
59                 t1 = (box->vmax.dim - ray->origin.dim) * invdir;        \
60                 if(invdir < 0.0f) {     \
61                         tmp = t0;       \
62                         t0 = t1;        \
63                         t1 = tmp;       \
64                 }       \
65                 tmin = t0 > tmin ? t0 : tmin;   \
66                 tmax = t1 < tmax ? t1 : tmax;   \
67                 if(tmax <= tmin) return 0; \
68         } while(0)
69
70 int ray_aabox_any(cgm_ray *ray, struct aabox *box, float tmax)
71 {
72         float invdir, t0, t1, tmp;
73         float tmin = 0.0f;
74
75         SLABCHECK(x);
76         SLABCHECK(y);
77         SLABCHECK(z);
78
79         return 1;
80 }
81
82 int ray_bvhnode(cgm_ray *ray, struct bvhnode *bn, float tmax, struct rayhit *hit)
83 {
84         int i, res = 0;
85         struct rayhit hit0;
86
87         if(!ray_aabox_any(ray, &bn->aabb, tmax)) {
88                 return 0;
89         }
90
91         if(!hit) {
92                 for(i=0; i<bn->num_faces; i++) {
93                         if(ray_triangle(ray, bn->faces + i, tmax, 0)) {
94                                 return 1;
95                         }
96                 }
97                 return 0;
98         }
99
100         hit0.t = FLT_MAX;
101         for(i=0; i<bn->num_faces; i++) {
102                 if(ray_triangle(ray, bn->faces + i, tmax, hit) && hit->t < hit0.t) {
103                         hit0 = *hit;
104                         res = 1;
105                 }
106         }
107         *hit = hit0;
108         return res;
109 }