ee7cb7da591213709f6a0933185c3806be8fdc68
[csgray] / src / geom.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <math.h>
4 #include "geom.h"
5 #include "matrix.h"
6
7 /* TODO custom hit allocator */
8 struct hit *alloc_hit(void)
9 {
10         struct hit *hit = calloc(sizeof *hit, 1);
11         if(!hit) {
12                 perror("failed to allocate ray hit node");
13                 abort();
14         }
15         return hit;
16 }
17
18 void free_hit(struct hit *hit)
19 {
20         free(hit);
21 }
22
23 void free_hit_list(struct hit *hit)
24 {
25         while(hit) {
26                 struct hit *tmp = hit;
27                 hit = hit->next;
28                 free_hit(tmp);
29         }
30 }
31
32 struct hit *ray_intersect(struct ray *ray, csg_object *o)
33 {
34         switch(o->ob.type) {
35         case OB_SPHERE:
36                 return ray_sphere(ray, o);
37         case OB_CYLINDER:
38                 return ray_cylinder(ray, o);
39         case OB_PLANE:
40                 return ray_plane(ray, o);
41         case OB_UNION:
42                 return ray_csg_un(ray, o);
43         case OB_INTERSECTION:
44                 return ray_csg_isect(ray, o);
45         case OB_SUBTRACTION:
46                 return ray_csg_sub(ray, o);
47         default:
48                 break;
49         }
50         return 0;
51 }
52
53 struct hit *ray_sphere(struct ray *ray, csg_object *o)
54 {
55         float a, b, c, d, sqrt_d, t0, t1, t, sq_rad;
56         struct hit *hit;
57         struct ray locray = *ray;
58
59         if(o->sph.rad == 0.0f) {
60                 return 0;
61         }
62         sq_rad = o->sph.rad * o->sph.rad;
63
64         xform_ray(&locray, o->ob.inv_xform);
65
66         a = locray.dx * locray.dx + locray.dy * locray.dy + locray.dz * locray.dz;
67         b = 2.0f * (locray.dx * locray.x + locray.dy * locray.y + locray.dz * locray.z);
68         c = (locray.x * locray.x + locray.y * locray.y + locray.z * locray.z) - sq_rad;
69
70         d = b * b - 4.0f * a * c;
71         if(d < 1e-6) return 0;
72
73         sqrt_d = sqrt(d);
74         t0 = (-b + sqrt_d) / (2.0f * a);
75         t1 = (-b - sqrt_d) / (2.0f * a);
76
77         if(t0 < 1e-6) t0 = t1;
78         if(t1 < 1e-6) t1 = t0;
79         t = t0 < t1 ? t0 : t1;
80         if(t < 1e-6) return 0;
81
82         hit = alloc_hit();
83         hit->t = t;
84         hit->x = ray->x + ray->dx * t;
85         hit->y = ray->y + ray->dy * t;
86         hit->z = ray->z + ray->dz * t;
87         hit->nx = hit->x / o->sph.rad;
88         hit->ny = hit->y / o->sph.rad;
89         hit->nz = hit->z / o->sph.rad;
90         hit->o = o;
91         return hit;
92 }
93
94 struct hit *ray_cylinder(struct ray *ray, csg_object *o)
95 {
96         struct ray locray = *ray;
97
98         xform_ray(&locray, o->ob.inv_xform);
99         return 0;       /* TODO */
100 }
101
102 struct hit *ray_plane(struct ray *ray, csg_object *o)
103 {
104         float vx, vy, vz, ndotv, ndotr, t;
105         struct hit *hit = 0;
106         struct ray locray = *ray;
107
108         xform_ray(&locray, o->ob.inv_xform);
109
110         vx = o->plane.nx * o->plane.d - locray.x;
111         vy = o->plane.ny * o->plane.d - locray.y;
112         vz = o->plane.nz * o->plane.d - locray.z;
113
114         ndotv = o->plane.nx * vx + o->plane.ny * vy + o->plane.nz * vz;
115         if(fabs(ndotv) < 1e-6) return 0;
116
117         ndotr = o->plane.nx * locray.dx + o->plane.ny * locray.dy + o->plane.nz * locray.dz;
118         t = ndotr / ndotv;
119
120         if(t > 1e-6) {
121                 hit = alloc_hit();
122                 hit->t = t;
123                 hit->x = ray->x + ray->dx * t;
124                 hit->y = ray->y + ray->dy * t;
125                 hit->z = ray->z + ray->dz * t;
126                 hit->nx = o->plane.nx;
127                 hit->ny = o->plane.ny;
128                 hit->nz = o->plane.nz;
129                 hit->o = o;
130         }
131         return hit;
132 }
133
134 struct hit *ray_csg_un(struct ray *ray, csg_object *o)
135 {
136         struct hit *hita, *hitb;
137
138         hita = ray_intersect(ray, o->un.a);
139         hitb = ray_intersect(ray, o->un.a);
140
141         if(!hita) return hitb;
142         if(!hitb) return hita;
143
144         if(hita->t < hitb->t) {
145                 free_hit(hitb);
146                 return hita;
147         }
148         free_hit(hita);
149         return hitb;
150 }
151
152 struct hit *ray_csg_isect(struct ray *ray, csg_object *o)
153 {
154         return 0;
155 }
156
157 struct hit *ray_csg_sub(struct ray *ray, csg_object *o)
158 {
159         return 0;
160 }
161
162
163 void xform_ray(struct ray *ray, float *mat)
164 {
165         float m3x3[16];
166
167         mat4_copy(m3x3, mat);
168         mat4_upper3x3(m3x3);
169
170         mat4_xform3(&ray->x, mat, &ray->x);
171         mat4_xform3(&ray->dx, m3x3, &ray->dx);
172 }