// File: tomfunkhouser[P]gaps/apps/msh2pts/msh2pts.cpp
// Function: SelectScaleSpaceExtrema(gaps::R3Mesh*, gaps::R3MeshProperty*, int, double, int)
static RNArray<Point *> *
SelectScaleSpaceExtrema(R3Mesh *mesh, R3MeshProperty *prp,
  int npoints, double min_spacing, int extrema_type)
{
  // Copy property 
  R3MeshProperty property(*prp);

  // Normalize property
  property.Normalize();

  // Allocate scores
  ScaleSpaceScore *scores = new ScaleSpaceScore [ mesh->NVertices() ];
  for (int i = 0; i < mesh->NVertices(); i++) {
    scores[i].vertex_index = i;
    scores[i].score = 0;
  }

  // Compute scale space scores
  int nblurs = 4;
  RNScalar weight = 1;
  RNScalar sigma = 0.01 * sqrt(mesh->Area());
  for (int blur = 0; blur < nblurs; blur++) { 
    // Compute strength of every vertex
    R3MeshProperty vote(property);
    for (int i = 0; i < mesh->NVertices(); i++) {
      R3MeshVertex *vertex = mesh->Vertex(i);
      RNScalar value = VoteValue(mesh, vertex, &property, extrema_type);
      vote.SetVertexValue(i, value); 
    }

    // Vote for vertex with its normalized strength value (augmented if local extremum)
    for (int i = 0; i < mesh->NVertices(); i++) {
      scores[i].score += weight * vote.VertexValue(i);
    }

    // Blur the property and iterate
    property.Blur(sigma);
    // weight *= 2;
    // sigma *= 2;
  }


  if (print_debug) {
    property.Write("property.val");
    R3MeshProperty foo(mesh, "ScaleSpaceScore");
    for (int i = 0; i < mesh->NVertices(); i++) foo.SetVertexValue(i, scores[i].score);
    foo.Write("scores.val");
  }

  // Sort vertices by score
  qsort(scores, mesh->NVertices(), sizeof(ScaleSpaceScore), CompareScaleSpaceScores);

  // Select vertices taking into account min_spacing
  R3mesh_mark++;
  RNArray<R3MeshVertex *> selected_vertices;
  for (int i = 0; i < mesh->NVertices(); i++) {
    R3MeshVertex *vertex = mesh->Vertex(scores[i].vertex_index);
    
    // Check if vertex is marked (i.e., too close to vertex previously selected)
    if (mesh->VertexMark(vertex) == R3mesh_mark) continue;

    // Check if vertex is disconnected completely
    if (mesh->VertexValence(vertex) == 0) continue;
    
    // Select vertex
    selected_vertices.Insert(vertex);
    
    // Mark nearby vertices
    mesh->SetVertexMark(vertex, R3mesh_mark);
    if (min_spacing > 0) {
      RNLength *distances = mesh->DijkstraDistances(vertex, min_spacing);
      for (int j = 0; j < mesh->NVertices(); j++) {
        R3MeshVertex *nearby_vertex = mesh->Vertex(j);
        if (mesh->VertexMark(nearby_vertex) != R3mesh_mark) {
          if (distances[j] <= min_spacing) {
            mesh->SetVertexMark(nearby_vertex, R3mesh_mark);
          }
        }
      } 
      delete [] distances;
    }

    // Check if found all points
    if ((npoints > 0) && (selected_vertices.NEntries() >= npoints)) break;
  }

  // Delete scores
  delete [] scores;

  // Allocate array of points
  RNArray<Point *> *points = new RNArray<Point *>();
  if (!points) {
    RNFail("Unable to allocate array of points\n");
    return NULL;
  }

  // Create points
  for (int i = 0; i < selected_vertices.NEntries(); i++) {
    R3MeshVertex *vertex = selected_vertices[i];
    Point *point = new Point(mesh, vertex);
    points->Insert(point);
  }

  // Return points
  return points;
}

