// File: tomfunkhouser[P]gaps/pkgs/R3Graphics/R3SceneNode.cpp
// Function: gaps::R3SceneNode::Intersects(gaps::R3Ray const&, gaps::R3SceneNode**, gaps::R3Material**, gaps::R3Shape**, gaps::R3Point*, gaps::R3Vector*, double*, double, double) const
RNBoolean R3SceneNode::
Intersects(const R3Ray& ray,
  R3SceneNode **hit_node, R3Material **hit_material, R3Shape **hit_shape,
  R3Point *hit_point, R3Vector *hit_normal, RNScalar *hit_t,
  RNScalar min_t, RNScalar max_t) const
{
  // Temporary variables
  R3SceneNode *closest_node = NULL;
  R3Point closest_point = R3zero_point;
  RNScalar closest_t = max_t;
  RNScalar bbox_t;
  R3SceneNode *node;
  R3Material *material;
  R3Shape *shape;
  R3Point point;
  R3Vector normal;
  RNScalar t;

  // Check if ray intersects bounding box
  if (!R3Intersects(ray, BBox(), NULL, NULL, &bbox_t)) return FALSE;
  if (RNIsGreater(bbox_t, max_t)) return FALSE;

  // Apply inverse transformation to ray
  R3Ray node_ray = ray;
  node_ray.InverseTransform(transformation);

  // Apply inverse transform to min_t and closest_t
  RNScalar scale = 1.0;
  R3Vector v(ray.Vector());
  v.InverseTransform(transformation);
  RNScalar length = v.Length();
  if (RNIsNegativeOrZero(length)) return FALSE;
  if (RNIsNotEqual(length, 1.0)) {
    scale = length;
    min_t *= scale;
    closest_t *= scale;
  }

  // Find closest element intersection
  for (int i = 0; i < elements.NEntries(); i++) {
    R3SceneElement *element = elements.Kth(i);
    if (element->Intersects(node_ray, &shape, &point, &normal, &t, min_t, closest_t)) {
      if ((t >= min_t) && (t <= closest_t)) {
        if (hit_node) *hit_node = (R3SceneNode *) this;
        if (hit_material) *hit_material = element->Material();
        if (hit_shape) *hit_shape = shape; 
        if (hit_normal) *hit_normal = normal; 
        closest_node = (R3SceneNode *) this;
        closest_point = point;
        closest_t = t;
      }
    }
  }

  // Find closest reference intersection
  for (int i = 0; i < references.NEntries(); i++) {
    R3SceneReference *reference = references.Kth(i);
    R3Scene *referenced_scene = reference->ReferencedScene();
    if (referenced_scene) {
      if (referenced_scene->Intersects(node_ray, &node, &material, &shape, &point, &normal, &t, min_t, closest_t)) {
        if ((t >= min_t) && (t <= closest_t)) {
          if (hit_node) *hit_node = node;
          if (hit_material) *hit_material = material;
          if (hit_shape) *hit_shape = shape; 
          if (hit_normal) *hit_normal = normal; 
          closest_node = (R3SceneNode *) this;
          closest_point = point;
          closest_t = t;
        }
      }
    }
  }

  // Find closest node intersection
  for (int i = 0; i < children.NEntries(); i++) {
    R3SceneNode *child = children.Kth(i);
    if (child->Intersects(node_ray, &node, &material, &shape, &point, &normal, &t, min_t, closest_t)) {
      if ((t >= min_t) && (t <= closest_t)) {
        if (hit_node) *hit_node = node;
        if (hit_material) *hit_material = material;
        if (hit_shape) *hit_shape = shape; 
        if (hit_normal) *hit_normal = normal; 
        closest_node = node;
        closest_point = point;
        closest_t = t;
      }
    }
  }

  // Check if found hit
  if (!closest_node) return FALSE;

  // Transform hit point into parent's coordinate system
  if (hit_t || hit_point) {
    closest_point.Transform(transformation); 
    if (hit_point) *hit_point = closest_point;
    if (hit_t) *hit_t = closest_t / scale; 
  }

  // Transform hit normal into parent's coordinate system
  if (hit_normal) {
    hit_normal->Transform(transformation); 
    hit_normal->Normalize();
  }

  // Return success
  return TRUE;
}

