X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=csgray;a=blobdiff_plain;f=src%2Fgeom.c;fp=src%2Fgeom.c;h=ee7cb7da591213709f6a0933185c3806be8fdc68;hp=0000000000000000000000000000000000000000;hb=07ca36e28aa10804ba5a544276eb5a25f8105e0f;hpb=40a4c5772ab19e7f27c62768d40f697bf5d80a12 diff --git a/src/geom.c b/src/geom.c new file mode 100644 index 0000000..ee7cb7d --- /dev/null +++ b/src/geom.c @@ -0,0 +1,172 @@ +#include +#include +#include +#include "geom.h" +#include "matrix.h" + +/* TODO custom hit allocator */ +struct hit *alloc_hit(void) +{ + struct hit *hit = calloc(sizeof *hit, 1); + if(!hit) { + perror("failed to allocate ray hit node"); + abort(); + } + return hit; +} + +void free_hit(struct hit *hit) +{ + free(hit); +} + +void free_hit_list(struct hit *hit) +{ + while(hit) { + struct hit *tmp = hit; + hit = hit->next; + free_hit(tmp); + } +} + +struct hit *ray_intersect(struct ray *ray, csg_object *o) +{ + switch(o->ob.type) { + case OB_SPHERE: + return ray_sphere(ray, o); + case OB_CYLINDER: + return ray_cylinder(ray, o); + case OB_PLANE: + return ray_plane(ray, o); + case OB_UNION: + return ray_csg_un(ray, o); + case OB_INTERSECTION: + return ray_csg_isect(ray, o); + case OB_SUBTRACTION: + return ray_csg_sub(ray, o); + default: + break; + } + return 0; +} + +struct hit *ray_sphere(struct ray *ray, csg_object *o) +{ + float a, b, c, d, sqrt_d, t0, t1, t, sq_rad; + struct hit *hit; + struct ray locray = *ray; + + if(o->sph.rad == 0.0f) { + return 0; + } + sq_rad = o->sph.rad * o->sph.rad; + + xform_ray(&locray, o->ob.inv_xform); + + a = locray.dx * locray.dx + locray.dy * locray.dy + locray.dz * locray.dz; + b = 2.0f * (locray.dx * locray.x + locray.dy * locray.y + locray.dz * locray.z); + c = (locray.x * locray.x + locray.y * locray.y + locray.z * locray.z) - sq_rad; + + d = b * b - 4.0f * a * c; + if(d < 1e-6) return 0; + + sqrt_d = sqrt(d); + t0 = (-b + sqrt_d) / (2.0f * a); + t1 = (-b - sqrt_d) / (2.0f * a); + + if(t0 < 1e-6) t0 = t1; + if(t1 < 1e-6) t1 = t0; + t = t0 < t1 ? t0 : t1; + if(t < 1e-6) return 0; + + hit = alloc_hit(); + hit->t = t; + hit->x = ray->x + ray->dx * t; + hit->y = ray->y + ray->dy * t; + hit->z = ray->z + ray->dz * t; + hit->nx = hit->x / o->sph.rad; + hit->ny = hit->y / o->sph.rad; + hit->nz = hit->z / o->sph.rad; + hit->o = o; + return hit; +} + +struct hit *ray_cylinder(struct ray *ray, csg_object *o) +{ + struct ray locray = *ray; + + xform_ray(&locray, o->ob.inv_xform); + return 0; /* TODO */ +} + +struct hit *ray_plane(struct ray *ray, csg_object *o) +{ + float vx, vy, vz, ndotv, ndotr, t; + struct hit *hit = 0; + struct ray locray = *ray; + + xform_ray(&locray, o->ob.inv_xform); + + vx = o->plane.nx * o->plane.d - locray.x; + vy = o->plane.ny * o->plane.d - locray.y; + vz = o->plane.nz * o->plane.d - locray.z; + + ndotv = o->plane.nx * vx + o->plane.ny * vy + o->plane.nz * vz; + if(fabs(ndotv) < 1e-6) return 0; + + ndotr = o->plane.nx * locray.dx + o->plane.ny * locray.dy + o->plane.nz * locray.dz; + t = ndotr / ndotv; + + if(t > 1e-6) { + hit = alloc_hit(); + hit->t = t; + hit->x = ray->x + ray->dx * t; + hit->y = ray->y + ray->dy * t; + hit->z = ray->z + ray->dz * t; + hit->nx = o->plane.nx; + hit->ny = o->plane.ny; + hit->nz = o->plane.nz; + hit->o = o; + } + return hit; +} + +struct hit *ray_csg_un(struct ray *ray, csg_object *o) +{ + struct hit *hita, *hitb; + + hita = ray_intersect(ray, o->un.a); + hitb = ray_intersect(ray, o->un.a); + + if(!hita) return hitb; + if(!hitb) return hita; + + if(hita->t < hitb->t) { + free_hit(hitb); + return hita; + } + free_hit(hita); + return hitb; +} + +struct hit *ray_csg_isect(struct ray *ray, csg_object *o) +{ + return 0; +} + +struct hit *ray_csg_sub(struct ray *ray, csg_object *o) +{ + return 0; +} + + +void xform_ray(struct ray *ray, float *mat) +{ + float m3x3[16]; + + mat4_copy(m3x3, mat); + mat4_upper3x3(m3x3); + + mat4_xform3(&ray->x, mat, &ray->x); + mat4_xform3(&ray->dx, m3x3, &ray->dx); +}