// File: tomfunkhouser[P]gaps/pkgs/R3Shapes/R3MeshSearchTree.cpp
// Function: gaps::R3MeshSearchTree::FindClosest(gaps::R3Point const&, gaps::R3Vector const&, gaps::R3MeshIntersection&, double, double, int (*)(gaps::R3Point const&, gaps::R3Vector const&, gaps::R3Mesh*, gaps::R3MeshFace*, void*), void*)
void R3MeshSearchTree::
FindClosest(const R3Point& query_position, const R3Vector& query_normal, R3MeshIntersection& closest,
  RNScalar min_distance, RNScalar max_distance, 
  int (*IsCompatible)(const R3Point&, const R3Vector&, R3Mesh *, R3MeshFace *, void *), void *compatible_data)
{
  // Initialize result
  closest.type = R3_MESH_NULL_TYPE;
  closest.vertex = NULL;
  closest.edge = NULL;
  closest.face = NULL;
  closest.point = R3zero_point;
  closest.t = 0;

  // Check root
  if (!root) return;

  // Update mark (used to avoid checking same face twice)
  mark++;

  // Use squared distances for efficiency
  RNScalar min_distance_squared = min_distance * min_distance;
  RNScalar closest_distance_squared = max_distance * max_distance;

  // Search nodes recursively
  FindClosest(query_position, query_normal, closest, 
    min_distance_squared, closest_distance_squared, 
    IsCompatible, compatible_data, 
    root, BBox());

  // Update result
  closest.t = sqrt(closest_distance_squared);
  if (closest.type == R3_MESH_VERTEX_TYPE) { 
    closest.face = mesh->FaceOnVertex(closest.vertex);
    closest.edge = mesh->EdgeOnVertex(closest.vertex, closest.face, RN_CCW); 
  }
  else if (closest.type == R3_MESH_EDGE_TYPE) { 
    R3MeshVertex *v0 = mesh->VertexOnEdge(closest.edge, 0);
    R3MeshVertex *v1 = mesh->VertexOnEdge(closest.edge, 1);
    const R3Point& p0 = mesh->VertexPosition(v0);
    const R3Point& p1 = mesh->VertexPosition(v1);
    RNScalar dd0 = R3SquaredDistance(query_position, p0);
    RNScalar dd1 = R3SquaredDistance(query_position, p1);
    closest.vertex = (dd0 < dd1) ? v0 : v1;
    closest.face = mesh->FaceOnEdge(closest.edge);
  }
  else if (closest.type == R3_MESH_FACE_TYPE) { 
    R3MeshVertex *v0 = mesh->VertexOnFace(closest.face, 0);
    R3MeshVertex *v1 = mesh->VertexOnFace(closest.face, 1);
    R3MeshVertex *v2 = mesh->VertexOnFace(closest.face, 2);
    const R3Point& p0 = mesh->VertexPosition(v0);
    const R3Point& p1 = mesh->VertexPosition(v1);
    const R3Point& p2 = mesh->VertexPosition(v2);
    RNScalar dd0 = R3SquaredDistance(query_position, p0);
    RNScalar dd1 = R3SquaredDistance(query_position, p1);
    RNScalar dd2 = R3SquaredDistance(query_position, p2);
    if (dd0 < dd1) closest.vertex = (dd0 < dd2) ? v0 : v2;
    else closest.vertex = (dd1 < dd2) ? v1 : v2;
  }

  // Just checking
  assert((closest.type == R3_MESH_NULL_TYPE) || (RNIsZero(R3SquaredDistance(closest.point, mesh->ClosestPointOnFace(closest.face, closest.point)), RN_SMALL_EPSILON)));
}

