// File: /workspace/github_cpp_makefile_star2_O2/tomfunkhouser[P]gaps/pkgs/R3Shapes/R3Isect.cpp
// Function: gaps::R3Intersects(gaps::R3Ray const&, gaps::R3Cylinder const&, gaps::R3Point*, gaps::R3Vector*, double*)
RNClassID R3Intersects(const R3Ray& ray, const R3Cylinder& cylinder, 
    R3Point *hit_point1, R3Vector *hit_normal1, RNScalar *hit_t1)
{
    // Check if sphere contains ray start point
    RNBoolean start_inside = R3Contains(cylinder, ray.Start());
    if (start_inside) {
      if (hit_point1) *hit_point1 = ray.Start();
      if (hit_normal1) *hit_normal1 = -ray.Vector();
      if (hit_t1) *hit_t1 = 0;
      return R3_SPAN_CLASS_ID;
    }

    // See Graphics Gems IV, page 356
    // Compute parametric values of intersection with infinite cylinder
    RNScalar cyl_t1, cyl_t2;
    R3Vector R = ray.Vector();
    R3Vector A = cylinder.Axis().Vector();
    R3Vector D = R % A;
    RNScalar a = D.Length();
    if (RNIsZero(a)) {
	// Ray and axis are parallel
	RNScalar d = R3Distance(ray.Start(), cylinder.Axis().Line());
	if (RNIsLessOrEqual(d, cylinder.Radius())) {
	    // Ray lies entirely inside infinite cylinder
	    cyl_t1 = 0.0;
	    cyl_t2 = RN_INFINITY;
	}
	else {
	    // Ray lies entirely outside infinite cylinder
	    return RN_NULL_CLASS_ID;
	}
    }
    else {
	// Ray and axis are not parallel
	// Compute distance from axis to closest point on ray's line
	D /= a;
	R3Vector RC = ray.Start() - cylinder.Axis().Start();
	RNScalar d = RC.Dot(D);
	if (d < 0.0) d = -d;
	if (RNIsGreater(d, cylinder.Radius())) {
	    // Ray does not intersect infinite cylinder
	    return RN_NULL_CLASS_ID;
	}
	else {
	    // Find parametric value (cyl_t) of point on ray closest to axis
	    assert(RNIsNotZero(a));
	    RNScalar t = (RC % A).Dot(D) / -a;
	    
	    // Find parametric value delta (s) to intersection points
	    RNScalar s;
	    R3Vector O = D % A;
	    O.Normalize();
	    RNScalar b = cylinder.Radius() * cylinder.Radius() - d*d;
	    if (RNIsPositive(b)) {
		// Crossing span intersection
		RNScalar e = R.Dot(O);
		assert(RNIsNotZero(e));
		s = sqrt(b) / e;
		if (s < 0.0) s = -s;
	    }
	    else {
		// Grazing point intersection
		s = 0.0;
	    }
	    
	    // Find parametric value (cyl_t2) of second intersection
	    cyl_t2 = t + s;
	    if (RNIsNegative(cyl_t2)) {
		// Intersection point is behind ray
		return RN_NULL_CLASS_ID;
	    }
	    else {
		// Find parametric value (cyl_t1) of first intersection
		cyl_t1 = t - s;
		
		// Check if ray start is in infinite cylinder
		if (cyl_t1 < 0.0) cyl_t1 = 0.0;
	    }
	}
    }
	
    // Compute parametric values of intersection with caps
    RNScalar cap_t1 = 0, cap_t2 = 0;
    RNScalar dot = ray.Vector().Dot(cylinder.Axis().Vector());
    RNScalar d_top = R3SignedDistance(cylinder.Top().Plane(), ray.Start());
    RNScalar d_base = R3SignedDistance(cylinder.Base().Plane(), ray.Start());
    if (RNIsPositive(d_top)) {
	// Ray starts above top cap
	if (RNIsPositiveOrZero(dot)) {
	    // Ray points upward or orthogonally from above cylinder top
	    return RN_NULL_CLASS_ID;
	}
	else {
	    // Ray points downward from above cylinder top
	    if ((R3Intersects(ray, cylinder.Top().Plane(), NULL, &cap_t1)) &&
		(RNIsGreater(cap_t1, cyl_t2))) {
		// Ray misses cylinder
		return RN_NULL_CLASS_ID;
	    }
	    else if ((R3Intersects(ray, -(cylinder.Base().Plane()), NULL, &cap_t2)) &&
		     (RNIsLess(cap_t2, cyl_t1))) {
		// Ray misses cylinder
		return RN_NULL_CLASS_ID;
	    }
	    else if (RNIsGreater(cap_t1, cyl_t1)) {
		// Ray hits top cap 
		assert(cap_t1 >= 0.0);
		if (hit_t1) *hit_t1 = cap_t1;
		if (hit_point1) *hit_point1 = ray.Point(cap_t1);
		if (hit_normal1) *hit_normal1 = cylinder.Top().Normal();
		return R3_POINT_CLASS_ID;
	    }
	    else {
		// Ray hits side of cylinder
	    }
	}
    }
    else if (RNIsPositive(d_base)) {
	// Ray starts below base cap
	if (RNIsNegativeOrZero(dot)) {
	    // Ray points downward or orthogonally
	    return RN_NULL_CLASS_ID;
	}
	else {
	    // Ray points upward from below cylinder base
	    if ((R3Intersects(ray, cylinder.Base().Plane(), NULL, &cap_t1)) &&
		(RNIsGreater(cap_t1, cyl_t2))) {
		// Ray misses cylinder
		return RN_NULL_CLASS_ID;
	    }
	    else if ((R3Intersects(ray, -(cylinder.Top().Plane()), NULL, &cap_t2)) &&
		     (RNIsLess(cap_t2, cyl_t1))) {
		// Ray misses cylinder
		return RN_NULL_CLASS_ID;
	    }
	    else if (RNIsGreater(cap_t1, cyl_t1)) {
		// Ray hits base cap 
		assert(cap_t1 >= 0.0);
		if (hit_t1) *hit_t1 = cap_t1;
		if (hit_point1) *hit_point1 = ray.Point(cap_t1);
		if (hit_normal1) *hit_normal1 = cylinder.Base().Normal();
		return R3_POINT_CLASS_ID;
	    }
	    else {
		// Ray hits side of cylinder
	    }
	}
    }
    else {
	// Ray starts on or between caps
	if (RNIsPositive(dot)) {
	    if (R3Intersects(ray, -(cylinder.Top().Plane()), NULL, &cap_t1)) {
		if (RNIsLess(cap_t1, cyl_t1)) {
		    // Intersection with infinite cylinder is beyond cap
		    return RN_NULL_CLASS_ID;
		}
	    }
	}
	else if (RNIsNegative(dot)) {
	    if (R3Intersects(ray, -(cylinder.Base().Plane()), NULL, &cap_t1)) {
		if (RNIsLess(cap_t1, cyl_t1)) {
		    // Intersection with infinite cylinder is beyond cap
		    return RN_NULL_CLASS_ID;
		}
	    }
	}
    }

    // Ray hit side of cylinder
    assert(cyl_t1 >= 0.0);
    if (hit_t1) *hit_t1 = cyl_t1;
    if (hit_point1) *hit_point1 = ray.Point(cyl_t1);
    if (hit_normal1) {
	R3Point p, *H;
	if (hit_point1) H = hit_point1;
	else { p = ray.Point(cyl_t1); H = &p; }
        R3Vector HB = *H - cylinder.Axis().Start();
	*hit_normal1 = (HB - HB.Dot(A) * A) / cylinder.Radius();
    }
    return R3_POINT_CLASS_ID;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x138, %rsp            # imm = 0x138
movq %r8, %r13
movq %rcx, %r15
movq %rdx, %rbx
movq %rsi, %r12
movq %rdi, %r14
movq %rsi, %rdi
movq %r14, %rsi
callq 0x42df6
testl %eax, %eax
je 0x3e969
testq %rbx, %rbx
je 0x3e92f
movq %rbx, %rdi
movq %r14, %rsi
callq 0x37e36
testq %r15, %r15
je 0x3e953
addq $0x18, %r14
leaq 0x60(%rsp), %rbx
movq %rbx, %rdi
movq %r14, %rsi
callq 0x38c72
movq %r15, %rdi
movq %rbx, %rsi
callq 0x3887c
pushq $0x4
popq %rbp
testq %r13, %r13
je 0x3edd7
andq $0x0, (%r13)
jmp 0x3edd7
movq %r13, 0x28(%rsp)
movq %rbx, 0x30(%rsp)
movq %r15, 0x38(%rsp)
leaq 0x18(%r14), %rsi
leaq 0xd8(%rsp), %rbp
movq %rbp, %rdi
movq %rsi, 0x40(%rsp)
callq 0x3831c
leaq 0x8(%r12), %rax
movq %rax, 0x58(%rsp)
leaq 0x20(%r12), %r15
leaq 0xc0(%rsp), %r13
movq %r13, %rdi
movq %r15, %rsi
callq 0x3831c
leaq 0xa8(%rsp), %rbx
movq %rbx, %rdi
movq %rbp, %rsi
movq %r13, %rdx
callq 0x389be
movq %rbx, %rdi
callq 0x38412
leaq 0x9c1d0(%rip), %rbp     # 0xdaba8
movsd (%rbp), %xmm2
movapd 0x5464b(%rip), %xmm1    # 0x93030
xorpd %xmm2, %xmm1
ucomisd %xmm1, %xmm0
jb 0x3ea45
ucomisd %xmm0, %xmm2
jb 0x3ea45
movq %r14, %rdi
movq 0x58(%rsp), %rsi
callq 0x43240
subsd 0x78(%r12), %xmm0
movq %rbp, %rcx
movsd (%rbp), %xmm1
xorl %ebp, %ebp
ucomisd %xmm0, %xmm1
jb 0x3edd7
leaq 0x9c194(%rip), %rax     # 0xdabb8
movsd (%rax), %xmm0
movsd %xmm0, 0x50(%rsp)
xorpd %xmm0, %xmm0
movsd %xmm0, 0x10(%rsp)
movq 0x28(%rsp), %r13
movq %rcx, %rbp
jmp 0x3ebeb
leaq 0xa8(%rsp), %rbx
movq %rbx, %rdi
movapd %xmm0, 0x80(%rsp)
callq 0x38c0a
leaq 0x60(%rsp), %r13
movq %r13, %rdi
movq %r14, %rsi
movq 0x58(%rsp), %rdx
callq 0x37d29
movq %r13, %rdi
movq %rbx, %rsi
callq 0x38586
movapd 0x545aa(%rip), %xmm1    # 0x93030
xorpd %xmm0, %xmm1
maxsd %xmm0, %xmm1
movapd %xmm1, %xmm0
subsd 0x78(%r12), %xmm0
ucomisd (%rbp), %xmm0
ja 0x3edd5
leaq 0x90(%rsp), %rbx
leaq 0x60(%rsp), %rsi
leaq 0xc0(%rsp), %r13
movq %rbx, %rdi
movq %r13, %rdx
movapd %xmm1, 0x10(%rsp)
callq 0x389be
leaq 0xa8(%rsp), %rbp
movq %rbx, %rdi
movq %rbp, %rsi
callq 0x38586
movapd 0x80(%rsp), %xmm1
xorpd 0x54542(%rip), %xmm1    # 0x93030
divsd %xmm1, %xmm0
movsd %xmm0, 0x80(%rsp)
leaq 0x90(%rsp), %rbx
movq %rbx, %rdi
movq %rbp, %rsi
leaq 0x9c098(%rip), %rbp     # 0xdaba8
movq %r13, %rdx
callq 0x389be
movq %rbx, %rdi
callq 0x3860e
movsd 0x78(%r12), %xmm2
movapd 0x10(%rsp), %xmm0
mulsd %xmm0, %xmm0
mulsd %xmm2, %xmm2
subsd %xmm0, %xmm2
movsd (%rbp), %xmm0
xorpd %xmm1, %xmm1
ucomisd %xmm0, %xmm2
movq 0x28(%rsp), %r13
jbe 0x3ebb0
leaq 0xd8(%rsp), %rdi
leaq 0x90(%rsp), %rsi
movsd %xmm2, 0x10(%rsp)
callq 0x38586
movsd 0x10(%rsp), %xmm1
movapd %xmm0, %xmm2
xorpd %xmm0, %xmm0
ucomisd %xmm0, %xmm1
jb 0x3eb82
sqrtsd %xmm1, %xmm0
jmp 0x3eb97
movapd %xmm1, %xmm0
movsd %xmm2, 0x10(%rsp)
callq 0xe350
movsd 0x10(%rsp), %xmm2
divsd %xmm2, %xmm0
movapd 0x5448d(%rip), %xmm1    # 0x93030
xorpd %xmm0, %xmm1
maxsd %xmm0, %xmm1
movsd (%rbp), %xmm0
movsd 0x80(%rsp), %xmm3
movapd %xmm3, %xmm2
addsd %xmm1, %xmm2
xorpd 0x54467(%rip), %xmm0    # 0x93030
ucomisd %xmm2, %xmm0
ja 0x3edd5
movsd %xmm2, 0x50(%rsp)
subsd %xmm1, %xmm3
xorpd %xmm0, %xmm0
maxsd %xmm3, %xmm0
movsd %xmm0, 0x10(%rsp)
andq $0x0, 0x8(%rsp)
andq $0x0, 0x48(%rsp)
movq 0x40(%rsp), %rdi
movq %r15, %rsi
callq 0x38586
movsd %xmm0, 0x40(%rsp)
leaq 0xc8(%r12), %rbx
movq %rbx, %rdi
movq %r14, %rsi
callq 0x43420
movsd %xmm0, 0x80(%rsp)
leaq 0x80(%r12), %r15
movq %r15, %rdi
movq %r14, %rsi
callq 0x43420
movsd (%rbp), %xmm1
movsd 0x80(%rsp), %xmm2
ucomisd %xmm1, %xmm2
ja 0x3ec9b
movsd 0x40(%rsp), %xmm2
ucomisd %xmm1, %xmm0
ja 0x3ed43
ucomisd %xmm1, %xmm2
ja 0x3edeb
xorpd 0x543c1(%rip), %xmm1    # 0x93030
ucomisd %xmm2, %xmm1
jbe 0x3eecd
leaq 0x60(%rsp), %rbx
movq %rbx, %rdi
movq %r15, %rsi
callq 0x21c84
xorl %ebp, %ebp
leaq 0x8(%rsp), %rcx
movq %r14, %rdi
movq %rbx, %rsi
jmp 0x3ee08
xorpd 0x5438d(%rip), %xmm1    # 0x93030
movsd 0x40(%rsp), %xmm0
ucomisd %xmm1, %xmm0
jae 0x3edd5
movq %rbp, %r13
xorl %ebp, %ebp
leaq 0x8(%rsp), %rcx
movq %r14, %rdi
movq %rbx, %rsi
xorl %edx, %edx
callq 0x3dc32
testl %eax, %eax
je 0x3ece6
movsd 0x8(%rsp), %xmm0
subsd 0x50(%rsp), %xmm0
ucomisd (%r13), %xmm0
ja 0x3edd7
leaq 0x60(%rsp), %rdi
movq %r15, %rsi
callq 0x21c84
xorl %ebp, %ebp
leaq 0x48(%rsp), %rcx
movq %r14, %rdi
leaq 0x60(%rsp), %rsi
xorl %edx, %edx
callq 0x3dc32
testl %eax, %eax
je 0x3ee41
movsd 0x48(%rsp), %xmm0
movsd (%r13), %xmm1
subsd 0x10(%rsp), %xmm0
movapd 0x54305(%rip), %xmm2    # 0x93030
xorpd %xmm1, %xmm2
ucomisd %xmm0, %xmm2
movq 0x28(%rsp), %r13
ja 0x3edd7
jmp 0x3ee4c
ucomisd %xmm2, %xmm1
jae 0x3edd5
movq %rbp, %r13
xorl %ebp, %ebp
leaq 0x8(%rsp), %rcx
movq %r14, %rdi
movq %r15, %rsi
xorl %edx, %edx
callq 0x3dc32
testl %eax, %eax
je 0x3ed7c
movsd 0x8(%rsp), %xmm0
subsd 0x50(%rsp), %xmm0
ucomisd (%r13), %xmm0
ja 0x3edd7
leaq 0x60(%rsp), %rdi
movq %rbx, %rsi
callq 0x21c84
xorl %ebp, %ebp
leaq 0x48(%rsp), %rcx
movq %r14, %rdi
leaq 0x60(%rsp), %rsi
xorl %edx, %edx
callq 0x3dc32
testl %eax, %eax
je 0x3eea8
movsd 0x48(%rsp), %xmm0
movsd (%r13), %xmm1
subsd 0x10(%rsp), %xmm0
movapd 0x5426f(%rip), %xmm2    # 0x93030
xorpd %xmm1, %xmm2
ucomisd %xmm0, %xmm2
movq 0x28(%rsp), %r13
ja 0x3edd7
jmp 0x3eeb3
xorl %ebp, %ebp
movl %ebp, %eax
addq $0x138, %rsp            # imm = 0x138
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x60(%rsp), %r15
movq %r15, %rdi
movq %rbx, %rsi
callq 0x21c84
xorl %ebp, %ebp
leaq 0x8(%rsp), %rcx
movq %r14, %rdi
movq %r15, %rsi
xorl %edx, %edx
callq 0x3dc32
testl %eax, %eax
je 0x3eecd
movsd 0x8(%rsp), %xmm0
subsd 0x10(%rsp), %xmm0
leaq 0x9bd7e(%rip), %rax     # 0xdaba8
movsd (%rax), %xmm1
xorpd 0x541fa(%rip), %xmm1    # 0x93030
ucomisd %xmm0, %xmm1
ja 0x3edd7
jmp 0x3eecd
movsd (%r13), %xmm1
movq 0x28(%rsp), %r13
movsd 0x8(%rsp), %xmm0
movapd %xmm0, %xmm2
subsd 0x10(%rsp), %xmm2
ucomisd %xmm1, %xmm2
jbe 0x3eecd
testq %r13, %r13
je 0x3ee6d
movsd %xmm0, (%r13)
movq 0x30(%rsp), %r12
testq %r12, %r12
je 0x3ee92
leaq 0x60(%rsp), %r15
movq %r15, %rdi
movq %r14, %rsi
callq 0x37770
movq %r12, %rdi
movq %r15, %rsi
callq 0x37e36
pushq $0x1
popq %rbp
movq 0x38(%rsp), %rdi
testq %rdi, %rdi
jne 0x3efc8
jmp 0x3edd7
movsd (%r13), %xmm1
movq 0x28(%rsp), %r13
movsd 0x8(%rsp), %xmm0
movapd %xmm0, %xmm2
subsd 0x10(%rsp), %xmm2
ucomisd %xmm1, %xmm2
ja 0x3efd5
testq %r13, %r13
je 0x3eede
movsd 0x10(%rsp), %xmm0
movsd %xmm0, (%r13)
movq 0x30(%rsp), %r13
testq %r13, %r13
movq 0x38(%rsp), %r15
je 0x3ef0e
leaq 0x60(%rsp), %rbx
movq %rbx, %rdi
movq %r14, %rsi
movsd 0x10(%rsp), %xmm0
callq 0x37770
movq %r13, %rdi
movq %rbx, %rsi
callq 0x37e36
pushq $0x1
popq %rbp
testq %r15, %r15
je 0x3edd7
leaq 0x60(%rsp), %rbx
movq %rbx, %rdi
callq 0x37b4a
movq 0x30(%rsp), %rsi
testq %rsi, %rsi
jne 0x3ef58
leaq 0x90(%rsp), %r15
movq %r15, %rdi
movq %r14, %rsi
movsd 0x10(%rsp), %xmm0
callq 0x37770
movq %rbx, %rdi
movq %r15, %rsi
callq 0x37e36
movq %rbx, %rsi
leaq 0x90(%rsp), %rbx
movq %rbx, %rdi
movq 0x58(%rsp), %rdx
callq 0x37d29
leaq 0xc0(%rsp), %r14
movq %rbx, %rdi
movq %r14, %rsi
callq 0x38586
leaq 0xf0(%rsp), %r15
movq %r15, %rdi
movq %r14, %rsi
callq 0x38a02
leaq 0x108(%rsp), %r14
movq %r14, %rdi
movq %rbx, %rsi
movq %r15, %rdx
callq 0x38cb5
movsd 0x78(%r12), %xmm0
leaq 0x120(%rsp), %rbx
movq %rbx, %rdi
movq %r14, %rsi
callq 0x38d1e
movq 0x38(%rsp), %rdi
movq %rbx, %rsi
callq 0x3887c
jmp 0x3edd7
testq %r13, %r13
je 0x3efe0
movsd %xmm0, (%r13)
movq 0x30(%rsp), %r12
testq %r12, %r12
je 0x3f005
leaq 0x60(%rsp), %rbx
movq %rbx, %rdi
movq %r14, %rsi
callq 0x37770
movq %r12, %rdi
movq %rbx, %rsi
callq 0x37e36
pushq $0x1
popq %rbp
movq 0x38(%rsp), %rdi
testq %rdi, %rdi
je 0x3edd7
movq %r15, %rsi
jmp 0x3efcb