// Assembly:
subq $0x188, %rsp            # imm = 0x188
movq 0x198(%rsp), %rax
movq 0x190(%rsp), %rax
movq %rdi, 0x178(%rsp)
movq %rsi, 0x170(%rsp)
movq %rdx, 0x168(%rsp)
movq %rcx, 0x160(%rsp)
movq %r8, 0x158(%rsp)
movq %r9, 0x150(%rsp)
movsd %xmm0, 0x148(%rsp)
movsd %xmm1, 0x140(%rsp)
movq 0x178(%rsp), %rax
movq %rax, 0x20(%rsp)
movq $0x0, 0x138(%rsp)
leaq 0x120(%rsp), %rdi
leaq 0x1a77ef(%rip), %rsi    # 0x1ff1e0
callq 0xcc8b0
movsd 0x140(%rsp), %xmm0
movsd %xmm0, 0x118(%rsp)
leaq 0xe0(%rsp), %rdi
callq 0xcc860
leaq 0xc8(%rsp), %rdi
callq 0xcd9c0
movq 0x20(%rsp), %rdi
movq 0x170(%rsp), %rax
movq %rax, 0x28(%rsp)
callq 0x56d40
movq 0x28(%rsp), %rdi
movq %rax, %rsi
xorl %eax, %eax
movl %eax, %ecx
leaq 0x110(%rsp), %r8
movq %rcx, %rdx
callq 0x6bec0
cmpl $0x0, %eax
jne 0x57a6a
movl $0x0, 0x184(%rsp)
jmp 0x5815e
movsd 0x110(%rsp), %xmm0
movsd 0x140(%rsp), %xmm1
leaq 0x19e825(%rip), %rax    # 0x1f62a8
movsd (%rax), %xmm2
callq 0x585b0
cmpl $0x0, %eax
je 0x57aa1
movl $0x0, 0x184(%rsp)
jmp 0x5815e
movq 0x170(%rsp), %rsi
leaq 0x90(%rsp), %rdi
callq 0xcc130
movq 0x20(%rsp), %rsi
addq $0x58, %rsi
leaq 0x90(%rsp), %rdi
callq 0xcc380
movsd 0x13653c(%rip), %xmm0   # 0x18e010
movsd %xmm0, 0x88(%rsp)
movq 0x170(%rsp), %rdi
callq 0x4ebc0
movq %rax, %rsi
leaq 0x70(%rsp), %rdi
callq 0xcda10
movq 0x20(%rsp), %rsi
addq $0x58, %rsi
leaq 0x70(%rsp), %rdi
callq 0xceb60
leaq 0x70(%rsp), %rdi
callq 0xcdbb0
movsd %xmm0, 0x68(%rsp)
movsd 0x68(%rsp), %xmm0
leaq 0x19e781(%rip), %rax    # 0x1f62a8
movsd (%rax), %xmm1
callq 0x49e40
cmpl $0x0, %eax
je 0x57b45
movl $0x0, 0x184(%rsp)
jmp 0x5815e
movsd 0x68(%rsp), %xmm0
leaq 0x19e756(%rip), %rax    # 0x1f62a8
movsd (%rax), %xmm2
movsd 0x1364b2(%rip), %xmm1   # 0x18e010
callq 0x48a20
cmpl $0x0, %eax
je 0x57bad
movsd 0x68(%rsp), %xmm0
movsd %xmm0, 0x88(%rsp)
movsd 0x88(%rsp), %xmm0
mulsd 0x148(%rsp), %xmm0
movsd %xmm0, 0x148(%rsp)
movsd 0x88(%rsp), %xmm0
mulsd 0x118(%rsp), %xmm0
movsd %xmm0, 0x118(%rsp)
movl $0x0, 0x64(%rsp)
movq 0x20(%rsp), %rdi
movl 0x64(%rsp), %eax
movl %eax, 0x1c(%rsp)
addq $0x30, %rdi
callq 0x2b8b0
movl %eax, %ecx
movl 0x1c(%rsp), %eax
cmpl %ecx, %eax
jge 0x57d35
movq 0x20(%rsp), %rdi
addq $0x30, %rdi
movl 0x64(%rsp), %esi
callq 0x2bd50
movq %rax, 0x58(%rsp)
movq 0x58(%rsp), %rdi
movsd 0x148(%rsp), %xmm0
movsd 0x118(%rsp), %xmm1
leaq 0x90(%rsp), %rsi
leaq 0xf8(%rsp), %rdx
leaq 0xe0(%rsp), %rcx
leaq 0xc8(%rsp), %r8
leaq 0xc0(%rsp), %r9
callq 0x59710
cmpl $0x0, %eax
je 0x57d23
movsd 0xc0(%rsp), %xmm0
ucomisd 0x148(%rsp), %xmm0
jb 0x57d21
movsd 0xc0(%rsp), %xmm1
movsd 0x118(%rsp), %xmm0
ucomisd %xmm1, %xmm0
jb 0x57d21
cmpq $0x0, 0x168(%rsp)
je 0x57c8c
movq 0x20(%rsp), %rcx
movq 0x168(%rsp), %rax
movq %rcx, (%rax)
cmpq $0x0, 0x160(%rsp)
je 0x57caf
movq 0x58(%rsp), %rdi
callq 0x48b50
movq %rax, %rcx
movq 0x160(%rsp), %rax
movq %rcx, (%rax)
cmpq $0x0, 0x158(%rsp)
je 0x57ccd
movq 0xf8(%rsp), %rcx
movq 0x158(%rsp), %rax
movq %rcx, (%rax)
cmpq $0x0, 0x190(%rsp)
je 0x57ced
movq 0x190(%rsp), %rdi
leaq 0xc8(%rsp), %rsi
callq 0xce690
movq 0x20(%rsp), %rax
movq %rax, 0x138(%rsp)
leaq 0x120(%rsp), %rdi
leaq 0xe0(%rsp), %rsi
callq 0xccf00
movsd 0xc0(%rsp), %xmm0
movsd %xmm0, 0x118(%rsp)
jmp 0x57d23
jmp 0x57d25
movl 0x64(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x64(%rsp)
jmp 0x57bb5
movl $0x0, 0x54(%rsp)
movq 0x20(%rsp), %rdi
movl 0x54(%rsp), %eax
movl %eax, 0x18(%rsp)
addq $0x40, %rdi
callq 0x2b8b0
movl %eax, %ecx
movl 0x18(%rsp), %eax
cmpl %ecx, %eax
jge 0x57ef1
movq 0x20(%rsp), %rdi
addq $0x40, %rdi
movl 0x54(%rsp), %esi
callq 0x2bd30
movq %rax, 0x48(%rsp)
movq 0x48(%rsp), %rdi
callq 0x2bb90
movq %rax, 0x40(%rsp)
cmpq $0x0, 0x40(%rsp)
je 0x57edf
movq 0x40(%rsp), %rdi
movsd 0x148(%rsp), %xmm0
movsd 0x118(%rsp), %xmm1
leaq 0x90(%rsp), %rsi
leaq 0x108(%rsp), %rdx
leaq 0x100(%rsp), %rcx
leaq 0xf8(%rsp), %r8
leaq 0xe0(%rsp), %r9
leaq 0xc8(%rsp), %r10
leaq 0xc0(%rsp), %rax
movq %r10, (%rsp)
movq %rax, 0x8(%rsp)
callq 0x2dd90
cmpl $0x0, %eax
je 0x57edd
movsd 0xc0(%rsp), %xmm0
ucomisd 0x148(%rsp), %xmm0
jb 0x57edb
movsd 0xc0(%rsp), %xmm1
movsd 0x118(%rsp), %xmm0
ucomisd %xmm1, %xmm0
jb 0x57edb
cmpq $0x0, 0x168(%rsp)
je 0x57e4b
movq 0x108(%rsp), %rcx
movq 0x168(%rsp), %rax
movq %rcx, (%rax)
cmpq $0x0, 0x160(%rsp)
je 0x57e69
movq 0x100(%rsp), %rcx
movq 0x160(%rsp), %rax
movq %rcx, (%rax)
cmpq $0x0, 0x158(%rsp)
je 0x57e87
movq 0xf8(%rsp), %rcx
movq 0x158(%rsp), %rax
movq %rcx, (%rax)
cmpq $0x0, 0x190(%rsp)
je 0x57ea7
movq 0x190(%rsp), %rdi
leaq 0xc8(%rsp), %rsi
callq 0xce690
movq 0x20(%rsp), %rax
movq %rax, 0x138(%rsp)
leaq 0x120(%rsp), %rdi
leaq 0xe0(%rsp), %rsi
callq 0xccf00
movsd 0xc0(%rsp), %xmm0
movsd %xmm0, 0x118(%rsp)
jmp 0x57edd
jmp 0x57edf
jmp 0x57ee1
movl 0x54(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x54(%rsp)
jmp 0x57d3d
movl $0x0, 0x3c(%rsp)
movq 0x20(%rsp), %rdi
movl 0x3c(%rsp), %eax
movl %eax, 0x14(%rsp)
addq $0x20, %rdi
callq 0x2b8b0
movl %eax, %ecx
movl 0x14(%rsp), %eax
cmpl %ecx, %eax
jge 0x58093
movq 0x20(%rsp), %rdi
addq $0x20, %rdi
movl 0x3c(%rsp), %esi
callq 0x2bd10
movq %rax, 0x30(%rsp)
movq 0x30(%rsp), %rdi
movsd 0x148(%rsp), %xmm0
movsd 0x118(%rsp), %xmm1
leaq 0x90(%rsp), %rsi
leaq 0x108(%rsp), %rdx
leaq 0x100(%rsp), %rcx
leaq 0xf8(%rsp), %r8
leaq 0xe0(%rsp), %r9
leaq 0xc8(%rsp), %r10
leaq 0xc0(%rsp), %rax
movq %r10, (%rsp)
movq %rax, 0x8(%rsp)
callq 0x57970
cmpl $0x0, %eax
je 0x58081
movsd 0xc0(%rsp), %xmm0
ucomisd 0x148(%rsp), %xmm0
jb 0x5807f
movsd 0xc0(%rsp), %xmm1
movsd 0x118(%rsp), %xmm0
ucomisd %xmm1, %xmm0
jb 0x5807f
cmpq $0x0, 0x168(%rsp)
je 0x57fec
movq 0x108(%rsp), %rcx
movq 0x168(%rsp), %rax
movq %rcx, (%rax)
cmpq $0x0, 0x160(%rsp)
je 0x5800a
movq 0x100(%rsp), %rcx
movq 0x160(%rsp), %rax
movq %rcx, (%rax)
cmpq $0x0, 0x158(%rsp)
je 0x58028
movq 0xf8(%rsp), %rcx
movq 0x158(%rsp), %rax
movq %rcx, (%rax)
cmpq $0x0, 0x190(%rsp)
je 0x58048
movq 0x190(%rsp), %rdi
leaq 0xc8(%rsp), %rsi
callq 0xce690
movq 0x108(%rsp), %rax
movq %rax, 0x138(%rsp)
leaq 0x120(%rsp), %rdi
leaq 0xe0(%rsp), %rsi
callq 0xccf00
movsd 0xc0(%rsp), %xmm0
movsd %xmm0, 0x118(%rsp)
jmp 0x58081
jmp 0x58083
movl 0x3c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x3c(%rsp)
jmp 0x57ef9
cmpq $0x0, 0x138(%rsp)
jne 0x580ae
movl $0x0, 0x184(%rsp)
jmp 0x5815e
cmpq $0x0, 0x198(%rsp)
jne 0x580c4
cmpq $0x0, 0x150(%rsp)
je 0x58125
movq 0x20(%rsp), %rsi
addq $0x58, %rsi
leaq 0x120(%rsp), %rdi
callq 0xcd4e0
cmpq $0x0, 0x150(%rsp)
je 0x580fa
movq 0x150(%rsp), %rdi
leaq 0x120(%rsp), %rsi
callq 0xccf00
cmpq $0x0, 0x198(%rsp)
je 0x58123
movsd 0x118(%rsp), %xmm0
divsd 0x88(%rsp), %xmm0
movq 0x198(%rsp), %rax
movsd %xmm0, (%rax)
jmp 0x58125
cmpq $0x0, 0x190(%rsp)
je 0x58153
movq 0x20(%rsp), %rsi
movq 0x190(%rsp), %rdi
addq $0x58, %rsi
callq 0xceb30
movq 0x190(%rsp), %rdi
callq 0xce130
movl $0x1, 0x184(%rsp)
movl 0x184(%rsp), %eax
addq $0x188, %rsp            # imm = 0x188
retq
nopl (%rax)