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