// Assembly:
subq $0xe78, %rsp            # imm = 0xE78
movq %rdi, 0xe68(%rsp)
movq %rsi, 0xe60(%rsp)
movl %edx, 0xe5c(%rsp)
movsd %xmm0, 0xe50(%rsp)
movl %ecx, 0xe4c(%rsp)
movq 0xe60(%rsp), %rsi
leaq 0xa00(%rsp), %rdi
movq %rdi, 0xb0(%rsp)
callq 0x26500
movq 0xb0(%rsp), %rdi
callq 0x29580
jmp 0x182ca
movq 0xe68(%rsp), %rdi
callq 0x1b460
cltq
movl $0x10, %ecx
mulq %rcx
movq %rax, %rdi
movq $-0x1, %rax
cmovoq %rax, %rdi
callq 0xf030
movq %rax, 0xa8(%rsp)
jmp 0x182fe
movq 0xa8(%rsp), %rax
movq %rax, 0x9e8(%rsp)
movl $0x0, 0x9e4(%rsp)
movl 0x9e4(%rsp), %eax
movl %eax, 0xa4(%rsp)
movq 0xe68(%rsp), %rdi
callq 0x1b460
movl %eax, %ecx
movl 0xa4(%rsp), %eax
cmpl %ecx, %eax
jge 0x183ac
movl 0x9e4(%rsp), %ecx
movq 0x9e8(%rsp), %rax
movslq 0x9e4(%rsp), %rdx
shlq $0x4, %rdx
addq %rdx, %rax
movl %ecx, (%rax)
movq 0x9e8(%rsp), %rax
movslq 0x9e4(%rsp), %rcx
shlq $0x4, %rcx
addq %rcx, %rax
xorps %xmm0, %xmm0
movsd %xmm0, 0x8(%rax)
movl 0x9e4(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x9e4(%rsp)
jmp 0x18319
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x9f8(%rsp)
movl %eax, 0x9f4(%rsp)
jmp 0x18bb6
movl $0x4, 0x9e0(%rsp)
movabsq $0x3ff0000000000000, %rax # imm = 0x3FF0000000000000
movq %rax, 0x9d8(%rsp)
movq 0xe68(%rsp), %rdi
callq 0x41930
movsd %xmm0, 0x98(%rsp)
jmp 0x183e1
movsd 0x98(%rsp), %xmm0
callq 0xf390
movaps %xmm0, %xmm1
movsd 0x131c46(%rip), %xmm0   # 0x14a040
mulsd %xmm1, %xmm0
movsd %xmm0, 0x9d0(%rsp)
movl $0x0, 0x9cc(%rsp)
movl 0x9cc(%rsp), %eax
cmpl 0x9e0(%rsp), %eax
jge 0x18613
leaq 0x580(%rsp), %rdi
leaq 0xa00(%rsp), %rsi
callq 0x26500
jmp 0x1843d
movl $0x0, 0x57c(%rsp)
movl 0x57c(%rsp), %eax
movl %eax, 0x94(%rsp)
movq 0xe68(%rsp), %rdi
callq 0x1b460
movl %eax, %ecx
movl 0x94(%rsp), %eax
cmpl %ecx, %eax
jge 0x18540
movq 0xe68(%rsp), %rdi
movl 0x57c(%rsp), %esi
callq 0x1b5b0
movq %rax, 0x88(%rsp)
jmp 0x18492
movq 0x88(%rsp), %rax
movq %rax, 0x570(%rsp)
movq 0xe68(%rsp), %rdi
movq 0x570(%rsp), %rsi
movl 0xe4c(%rsp), %ecx
leaq 0xa00(%rsp), %rdx
callq 0x1a730
movsd %xmm0, 0x80(%rsp)
jmp 0x184d1
movsd 0x80(%rsp), %xmm0
movsd %xmm0, 0x568(%rsp)
movl 0x57c(%rsp), %esi
movsd 0x568(%rsp), %xmm0
leaq 0x580(%rsp), %rdi
callq 0x29250
jmp 0x18502
jmp 0x18504
movl 0x57c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x57c(%rsp)
jmp 0x18448
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x9f8(%rsp)
movl %eax, 0x9f4(%rsp)
leaq 0x580(%rsp), %rdi
callq 0x26680
jmp 0x18bb6
movl $0x0, 0x564(%rsp)
movl 0x564(%rsp), %eax
movl %eax, 0x7c(%rsp)
movq 0xe68(%rsp), %rdi
callq 0x1b460
movl %eax, %ecx
movl 0x7c(%rsp), %eax
cmpl %ecx, %eax
jge 0x185d8
movsd 0x9d8(%rsp), %xmm0
movsd %xmm0, 0x70(%rsp)
movl 0x564(%rsp), %esi
leaq 0x580(%rsp), %rdi
callq 0x1ba10
movaps %xmm0, %xmm2
movsd 0x70(%rsp), %xmm0
movq 0x9e8(%rsp), %rax
movslq 0x564(%rsp), %rcx
shlq $0x4, %rcx
addq %rcx, %rax
movsd 0x8(%rax), %xmm1
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, 0x8(%rax)
movl 0x564(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x564(%rsp)
jmp 0x1854b
movsd 0x9d0(%rsp), %xmm0
leaq 0xa00(%rsp), %rdi
callq 0x29e30
jmp 0x185f0
leaq 0x580(%rsp), %rdi
callq 0x26680
movl 0x9cc(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x9cc(%rsp)
jmp 0x18412
cmpl $0x0, 0x178fe2(%rip)    # 0x1915fc
je 0x1870e
leaq 0x132082(%rip), %rsi    # 0x14a6a9
leaq 0xa00(%rsp), %rdi
callq 0x2af60
jmp 0x18636
movq 0xe68(%rsp), %rsi
leaq 0x132071(%rip), %rdx    # 0x14a6b6
xorl %eax, %eax
movl %eax, %ecx
leaq 0x118(%rsp), %rdi
callq 0x262f0
jmp 0x18658
movl $0x0, 0x114(%rsp)
movl 0x114(%rsp), %eax
movl %eax, 0x6c(%rsp)
movq 0xe68(%rsp), %rdi
callq 0x1b460
movl %eax, %ecx
movl 0x6c(%rsp), %eax
cmpl %ecx, %eax
jge 0x186eb
movslq 0x114(%rsp), %rcx
movl %ecx, %esi
movq 0x9e8(%rsp), %rax
shlq $0x4, %rcx
movsd 0x8(%rax,%rcx), %xmm0
leaq 0x118(%rsp), %rdi
callq 0x29250
jmp 0x186b0
jmp 0x186b2
movl 0x114(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x114(%rsp)
jmp 0x18663
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x9f8(%rsp)
movl %eax, 0x9f4(%rsp)
leaq 0x118(%rsp), %rdi
callq 0x26680
jmp 0x18bb6
leaq 0x131fd4(%rip), %rsi    # 0x14a6c6
leaq 0x118(%rsp), %rdi
callq 0x2af60
jmp 0x18701
leaq 0x118(%rsp), %rdi
callq 0x26680
movq 0x9e8(%rsp), %rax
movq %rax, 0x60(%rsp)
movq 0xe68(%rsp), %rdi
callq 0x1b460
movq 0x60(%rsp), %rdi
movslq %eax, %rsi
leaq 0x2259(%rip), %rcx      # 0x1a990
movl $0x10, %edx
callq 0xf960
jmp 0x18743
leaq 0x16fe06(%rip), %rax    # 0x188550
movl (%rax), %ecx
incl %ecx
movl %ecx, (%rax)
leaq 0x100(%rsp), %rdi
callq 0x1e540
jmp 0x1875f
movl $0x0, 0xfc(%rsp)
movl 0xfc(%rsp), %eax
movl %eax, 0x5c(%rsp)
movq 0xe68(%rsp), %rdi
callq 0x1b460
movl %eax, %ecx
movl 0x5c(%rsp), %eax
cmpl %ecx, %eax
jge 0x189d4
movq 0xe68(%rsp), %rdi
movq 0x9e8(%rsp), %rax
movslq 0xfc(%rsp), %rcx
shlq $0x4, %rcx
movl (%rax,%rcx), %esi
callq 0x1b5b0
movq %rax, 0x50(%rsp)
jmp 0x187bb
movq 0x50(%rsp), %rax
movq %rax, 0xf0(%rsp)
movq 0xe68(%rsp), %rdi
movq 0xf0(%rsp), %rsi
callq 0x1b610
leaq 0x16fd6c(%rip), %rcx    # 0x188550
cmpl (%rcx), %eax
jne 0x18806
jmp 0x189be
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x9f8(%rsp)
movl %eax, 0x9f4(%rsp)
jmp 0x18ba9
movq 0xe68(%rsp), %rdi
movq 0xf0(%rsp), %rsi
callq 0x1e5e0
cmpl $0x0, %eax
jne 0x18825
jmp 0x189be
movq 0xf0(%rsp), %rsi
leaq 0x100(%rsp), %rdi
callq 0x1e5b0
jmp 0x1883c
movq 0xe68(%rsp), %rdi
movq 0xf0(%rsp), %rsi
leaq 0x16fcfd(%rip), %rax    # 0x188550
movl (%rax), %edx
callq 0x1b6e0
movsd 0xe50(%rsp), %xmm0
xorps %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jbe 0x1899a
movq 0xe68(%rsp), %rdi
movq 0xf0(%rsp), %rsi
movsd 0xe50(%rsp), %xmm0
xorl %eax, %eax
movl %eax, %edx
callq 0x54770
movq %rax, 0x48(%rsp)
jmp 0x18899
movq 0x48(%rsp), %rax
movq %rax, 0xe8(%rsp)
movl $0x0, 0xe4(%rsp)
movl 0xe4(%rsp), %eax
movl %eax, 0x44(%rsp)
movq 0xe68(%rsp), %rdi
callq 0x1b460
movl %eax, %ecx
movl 0x44(%rsp), %eax
cmpl %ecx, %eax
jge 0x1897b
movq 0xe68(%rsp), %rdi
movl 0xe4(%rsp), %esi
callq 0x1b5b0
movq %rax, 0x38(%rsp)
jmp 0x188f2
movq 0x38(%rsp), %rax
movq %rax, 0xd8(%rsp)
movq 0xe68(%rsp), %rdi
movq 0xd8(%rsp), %rsi
callq 0x1b610
leaq 0x16fc35(%rip), %rcx    # 0x188550
cmpl (%rcx), %eax
je 0x18963
movq 0xe8(%rsp), %rax
movslq 0xe4(%rsp), %rcx
movsd (%rax,%rcx,8), %xmm1
movsd 0xe50(%rsp), %xmm0
ucomisd %xmm1, %xmm0
jb 0x18961
movq 0xe68(%rsp), %rdi
movq 0xd8(%rsp), %rsi
leaq 0x16fbf6(%rip), %rax    # 0x188550
movl (%rax), %edx
callq 0x1b6e0
jmp 0x18963
jmp 0x18965
movl 0xe4(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xe4(%rsp)
jmp 0x188b1
movq 0xe8(%rsp), %rax
movq %rax, 0x30(%rsp)
cmpq $0x0, %rax
je 0x18998
movq 0x30(%rsp), %rdi
callq 0xf680
jmp 0x1899a
cmpl $0x0, 0xe5c(%rsp)
jle 0x189bc
leaq 0x100(%rsp), %rdi
callq 0x1b2f0
cmpl 0xe5c(%rsp), %eax
jl 0x189bc
jmp 0x189d4
jmp 0x189be
movl 0xfc(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xfc(%rsp)
jmp 0x1876a
movq 0x9e8(%rsp), %rax
movq %rax, 0x28(%rsp)
cmpq $0x0, %rax
je 0x189f1
movq 0x28(%rsp), %rdi
callq 0xf680
movl $0x10, %edi
callq 0xf4d0
movq %rax, 0x20(%rsp)
jmp 0x18a02
movq 0x20(%rsp), %rdi
callq 0x1b5a0
jmp 0x18a0e
movq 0x20(%rsp), %rax
movq %rax, 0xd0(%rsp)
cmpq $0x0, 0xd0(%rsp)
jne 0x18a7a
leaq 0x131be2(%rip), %rdi    # 0x14a60f
xorl %eax, %eax
callq 0xebe00
jmp 0x18a36
movq $0x0, 0xe70(%rsp)
movl $0x1, 0xcc(%rsp)
jmp 0x18b7f
movq 0x20(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x9f8(%rsp)
movl %eax, 0x9f4(%rsp)
movl $0x10, %esi
callq 0xf4e0
jmp 0x18ba9
movl $0x0, 0xc8(%rsp)
movl 0xc8(%rsp), %eax
movl %eax, 0x1c(%rsp)
leaq 0x100(%rsp), %rdi
callq 0x1b2f0
movl %eax, %ecx
movl 0x1c(%rsp), %eax
cmpl %ecx, %eax
jge 0x18b64
movl 0xc8(%rsp), %esi
leaq 0x100(%rsp), %rdi
callq 0x1f300
movq %rax, 0x10(%rsp)
jmp 0x18ac6
movq 0x10(%rsp), %rax
movq (%rax), %rax
movq %rax, 0xc0(%rsp)
movl $0x48, %edi
callq 0xf4d0
movq %rax, 0x8(%rsp)
jmp 0x18ae7
movq 0x8(%rsp), %rdi
movq 0xe68(%rsp), %rsi
movq 0xc0(%rsp), %rdx
callq 0x1b650
jmp 0x18b03
movq 0x8(%rsp), %rax
movq %rax, 0xb8(%rsp)
movq 0xd0(%rsp), %rdi
movq 0xb8(%rsp), %rsi
callq 0x1b540
jmp 0x18b27
jmp 0x18b29
movl 0xc8(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xc8(%rsp)
jmp 0x18a85
movq 0x8(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x9f8(%rsp)
movl %eax, 0x9f4(%rsp)
movl $0x48, %esi
callq 0xf4e0
jmp 0x18ba9
movq 0xd0(%rsp), %rax
movq %rax, 0xe70(%rsp)
movl $0x1, 0xcc(%rsp)
leaq 0x100(%rsp), %rdi
callq 0x1e550
leaq 0xa00(%rsp), %rdi
callq 0x26680
movq 0xe70(%rsp), %rax
addq $0xe78, %rsp            # imm = 0xE78
retq
leaq 0x100(%rsp), %rdi
callq 0x1e550
leaq 0xa00(%rsp), %rdi
callq 0x26680
movq 0x9f8(%rsp), %rdi
callq 0xf8a0