+
+ a = locray.dx * locray.dx + locray.dz * locray.dz;
+ b = 2.0f * (locray.dx * locray.x + locray.dz * locray.z);
+ c = locray.x * locray.x + locray.z * locray.z - sq_rad;
+
+ d = b * b - 4.0f * a * c;
+ if(d < EPSILON) return 0;
+
+ sqrt_d = sqrt(d);
+ t[0] = (-b + sqrt_d) / (2.0f * a);
+ t[1] = (-b - sqrt_d) / (2.0f * a);
+
+ if(t[0] < EPSILON && t[1] < EPSILON) {
+ return 0;
+ }
+ if(t[1] < t[0]) {
+ tmp = t[0];
+ t[0] = t[1];
+ t[1] = tmp;
+ }
+
+ y[0] = locray.y + locray.dy * t[0];
+ y[1] = locray.y + locray.dy * t[1];
+
+ if(y[0] < -hh || y[0] > hh) {
+ out[0] = 1;
+ }
+ if(y[1] < -hh || y[1] > hh) {
+ out[1] = 1;
+ }
+
+ if(out[0]) {
+ t[0] = t[1];
+ }
+ if(out[1]) {
+ t[1] = t[0];
+ }
+
+ if(ray_cylcap(ray, hh, o->cyl.rad, &cap_t)) {
+ if(cap_t < t[0]) {
+ t[0] = cap_t;
+ t_is_cap[0] = 1;
+ out[0] = 0;
+ }
+ if(cap_t > t[1]) {
+ t[1] = cap_t;
+ t_is_cap[1] = 1;
+ out[1] = 0;
+ }
+ }
+ if(ray_cylcap(ray, -hh, o->cyl.rad, &cap_t)) {
+ if(cap_t < t[0]) {
+ t[0] = cap_t;
+ t_is_cap[0] = -1;
+ out[0] = 0;
+ }
+ if(cap_t > t[1]) {
+ t[1] = cap_t;
+ t_is_cap[1] = -1;
+ out[1] = 0;
+ }
+ }
+
+ if(out[0] && out[1]) {
+ return 0;
+ }
+
+ hit = alloc_hits(1);
+ hit->o = o;
+ for(i=0; i<2; i++) {
+ float c[3] = {0, 0, 0};
+ float x, y, z;
+
+ x = ray->x + ray->dx * t[i];
+ y = ray->y + ray->dy * t[i];
+ z = ray->z + ray->dz * t[i];
+
+ if(t_is_cap[i]) {
+ hit->end[i].nx = hit->end[i].nz = 0.0f;
+ hit->end[i].ny = t_is_cap[i] > 0 ? 1.0f : -1.0f;
+ } else {
+ c[1] = locray.y + locray.dy * t[i];
+ mat4_xform3(c, o->ob.xform, c);
+
+ hit->end[i].nx = (x - c[0]) / o->cyl.rad;
+ hit->end[i].ny = (y - c[1]) / o->cyl.rad;
+ hit->end[i].nz = (z - c[2]) / o->cyl.rad;
+ }
+
+ hit->end[i].t = t[i];
+ hit->end[i].x = x;
+ hit->end[i].y = y;
+ hit->end[i].z = z;
+ hit->end[i].o = o;
+ }
+ return hit;