// File: tomfunkhouser[P]gaps/apps/prp2prp/prp2prp.cpp
// Function: Multiscale(gaps::R3MeshPropertySet*, char const*, int&, char**&)
static void
Multiscale(R3MeshPropertySet *properties, const char *property_name, int& argc, char **& argv)
{
  // Get convenient variables
  R3Mesh *mesh = properties->Mesh();
  RNScalar sigma0 = atof(argv[0]) * Scale(mesh);
  RNScalar scale_factor = atof(argv[1]);
  int nscales = atoi(argv[2]);
  argc -= 3; argv += 3;
  if (sigma0 == 0) return;
  if (scale_factor == 0) return;
  if (nscales == 0) return;;

  // Find properties matching property_name
  RNArray<R3MeshProperty *> subset = FindProperties(properties, property_name);
  if (subset.NEntries() == 0) return;;

  // Allocate multiscale properties
  char name[4096];
  R3MeshProperty ***blurs = new R3MeshProperty **[ subset.NEntries() ];
  for (int i = 0; i < subset.NEntries(); i++) {
    R3MeshProperty *property = subset.Kth(i);
    blurs[i] = new R3MeshProperty *[nscales];
    for (int j = 0; j < nscales; j++) {
      sprintf(name, "%s_Multiscale_%d", property->Name(), j+1);
      blurs[i][j] = new R3MeshProperty(mesh, name);
    }
  }

  // Compute multiscale properties
  for (int k = 0; k < mesh->NVertices(); k++) {
    R3MeshVertex *vertex = mesh->Vertex(k);

    // Compute distances
    RNLength *distances = mesh->DijkstraDistances(vertex);

    // Consider all properties
    for (int i = 0; i < subset.NEntries(); i++) {
      RNScalar sigma = sigma0;
      for (int j = 0; j < nscales; j++) {
        // Compute blurred values
        RNScalar total_value = 0;
        RNScalar total_weight = 0;
        RNScalar denom = -2 * sigma * sigma;
        for (int m = 0; m < mesh->NVertices(); m++) {
          RNLength distance = distances[m];
          if (distance > 3 * sigma) continue;
          RNScalar value = subset[i]->VertexValue(m);;
          RNScalar weight = exp(distance * distance / denom); 
          total_value += weight * value;
          total_weight += weight;
        }

        // Assign blurred value (normalized by total weight)
        if (total_weight > 0) {
          blurs[i][j]->SetVertexValue(k, total_value / total_weight);
        }

        // Update sigma
        sigma *= scale_factor;
      }
    }

    // Delete distances
    delete [] distances;
  }

  // Insert multiscale properties
  for (int i = 0; i < subset.NEntries(); i++) {
    for (int j = 0; j < nscales; j++) {
      properties->Insert(blurs[i][j]);
    }
  }
}

