11 static struct hinterv *interval_union(struct hinterv *a, struct hinterv *b);
12 static struct hinterv *interval_isect(struct hinterv *a, struct hinterv *b);
13 static struct hinterv *interval_sub(struct hinterv *a, struct hinterv *b);
15 /* TODO custom hit allocator */
16 struct hinterv *alloc_hit(void)
18 struct hinterv *hit = calloc(sizeof *hit, 1);
20 perror("failed to allocate ray hit node");
26 struct hinterv *alloc_hits(int n)
29 struct hinterv *list = 0;
32 struct hinterv *hit = alloc_hit();
40 void free_hit(struct hinterv *hit)
45 void free_hit_list(struct hinterv *hit)
48 struct hinterv *tmp = hit;
54 struct hinterv *ray_intersect(struct ray *ray, csg_object *o)
58 return ray_sphere(ray, o);
60 return ray_cylinder(ray, o);
62 return ray_plane(ray, o);
64 return ray_box(ray, o);
66 return ray_csg_un(ray, o);
68 return ray_csg_isect(ray, o);
70 return ray_csg_sub(ray, o);
77 struct hinterv *ray_sphere(struct ray *ray, csg_object *o)
80 float a, b, c, d, sqrt_d, t[2], sq_rad, tmp;
82 struct ray locray = *ray;
84 if(o->sph.rad == 0.0f) {
87 sq_rad = o->sph.rad * o->sph.rad;
89 xform_ray(&locray, o->ob.inv_xform);
91 a = locray.dx * locray.dx + locray.dy * locray.dy + locray.dz * locray.dz;
92 b = 2.0f * (locray.dx * locray.x + locray.dy * locray.y + locray.dz * locray.z);
93 c = (locray.x * locray.x + locray.y * locray.y + locray.z * locray.z) - sq_rad;
95 d = b * b - 4.0f * a * c;
96 if(d < EPSILON) return 0;
99 t[0] = (-b + sqrt_d) / (2.0f * a);
100 t[1] = (-b - sqrt_d) / (2.0f * a);
102 if(t[0] < EPSILON && t[1] < EPSILON) {
115 float c[3] = {0, 0, 0};
118 mat4_xform3(c, o->ob.xform, c);
120 x = ray->x + ray->dx * t[i];
121 y = ray->y + ray->dy * t[i];
122 z = ray->z + ray->dz * t[i];
124 hit->end[i].t = t[i];
128 hit->end[i].nx = (x - c[0]) / o->sph.rad;
129 hit->end[i].ny = (y - c[1]) / o->sph.rad;
130 hit->end[i].nz = (z - c[2]) / o->sph.rad;
136 static int ray_cylcap(struct ray *ray, float y, float rad, float *tres)
138 float ndotr, ndotv, vy, t;
139 float ny = y > 0.0f ? 1.0f : -1.0f;
142 ndotr = ny * ray->dy;
143 if(fabs(ndotr) < EPSILON) return 0;
151 x = ray->x + ray->dx * t;
152 z = ray->z + ray->dz * t;
153 lensq = x * x + z * z;
155 if(lensq <= rad * rad) {
162 struct hinterv *ray_cylinder(struct ray *ray, csg_object *o)
164 int i, out[2] = {0}, t_is_cap[2] = {0};
165 float a, b, c, d, sqrt_d, t[2], sq_rad, tmp, y[2], hh, cap_t;
167 struct ray locray = *ray;
169 if(o->cyl.rad == 0.0f || o->cyl.height == 0.0f) {
172 sq_rad = o->cyl.rad * o->cyl.rad;
173 hh = o->cyl.height / 2.0f;
175 xform_ray(&locray, o->ob.inv_xform);
177 a = locray.dx * locray.dx + locray.dz * locray.dz;
178 b = 2.0f * (locray.dx * locray.x + locray.dz * locray.z);
179 c = locray.x * locray.x + locray.z * locray.z - sq_rad;
181 d = b * b - 4.0f * a * c;
182 if(d < EPSILON) return 0;
185 t[0] = (-b + sqrt_d) / (2.0f * a);
186 t[1] = (-b - sqrt_d) / (2.0f * a);
188 if(t[0] < EPSILON && t[1] < EPSILON) {
197 y[0] = locray.y + locray.dy * t[0];
198 y[1] = locray.y + locray.dy * t[1];
200 if(y[0] < -hh || y[0] > hh) {
203 if(y[1] < -hh || y[1] > hh) {
214 if(ray_cylcap(ray, hh, o->cyl.rad, &cap_t)) {
226 if(ray_cylcap(ray, -hh, o->cyl.rad, &cap_t)) {
239 if(out[0] && out[1]) {
246 float c[3] = {0, 0, 0};
249 x = ray->x + ray->dx * t[i];
250 y = ray->y + ray->dy * t[i];
251 z = ray->z + ray->dz * t[i];
254 hit->end[i].nx = hit->end[i].nz = 0.0f;
255 hit->end[i].ny = t_is_cap[i] > 0 ? 1.0f : -1.0f;
257 c[1] = locray.y + locray.dy * t[i];
258 mat4_xform3(c, o->ob.xform, c);
260 hit->end[i].nx = (x - c[0]) / o->cyl.rad;
261 hit->end[i].ny = (y - c[1]) / o->cyl.rad;
262 hit->end[i].nz = (z - c[2]) / o->cyl.rad;
265 hit->end[i].t = t[i];
274 struct hinterv *ray_plane(struct ray *ray, csg_object *o)
276 float vx, vy, vz, ndotv, ndotr, t;
278 struct ray locray = *ray;
280 xform_ray(&locray, o->ob.inv_xform);
282 ndotr = o->plane.nx * locray.dx + o->plane.ny * locray.dy + o->plane.nz * locray.dz;
283 if(fabs(ndotr) < EPSILON) return 0;
285 vx = o->plane.nx * o->plane.d - locray.x;
286 vy = o->plane.ny * o->plane.d - locray.y;
287 vz = o->plane.nz * o->plane.d - locray.z;
289 ndotv = o->plane.nx * vx + o->plane.ny * vy + o->plane.nz * vz;
297 hit->o = hit->end[0].o = hit->end[1].o = o;
299 hit->end[0].x = ray->x + ray->dx * t;
300 hit->end[0].y = ray->y + ray->dy * t;
301 hit->end[0].z = ray->z + ray->dz * t;
303 hit->end[0].nx = hit->end[1].nx = o->plane.nx;
304 hit->end[0].ny = hit->end[1].ny = o->plane.ny;
305 hit->end[0].nz = hit->end[1].nz = o->plane.nz;
307 hit->end[1].t = FLT_MAX;
308 hit->end[1].x = ray->x + ray->dx * 10000.0f;
309 hit->end[1].y = ray->y + ray->dy * 10000.0f;
310 hit->end[1].z = ray->z + ray->dz * 10000.0f;
314 #define BEXT(x) ((x) * 0.49999)
316 struct hinterv *ray_box(struct ray *ray, csg_object *o)
321 float tmin, tmax, tymin, tymax, tzmin, tzmax;
323 struct ray locray = *ray;
326 xform_ray(&locray, o->ob.inv_xform);
329 float sz = *(&o->box.xsz + i);
330 param[0][i] = -0.5 * sz;
331 param[1][i] = 0.5 * sz;
333 inv_dir[i] = 1.0f / *(&locray.dx + i);
334 sign[i] = inv_dir[i] < 0;
337 tmin = (param[sign[0]][0] - locray.x) * inv_dir[0];
338 tmax = (param[1 - sign[0]][0] - locray.x) * inv_dir[0];
339 tymin = (param[sign[1]][1] - locray.y) * inv_dir[1];
340 tymax = (param[1 - sign[1]][1] - locray.y) * inv_dir[1];
342 if(tmin > tymax || tymin > tmax) {
352 tzmin = (param[sign[2]][2] - locray.z) * inv_dir[2];
353 tzmax = (param[1 - sign[2]][2] - locray.z) * inv_dir[2];
355 if(tmin > tzmax || tzmin > tmax) {
365 mat4_copy(dirmat, o->ob.xform);
366 mat4_upper3x3(dirmat);
372 float t = i == 0 ? tmin : tmax;
374 float x = (locray.x + locray.dx * t) / o->box.xsz;
375 float y = (locray.y + locray.dy * t) / o->box.ysz;
376 float z = (locray.z + locray.dz * t) / o->box.zsz;
378 if(fabs(x) > fabs(y) && fabs(x) > fabs(z)) {
379 n[0] = x > 0.0f ? 1.0f : -1.0f;
380 } else if(fabs(y) > fabs(z)) {
381 n[1] = y > 0.0f ? 1.0f : -1.0f;
383 n[2] = z > 0.0f ? 1.0f : -1.0f;
388 hit->end[i].x = ray->x + ray->dx * t;
389 hit->end[i].y = ray->y + ray->dy * t;
390 hit->end[i].z = ray->z + ray->dz * t;
391 mat4_xform3(&hit->end[i].nx, dirmat, n);
396 struct hinterv *ray_csg_un(struct ray *ray, csg_object *o)
398 struct hinterv *hita, *hitb, *res;
400 hita = ray_intersect(ray, o->un.a);
401 hitb = ray_intersect(ray, o->un.b);
403 if(!hita) return hitb;
404 if(!hitb) return hita;
406 res = interval_union(hita, hitb);
412 struct hinterv *ray_csg_isect(struct ray *ray, csg_object *o)
414 struct hinterv *hita, *hitb, *res;
416 hita = ray_intersect(ray, o->isect.a);
417 hitb = ray_intersect(ray, o->isect.b);
425 res = interval_isect(hita, hitb);
431 struct hinterv *ray_csg_sub(struct ray *ray, csg_object *o)
433 struct hinterv *hita, *hitb, *res;
435 hita = ray_intersect(ray, o->un.a);
436 hitb = ray_intersect(ray, o->un.b);
439 if(!hitb) return hita;
441 res = interval_sub(hita, hitb);
448 void xform_ray(struct ray *ray, float *mat)
452 mat4_copy(m3x3, mat);
455 mat4_xform3(&ray->x, mat, &ray->x);
456 mat4_xform3(&ray->dx, m3x3, &ray->dx);
459 static void flip_hit(struct hit *hit)
466 static struct hinterv *interval_union(struct hinterv *a, struct hinterv *b)
468 struct hinterv *res, *res2;
470 if(a->end[0].t > b->end[1].t || a->end[1].t < b->end[0].t) {
475 if(a->end[0].t < b->end[0].t) {
488 res->end[0] = a->end[0].t <= b->end[0].t ? a->end[0] : b->end[0];
489 res->end[1] = a->end[1].t >= b->end[1].t ? a->end[1] : b->end[1];
493 static struct hinterv *interval_isect(struct hinterv *a, struct hinterv *b)
497 if(a->end[0].t > b->end[1].t || a->end[1].t < b->end[0].t) {
504 if(a->end[0].t <= b->end[0].t && a->end[1].t >= b->end[1].t) {
510 if(a->end[0].t > b->end[0].t && a->end[1].t < b->end[1].t) {
517 /* partial overlap */
518 if(a->end[0].t < b->end[0].t) {
519 res->end[0] = b->end[0];
520 res->end[1] = a->end[1];
522 res->end[0] = a->end[0];
523 res->end[1] = b->end[1];
528 static struct hinterv *interval_sub(struct hinterv *a, struct hinterv *b)
532 if(a->end[0].t >= b->end[0].t && a->end[1].t <= b->end[1].t) {
537 if(a->end[0].t < b->end[0].t && a->end[1].t > b->end[1].t) {
540 res->end[0] = a->end[0];
541 res->end[1] = b->end[0];
542 res->next->end[0] = b->end[1];
543 res->next->end[1] = a->end[1];
549 if(a->end[0].t > b->end[1].t || a->end[1].t < b->end[0].t) {
556 /* partial overlap */
557 if(a->end[0].t <= b->end[0].t) {
558 res->end[0] = a->end[0];
559 res->end[1] = b->end[0];
561 res->end[0] = b->end[1];
562 res->end[1] = a->end[1];
565 flip_hit(res->end + 0);
566 flip_hit(res->end + 1);