// Assembly:
subq $0x138, %rsp            # imm = 0x138
movq %rdi, 0x130(%rsp)
movq %rsi, 0x128(%rsp)
movq %rdx, 0x120(%rsp)
movq %rcx, 0x118(%rsp)
movsd %xmm0, 0x110(%rsp)
movsd %xmm1, 0x108(%rsp)
movq %r8, 0x100(%rsp)
movq %r9, 0xf8(%rsp)
movq 0x130(%rsp), %rax
movq %rax, 0x68(%rsp)
movq 0x118(%rsp), %rax
movl $0x0, (%rax)
movq 0x118(%rsp), %rax
movq $0x0, 0x8(%rax)
movq 0x118(%rsp), %rax
movq $0x0, 0x10(%rax)
movq 0x118(%rsp), %rax
movq $0x0, 0x18(%rax)
movq 0x118(%rsp), %rdi
addq $0x20, %rdi
leaq 0x569779(%rip), %rsi    # 0x5877c0
callq 0x935a0
movq 0x68(%rsp), %rax
movq 0x118(%rsp), %rcx
xorps %xmm0, %xmm0
movsd %xmm0, 0x38(%rcx)
cmpq $0x0, 0x8(%rax)
jne 0x1e06d
jmp 0x1e501
movq 0x68(%rsp), %rdi
movl 0x14(%rdi), %eax
addl $0x1, %eax
movl %eax, 0x14(%rdi)
movsd 0x110(%rsp), %xmm0
mulsd 0x110(%rsp), %xmm0
movsd %xmm0, 0xf0(%rsp)
movsd 0x108(%rsp), %xmm0
mulsd 0x108(%rsp), %xmm0
movsd %xmm0, 0xe8(%rsp)
movq 0x128(%rsp), %rax
movq %rax, 0x30(%rsp)
movq 0x120(%rsp), %rax
movq %rax, 0x38(%rsp)
movq 0x118(%rsp), %rax
movq %rax, 0x40(%rsp)
movsd 0xf0(%rsp), %xmm0
movsd %xmm0, 0x48(%rsp)
movq 0x100(%rsp), %rax
movq %rax, 0x50(%rsp)
movq 0xf8(%rsp), %rax
movq %rax, 0x58(%rsp)
movq 0x8(%rdi), %rax
movq %rax, 0x60(%rsp)
callq 0x21710
movq 0x68(%rsp), %rdi
movq 0x30(%rsp), %rsi
movq 0x38(%rsp), %rdx
movq 0x40(%rsp), %rcx
movsd 0x48(%rsp), %xmm0
movq 0x50(%rsp), %r9
movq 0x58(%rsp), %r11
movq 0x60(%rsp), %r10
leaq 0xe8(%rsp), %r8
movq %r11, (%rsp)
movq %r10, 0x8(%rsp)
movq %rax, 0x10(%rsp)
callq 0x1d800
movsd 0xe8(%rsp), %xmm0
callq 0xf390
movq 0x118(%rsp), %rax
movsd %xmm0, 0x38(%rax)
movq 0x118(%rsp), %rax
cmpl $0x1, (%rax)
jne 0x1e1de
movq 0x68(%rsp), %rax
movq (%rax), %rdi
movq 0x118(%rsp), %rax
movq 0x8(%rax), %rsi
callq 0x218d0
movq %rax, %rdx
movq 0x68(%rsp), %rax
movq 0x118(%rsp), %rcx
movq %rdx, 0x18(%rcx)
movq (%rax), %rdi
movq 0x118(%rsp), %rax
movq 0x8(%rax), %rsi
movq 0x118(%rsp), %rax
movq 0x18(%rax), %rdx
xorl %ecx, %ecx
callq 0x3aae0
movq %rax, %rcx
movq 0x118(%rsp), %rax
movq %rcx, 0x10(%rax)
jmp 0x1e501
movq 0x118(%rsp), %rax
cmpl $0x2, (%rax)
jne 0x1e329
movq 0x68(%rsp), %rax
movq (%rax), %rdi
movq 0x118(%rsp), %rax
movq 0x10(%rax), %rsi
xorl %edx, %edx
callq 0x21980
movq %rax, %rcx
movq 0x68(%rsp), %rax
movq %rcx, 0xe0(%rsp)
movq (%rax), %rdi
movq 0x118(%rsp), %rax
movq 0x10(%rax), %rsi
movl $0x1, %edx
callq 0x21980
movq %rax, %rcx
movq 0x68(%rsp), %rax
movq %rcx, 0xd8(%rsp)
movq (%rax), %rdi
movq 0xe0(%rsp), %rsi
callq 0x17a40
movq %rax, %rcx
movq 0x68(%rsp), %rax
movq %rcx, 0xd0(%rsp)
movq (%rax), %rdi
movq 0xd8(%rsp), %rsi
callq 0x17a40
movq %rax, 0xc8(%rsp)
movq 0x128(%rsp), %rdi
movq 0xd0(%rsp), %rsi
callq 0x304d0
movsd %xmm0, 0xc0(%rsp)
movq 0x128(%rsp), %rdi
movq 0xc8(%rsp), %rsi
callq 0x304d0
movsd %xmm0, 0xb8(%rsp)
movsd 0xc0(%rsp), %xmm1
movsd 0xb8(%rsp), %xmm0
ucomisd %xmm1, %xmm0
jbe 0x1e2de
movq 0xe0(%rsp), %rax
movq %rax, 0x28(%rsp)
jmp 0x1e2eb
movq 0xd8(%rsp), %rax
movq %rax, 0x28(%rsp)
movq 0x68(%rsp), %rax
movq 0x28(%rsp), %rdx
movq 0x118(%rsp), %rcx
movq %rdx, 0x8(%rcx)
movq (%rax), %rdi
movq 0x118(%rsp), %rax
movq 0x10(%rax), %rsi
callq 0x219a0
movq %rax, %rcx
movq 0x118(%rsp), %rax
movq %rcx, 0x18(%rax)
jmp 0x1e4ff
movq 0x118(%rsp), %rax
cmpl $0x3, (%rax)
jne 0x1e4fd
movq 0x68(%rsp), %rax
movq (%rax), %rdi
movq 0x118(%rsp), %rax
movq 0x18(%rax), %rsi
xorl %edx, %edx
callq 0x17a60
movq %rax, %rcx
movq 0x68(%rsp), %rax
movq %rcx, 0xb0(%rsp)
movq (%rax), %rdi
movq 0x118(%rsp), %rax
movq 0x18(%rax), %rsi
movl $0x1, %edx
callq 0x17a60
movq %rax, %rcx
movq 0x68(%rsp), %rax
movq %rcx, 0xa8(%rsp)
movq (%rax), %rdi
movq 0x118(%rsp), %rax
movq 0x18(%rax), %rsi
movl $0x2, %edx
callq 0x17a60
movq %rax, %rcx
movq 0x68(%rsp), %rax
movq %rcx, 0xa0(%rsp)
movq (%rax), %rdi
movq 0xb0(%rsp), %rsi
callq 0x17a40
movq %rax, %rcx
movq 0x68(%rsp), %rax
movq %rcx, 0x98(%rsp)
movq (%rax), %rdi
movq 0xa8(%rsp), %rsi
callq 0x17a40
movq %rax, %rcx
movq 0x68(%rsp), %rax
movq %rcx, 0x90(%rsp)
movq (%rax), %rdi
movq 0xa0(%rsp), %rsi
callq 0x17a40
movq %rax, 0x88(%rsp)
movq 0x128(%rsp), %rdi
movq 0x98(%rsp), %rsi
callq 0x304d0
movsd %xmm0, 0x80(%rsp)
movq 0x128(%rsp), %rdi
movq 0x90(%rsp), %rsi
callq 0x304d0
movsd %xmm0, 0x78(%rsp)
movq 0x128(%rsp), %rdi
movq 0x88(%rsp), %rsi
callq 0x304d0
movsd %xmm0, 0x70(%rsp)
movsd 0x80(%rsp), %xmm1
movsd 0x78(%rsp), %xmm0
ucomisd %xmm1, %xmm0
jbe 0x1e4bc
movsd 0x80(%rsp), %xmm1
movsd 0x70(%rsp), %xmm0
ucomisd %xmm1, %xmm0
jbe 0x1e49c
movq 0xb0(%rsp), %rax
movq %rax, 0x20(%rsp)
jmp 0x1e4a9
movq 0xa0(%rsp), %rax
movq %rax, 0x20(%rsp)
movq 0x20(%rsp), %rcx
movq 0x118(%rsp), %rax
movq %rcx, 0x8(%rax)
jmp 0x1e4fb
movsd 0x78(%rsp), %xmm1
movsd 0x70(%rsp), %xmm0
ucomisd %xmm1, %xmm0
jbe 0x1e4dd
movq 0xa8(%rsp), %rax
movq %rax, 0x18(%rsp)
jmp 0x1e4ea
movq 0xa0(%rsp), %rax
movq %rax, 0x18(%rsp)
movq 0x18(%rsp), %rcx
movq 0x118(%rsp), %rax
movq %rcx, 0x8(%rax)
jmp 0x1e4fd
jmp 0x1e4ff
jmp 0x1e501
addq $0x138, %rsp            # imm = 0x138
retq
nopl (%rax)