// Assembly:
subq $0x1158, %rsp           # imm = 0x1158
movq %rdi, 0x1150(%rsp)
movq %rsi, 0x1148(%rsp)
movq %rdx, 0x1140(%rsp)
movq %rcx, 0x1138(%rsp)
movq 0x1150(%rsp), %rdi
callq 0x13470
movq %rax, 0x1130(%rsp)
movq 0x1138(%rsp), %rax
movq (%rax), %rax
movq (%rax), %rdi
callq 0xd530
movsd %xmm0, 0x68(%rsp)
movq 0x1130(%rsp), %rdi
callq 0x133e0
movaps %xmm0, %xmm1
movsd 0x68(%rsp), %xmm0
mulsd %xmm1, %xmm0
movsd %xmm0, 0x1128(%rsp)
movq 0x1138(%rsp), %rax
movq (%rax), %rax
movq 0x8(%rax), %rdi
callq 0xd530
movsd %xmm0, 0x1120(%rsp)
movq 0x1138(%rsp), %rax
movq (%rax), %rax
movq 0x10(%rax), %rdi
callq 0xd610
movl %eax, 0x111c(%rsp)
movq 0x1140(%rsp), %rax
movl (%rax), %ecx
subl $0x3, %ecx
movl %ecx, (%rax)
movq 0x1138(%rsp), %rax
movq (%rax), %rcx
addq $0x18, %rcx
movq %rcx, (%rax)
movsd 0x1128(%rsp), %xmm0
xorps %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jne 0x114ea
jp 0x114ea
jmp 0x11afe
movsd 0x1120(%rsp), %xmm0
xorps %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jne 0x11503
jp 0x11503
jmp 0x11afe
cmpl $0x0, 0x111c(%rsp)
jne 0x11512
jmp 0x11afe
movq 0x1150(%rsp), %rsi
movq 0x1148(%rsp), %rdx
leaq 0x1108(%rsp), %rdi
callq 0x11d60
leaq 0x1108(%rsp), %rdi
callq 0x135d0
cmpl $0x0, %eax
jne 0x11551
movl $0x1, 0x1104(%rsp)
jmp 0x11af1
leaq 0x1108(%rsp), %rdi
callq 0x135d0
cltq
movl $0x8, %ecx
mulq %rcx
movq %rax, %rdi
movq $-0x1, %rax
cmovoq %rax, %rdi
callq 0xd030
movq %rax, 0x60(%rsp)
jmp 0x11582
movq 0x60(%rsp), %rax
movq %rax, 0xf8(%rsp)
movl $0x0, 0xe8(%rsp)
movl 0xe8(%rsp), %eax
movl %eax, 0x5c(%rsp)
leaq 0x1108(%rsp), %rdi
callq 0x135d0
movl %eax, %ecx
movl 0x5c(%rsp), %eax
cmpl %ecx, %eax
jge 0x1173e
movl 0xe8(%rsp), %esi
leaq 0x1108(%rsp), %rdi
callq 0x13510
movq %rax, 0x50(%rsp)
jmp 0x115db
movq 0x50(%rsp), %rax
movq %rax, 0xe0(%rsp)
movslq 0x111c(%rsp), %rax
movl $0x8, %ecx
mulq %rcx
movq %rax, %rdi
movq $-0x1, %rax
cmovoq %rax, %rdi
callq 0xd030
movq %rax, 0x48(%rsp)
jmp 0x11612
movq 0x48(%rsp), %rdx
movq 0xf8(%rsp), %rax
movslq 0xe8(%rsp), %rcx
movq %rdx, (%rax,%rcx,8)
movl $0x0, 0xdc(%rsp)
movl 0xdc(%rsp), %eax
cmpl 0x111c(%rsp), %eax
jge 0x11726
movq 0xe0(%rsp), %rdi
callq 0x13600
movq %rax, %rdx
movl 0xdc(%rsp), %ecx
incl %ecx
leaq 0x93dfa(%rip), %rsi     # 0xa5464
xorl %eax, %eax
leaq 0x100(%rsp), %rdi
callq 0xd0e0
movl $0x448, %edi            # imm = 0x448
callq 0xd400
movq %rax, 0x40(%rsp)
jmp 0x1168a
movq 0x40(%rsp), %rdi
movq 0x1130(%rsp), %rsi
xorl %eax, %eax
movl %eax, %ecx
leaq 0x100(%rsp), %rdx
callq 0x16a70
jmp 0x116aa
movq 0x40(%rsp), %rdx
movq 0xf8(%rsp), %rax
movslq 0xe8(%rsp), %rcx
movq (%rax,%rcx,8), %rax
movslq 0xdc(%rsp), %rcx
movq %rdx, (%rax,%rcx,8)
movl 0xdc(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xdc(%rsp)
jmp 0x11636
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xf0(%rsp)
movl %eax, 0xec(%rsp)
jmp 0x11b06
movq 0x40(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xf0(%rsp)
movl %eax, 0xec(%rsp)
movl $0x448, %esi            # imm = 0x448
callq 0xd410
jmp 0x11b06
jmp 0x11728
movl 0xe8(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xe8(%rsp)
jmp 0x1159a
movl $0x0, 0xd8(%rsp)
movl 0xd8(%rsp), %eax
movl %eax, 0x3c(%rsp)
movq 0x1130(%rsp), %rdi
callq 0x135b0
movl %eax, %ecx
movl 0x3c(%rsp), %eax
cmpl %ecx, %eax
jge 0x11a63
movq 0x1130(%rsp), %rdi
movl 0xd8(%rsp), %esi
callq 0x13750
movq %rax, 0x30(%rsp)
jmp 0x1178a
movq 0x30(%rsp), %rax
movq %rax, 0xd0(%rsp)
movq 0x1130(%rsp), %rdi
movq 0xd0(%rsp), %rsi
xorl %eax, %eax
movl %eax, %edx
xorps %xmm0, %xmm0
callq 0x31750
movq %rax, 0x28(%rsp)
jmp 0x117ba
movq 0x28(%rsp), %rax
movq %rax, 0xc8(%rsp)
movl $0x0, 0xc4(%rsp)
movl 0xc4(%rsp), %eax
movl %eax, 0x24(%rsp)
leaq 0x1108(%rsp), %rdi
callq 0x135d0
movl %eax, %ecx
movl 0x24(%rsp), %eax
cmpl %ecx, %eax
jge 0x11a2e
movsd 0x1128(%rsp), %xmm0
movsd %xmm0, 0xb8(%rsp)
movl $0x0, 0xb4(%rsp)
movl 0xb4(%rsp), %eax
cmpl 0x111c(%rsp), %eax
jge 0x11a16
xorps %xmm0, %xmm0
movsd %xmm0, 0xa8(%rsp)
xorps %xmm0, %xmm0
movsd %xmm0, 0xa0(%rsp)
movsd 0x937bf(%rip), %xmm0    # 0xa5008
mulsd 0xb8(%rsp), %xmm0
mulsd 0xb8(%rsp), %xmm0
movsd %xmm0, 0x98(%rsp)
movl $0x0, 0x94(%rsp)
movl 0x94(%rsp), %eax
movl %eax, 0x20(%rsp)
movq 0x1130(%rsp), %rdi
callq 0x135b0
movl %eax, %ecx
movl 0x20(%rsp), %eax
cmpl %ecx, %eax
jge 0x1198d
movq 0xc8(%rsp), %rax
movslq 0x94(%rsp), %rcx
movsd (%rax,%rcx,8), %xmm0
movsd %xmm0, 0x88(%rsp)
movsd 0x88(%rsp), %xmm0
movsd 0x9374c(%rip), %xmm1    # 0xa5010
mulsd 0xb8(%rsp), %xmm1
ucomisd %xmm1, %xmm0
jbe 0x118d8
jmp 0x11977
movl 0xc4(%rsp), %esi
leaq 0x1108(%rsp), %rdi
callq 0x13610
movq %rax, 0x18(%rsp)
jmp 0x118f3
movq 0x18(%rsp), %rax
movq (%rax), %rdi
movl 0x94(%rsp), %esi
callq 0x13730
movsd %xmm0, 0x80(%rsp)
movsd 0x88(%rsp), %xmm0
mulsd 0x88(%rsp), %xmm0
divsd 0x98(%rsp), %xmm0
callq 0xd700
movsd %xmm0, 0x78(%rsp)
movsd 0x78(%rsp), %xmm0
movsd 0x80(%rsp), %xmm2
movsd 0xa8(%rsp), %xmm1
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, 0xa8(%rsp)
movsd 0x78(%rsp), %xmm0
addsd 0xa0(%rsp), %xmm0
movsd %xmm0, 0xa0(%rsp)
movl 0x94(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x94(%rsp)
jmp 0x1186f
movsd 0xa0(%rsp), %xmm0
xorps %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jbe 0x119e5
movq 0xf8(%rsp), %rax
movslq 0xc4(%rsp), %rcx
movq (%rax,%rcx,8), %rax
movslq 0xb4(%rsp), %rcx
movq (%rax,%rcx,8), %rdi
movl 0xd8(%rsp), %esi
movsd 0xa8(%rsp), %xmm0
movsd 0xa0(%rsp), %xmm1
divsd %xmm1, %xmm0
callq 0x199d0
jmp 0x119e3
jmp 0x119e5
movsd 0x1120(%rsp), %xmm0
mulsd 0xb8(%rsp), %xmm0
movsd %xmm0, 0xb8(%rsp)
movl 0xb4(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xb4(%rsp)
jmp 0x11815
jmp 0x11a18
movl 0xc4(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xc4(%rsp)
jmp 0x117d2
movq 0xc8(%rsp), %rax
movq %rax, 0x10(%rsp)
cmpq $0x0, %rax
je 0x11a4b
movq 0x10(%rsp), %rdi
callq 0xd550
jmp 0x11a4d
movl 0xd8(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xd8(%rsp)
jmp 0x11749
movl $0x0, 0x74(%rsp)
movl 0x74(%rsp), %eax
movl %eax, 0xc(%rsp)
leaq 0x1108(%rsp), %rdi
callq 0x135d0
movl %eax, %ecx
movl 0xc(%rsp), %eax
cmpl %ecx, %eax
jge 0x11ae6
movl $0x0, 0x70(%rsp)
movl 0x70(%rsp), %eax
cmpl 0x111c(%rsp), %eax
jge 0x11ad7
movq 0x1150(%rsp), %rdi
movq 0xf8(%rsp), %rax
movslq 0x74(%rsp), %rcx
movq (%rax,%rcx,8), %rax
movslq 0x70(%rsp), %rcx
movq (%rax,%rcx,8), %rsi
callq 0x138e0
jmp 0x11ac8
jmp 0x11aca
movl 0x70(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x70(%rsp)
jmp 0x11a92
jmp 0x11ad9
movl 0x74(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x74(%rsp)
jmp 0x11a6b
movl $0x0, 0x1104(%rsp)
leaq 0x1108(%rsp), %rdi
callq 0x13630
addq $0x1158, %rsp           # imm = 0x1158
retq
leaq 0x1108(%rsp), %rdi
callq 0x13630
movq 0xf0(%rsp), %rdi
callq 0xd6d0