// File: /workspace/github_cpp_makefile_star2_O3/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, %r14
movq %rdx, %rbx
movq %rsi, %r15
movq %rdi, %r12
movq %rsi, %rdi
movq %r12, %rsi
callq 0x48f86
testl %eax, %eax
je 0x43de4
testq %rbx, %rbx
je 0x43da5
movq %rbx, %rdi
movq %r12, %rsi
callq 0x3c89a
testq %r14, %r14
je 0x43dc9
addq $0x18, %r12
leaq 0x70(%rsp), %rbx
movq %rbx, %rdi
movq %r12, %rsi
callq 0x3dc00
movq %r14, %rdi
movq %rbx, %rsi
callq 0x3d752
movl $0x4, %ebp
testq %r13, %r13
je 0x44480
movq $0x0, (%r13)
jmp 0x44480
movq %r13, 0x28(%rsp)
movq %rbx, 0x48(%rsp)
movq %r14, 0x50(%rsp)
leaq 0x18(%r12), %rsi
leaq 0xd8(%rsp), %rbp
movq %rbp, %rdi
movq %rsi, 0x30(%rsp)
callq 0x3cfd6
leaq 0x8(%r15), %rax
movq %rax, 0x58(%rsp)
leaq 0x20(%r15), %r14
leaq 0xc0(%rsp), %r13
movq %r13, %rdi
movq %r14, %rsi
callq 0x3cfd6
leaq 0xa8(%rsp), %rbx
movq %rbx, %rdi
movq %rbp, %rsi
movq %r13, %rdx
callq 0x3d8fa
movq %rbx, %rdi
callq 0x3d0cc
leaq 0xa1d46(%rip), %rbp     # 0xe5b98
movsd (%rbp), %xmm2
movapd 0x5e1c1(%rip), %xmm1    # 0xa2020
xorpd %xmm2, %xmm1
ucomisd %xmm1, %xmm0
jb 0x43eb8
ucomisd %xmm0, %xmm2
jb 0x43eb8
movq %r12, %rdi
movq 0x58(%rsp), %rsi
callq 0x4942a
subsd 0x78(%r15), %xmm0
movsd (%rbp), %xmm1
xorl %ebp, %ebp
ucomisd %xmm0, %xmm1
jb 0x44480
leaq 0xa1d0e(%rip), %rax     # 0xe5ba8
movsd (%rax), %xmm0
movsd %xmm0, 0x40(%rsp)
xorpd %xmm0, %xmm0
movsd %xmm0, 0x10(%rsp)
movq 0x28(%rsp), %r13
jmp 0x44053
leaq 0xa8(%rsp), %rbx
movq %rbx, %rdi
movapd %xmm0, 0x60(%rsp)
callq 0x3db98
leaq 0x70(%rsp), %r13
movq %r13, %rdi
movq %r12, %rsi
movq 0x58(%rsp), %rdx
callq 0x3c78e
movq %r13, %rdi
movq %rbx, %rsi
callq 0x3d252
movapd 0x5e12a(%rip), %xmm1    # 0xa2020
xorpd %xmm0, %xmm1
maxsd %xmm0, %xmm1
movapd %xmm1, %xmm0
subsd 0x78(%r15), %xmm0
ucomisd (%rbp), %xmm0
ja 0x44101
leaq 0x90(%rsp), %rbx
leaq 0x70(%rsp), %rsi
leaq 0xc0(%rsp), %r13
movq %rbx, %rdi
movq %r13, %rdx
movapd %xmm1, 0x10(%rsp)
callq 0x3d8fa
leaq 0xa8(%rsp), %rbp
movq %rbx, %rdi
movq %rbp, %rsi
callq 0x3d252
movapd 0x60(%rsp), %xmm1
xorpd 0x5e0c6(%rip), %xmm1    # 0xa2020
divsd %xmm1, %xmm0
movsd %xmm0, 0x60(%rsp)
leaq 0x90(%rsp), %rbx
movq %rbx, %rdi
movq %rbp, %rsi
leaq 0xa1c1f(%rip), %rbp     # 0xe5b98
movq %r13, %rdx
callq 0x3d8fa
movq %rbx, %rdi
callq 0x3d2dc
movsd 0x78(%r15), %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 0x4401b
leaq 0xd8(%rsp), %rdi
leaq 0x90(%rsp), %rsi
movsd %xmm2, 0x10(%rsp)
callq 0x3d252
movsd 0x10(%rsp), %xmm1
movapd %xmm0, %xmm2
xorpd %xmm0, %xmm0
ucomisd %xmm0, %xmm1
jb 0x43fed
xorps %xmm0, %xmm0
sqrtsd %xmm1, %xmm0
jmp 0x44002
movapd %xmm1, %xmm0
movsd %xmm2, 0x10(%rsp)
callq 0xe340
movsd 0x10(%rsp), %xmm2
divsd %xmm2, %xmm0
movapd 0x5e012(%rip), %xmm1    # 0xa2020
xorpd %xmm0, %xmm1
maxsd %xmm0, %xmm1
movsd (%rbp), %xmm0
movsd 0x60(%rsp), %xmm3
movapd %xmm3, %xmm2
addsd %xmm1, %xmm2
xorpd 0x5dfef(%rip), %xmm0    # 0xa2020
ucomisd %xmm2, %xmm0
ja 0x44101
movsd %xmm2, 0x40(%rsp)
subsd %xmm1, %xmm3
xorpd %xmm0, %xmm0
maxsd %xmm3, %xmm0
movsd %xmm0, 0x10(%rsp)
xorl %ebp, %ebp
movq %rbp, 0x8(%rsp)
movq %rbp, 0x38(%rsp)
movq 0x30(%rsp), %rdi
movq %r14, %rsi
callq 0x3d252
movsd %xmm0, 0x30(%rsp)
leaq 0xc8(%r15), %rbx
movq %rbx, %rdi
movq %r12, %rsi
callq 0x49617
movsd %xmm0, 0x60(%rsp)
leaq 0x80(%r15), %r14
movq %r14, %rdi
movq %r12, %rsi
callq 0x49617
leaq 0xa1af5(%rip), %rax     # 0xe5b98
movsd (%rax), %xmm1
movsd 0x60(%rsp), %xmm2
ucomisd %xmm1, %xmm2
ja 0x44108
movsd 0x30(%rsp), %xmm2
ucomisd %xmm1, %xmm0
ja 0x441dc
ucomisd %xmm1, %xmm2
ja 0x4427e
xorpd 0x5df4b(%rip), %xmm1    # 0xa2020
ucomisd %xmm2, %xmm1
jbe 0x44373
leaq 0x70(%rsp), %rbx
movq %rbx, %rdi
movq %r14, %rsi
callq 0x46488
xorl %ebp, %ebp
leaq 0x8(%rsp), %rcx
movq %r12, %rdi
movq %rbx, %rsi
jmp 0x4429b
xorl %ebp, %ebp
jmp 0x44480
xorpd 0x5df10(%rip), %xmm1    # 0xa2020
movsd 0x30(%rsp), %xmm0
ucomisd %xmm1, %xmm0
jae 0x44480
xorl %ebp, %ebp
leaq 0x8(%rsp), %rcx
movq %r12, %rdi
movq %rbx, %rsi
xorl %edx, %edx
callq 0x43016
testl %eax, %eax
je 0x44155
movsd 0x8(%rsp), %xmm0
subsd 0x40(%rsp), %xmm0
leaq 0xa1a4d(%rip), %rax     # 0xe5b98
ucomisd (%rax), %xmm0
ja 0x44480
leaq 0x90(%rsp), %r13
movq %r13, %rdi
movq %r14, %rsi
callq 0x3dc00
movsd 0x98(%r15), %xmm0
xorpd 0x5dea7(%rip), %xmm0    # 0xa2020
leaq 0x70(%rsp), %r14
movq %r14, %rdi
movq %r13, %rsi
callq 0x3b08e
xorl %ebp, %ebp
leaq 0x38(%rsp), %rcx
movq %r12, %rdi
movq %r14, %rsi
xorl %edx, %edx
callq 0x43016
testl %eax, %eax
je 0x442d8
movsd 0x38(%rsp), %xmm0
leaq 0xa19e6(%rip), %rax     # 0xe5b98
movsd (%rax), %xmm1
subsd 0x10(%rsp), %xmm0
movapd 0x5de5c(%rip), %xmm2    # 0xa2020
xorpd %xmm1, %xmm2
ucomisd %xmm0, %xmm2
movq 0x28(%rsp), %r13
jbe 0x442e8
jmp 0x44480
ucomisd %xmm2, %xmm1
jae 0x44480
xorl %ebp, %ebp
leaq 0x8(%rsp), %rcx
movq %r12, %rdi
movq %r14, %rsi
xorl %edx, %edx
callq 0x43016
testl %eax, %eax
je 0x4421b
movsd 0x8(%rsp), %xmm0
subsd 0x40(%rsp), %xmm0
leaq 0xa1987(%rip), %rax     # 0xe5b98
ucomisd (%rax), %xmm0
ja 0x44480
leaq 0x70(%rsp), %r13
movq %r13, %rdi
movq %rbx, %rsi
callq 0x46488
xorl %ebp, %ebp
leaq 0x38(%rsp), %rcx
movq %r12, %rdi
movq %r13, %rsi
xorl %edx, %edx
callq 0x43016
testl %eax, %eax
je 0x44349
movsd 0x38(%rsp), %xmm0
leaq 0xa1944(%rip), %rax     # 0xe5b98
movsd (%rax), %xmm1
subsd 0x10(%rsp), %xmm0
movapd 0x5ddba(%rip), %xmm2    # 0xa2020
xorpd %xmm1, %xmm2
ucomisd %xmm0, %xmm2
movq 0x28(%rsp), %r13
jbe 0x44359
jmp 0x44480
leaq 0x70(%rsp), %r14
movq %r14, %rdi
movq %rbx, %rsi
callq 0x46488
xorl %ebp, %ebp
leaq 0x8(%rsp), %rcx
movq %r12, %rdi
movq %r14, %rsi
xorl %edx, %edx
callq 0x43016
testl %eax, %eax
je 0x44373
movsd 0x8(%rsp), %xmm0
subsd 0x10(%rsp), %xmm0
leaq 0xa18db(%rip), %rax     # 0xe5b98
movsd (%rax), %xmm1
xorpd 0x5dd57(%rip), %xmm1    # 0xa2020
ucomisd %xmm0, %xmm1
jbe 0x44373
jmp 0x44480
leaq 0xa18b9(%rip), %rax     # 0xe5b98
movsd (%rax), %xmm1
movq 0x28(%rsp), %r13
movsd 0x8(%rsp), %xmm0
movapd %xmm0, %xmm2
subsd 0x10(%rsp), %xmm2
ucomisd %xmm1, %xmm2
jbe 0x44373
testq %r13, %r13
je 0x44309
movsd %xmm0, (%r13)
movq 0x48(%rsp), %r15
testq %r15, %r15
je 0x4432e
leaq 0x70(%rsp), %r14
movq %r14, %rdi
movq %r12, %rsi
callq 0x3c132
movq %r15, %rdi
movq %r14, %rsi
callq 0x3c89a
movl $0x1, %ebp
movq 0x50(%rsp), %rdi
testq %rdi, %rdi
je 0x44480
movq %rbx, %rsi
jmp 0x444d6
leaq 0xa1848(%rip), %rax     # 0xe5b98
movsd (%rax), %xmm1
movq 0x28(%rsp), %r13
movsd 0x8(%rsp), %xmm0
movapd %xmm0, %xmm2
subsd 0x10(%rsp), %xmm2
ucomisd %xmm1, %xmm2
ja 0x44494
testq %r13, %r13
je 0x44384
movsd 0x10(%rsp), %xmm0
movsd %xmm0, (%r13)
movq 0x48(%rsp), %r14
testq %r14, %r14
movq 0x50(%rsp), %r13
je 0x443c9
leaq 0x70(%rsp), %rbx
movq %rbx, %rdi
movq %r12, %rsi
movsd 0x10(%rsp), %xmm0
callq 0x3c132
movq %r14, %rdi
movq %rbx, %rsi
callq 0x3c89a
testq %r13, %r13
je 0x4447b
leaq 0x70(%rsp), %rdi
callq 0x3c530
jmp 0x44403
testq %r13, %r13
je 0x4447b
leaq 0x70(%rsp), %r14
movq %r14, %rdi
callq 0x3c530
leaq 0x90(%rsp), %rbx
movq %rbx, %rdi
movq %r12, %rsi
movsd 0x10(%rsp), %xmm0
callq 0x3c132
movq %r14, %rdi
movq %rbx, %rsi
callq 0x3c89a
leaq 0x90(%rsp), %rbx
movq %rbx, %rdi
movq %r14, %rsi
movq 0x58(%rsp), %rdx
callq 0x3c78e
leaq 0xc0(%rsp), %r14
movq %rbx, %rdi
movq %r14, %rsi
callq 0x3d252
leaq 0xf0(%rsp), %r12
movq %r12, %rdi
movq %r14, %rsi
callq 0x3d962
leaq 0x108(%rsp), %r14
movq %r14, %rdi
movq %rbx, %rsi
movq %r12, %rdx
callq 0x3dc43
movsd 0x78(%r15), %xmm0
leaq 0x120(%rsp), %rbx
movq %rbx, %rdi
movq %r14, %rsi
callq 0x3dcac
movq %r13, %rdi
movq %rbx, %rsi
callq 0x3d752
movl $0x1, %ebp
movl %ebp, %eax
addq $0x138, %rsp            # imm = 0x138
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
testq %r13, %r13
je 0x4449f
movsd %xmm0, (%r13)
movq 0x48(%rsp), %r15
testq %r15, %r15
je 0x444c4
leaq 0x70(%rsp), %rbx
movq %rbx, %rdi
movq %r12, %rsi
callq 0x3c132
movq %r15, %rdi
movq %rbx, %rsi
callq 0x3c89a
movl $0x1, %ebp
movq 0x50(%rsp), %rdi
testq %rdi, %rdi
je 0x44480
movq %r14, %rsi
callq 0x3d752
jmp 0x44480