// File: /workspace/github_cpp_makefile_star2_O2/tomfunkhouser[P]gaps/pkgs/RGBD/RGBDUtil.cpp
// Function: gaps::RGBDCreateBoundaryChannel(gaps::R2Grid const&, gaps::R2Grid&, double)
int RGBDCreateBoundaryChannel(
  const R2Grid& input_depth_image, R2Grid& output_boundary_image,
  RNScalar depth_threshold)
{
  // Initialize position images
  output_boundary_image = input_depth_image; 
  output_boundary_image.Clear(R2_GRID_UNKNOWN_VALUE);

  // Mark bottom and top border boundaries
  for (int i = 0; i < output_boundary_image.XResolution(); i++) {
    for (int j = 0; j < output_boundary_image.YResolution(); j++) {
      output_boundary_image.SetGridValue(i, j, RGBD_BORDER_BOUNDARY);
      if (RNIsPositive(input_depth_image.GridValue(i, j))) break;
    }
    for (int j = output_boundary_image.YResolution()-1; j >= 0; j--) {
      output_boundary_image.SetGridValue(i, j, RGBD_BORDER_BOUNDARY);
      if (RNIsPositive(input_depth_image.GridValue(i, j))) break;
    }
  }

  // Mark left and right border boundaries
  for (int j = 0; j < output_boundary_image.YResolution(); j++) {
    for (int i = 0; i < output_boundary_image.XResolution(); i++) {
      output_boundary_image.SetGridValue(i, j, RGBD_BORDER_BOUNDARY);
      if (RNIsPositive(input_depth_image.GridValue(i, j))) break;
    }
    for (int i = output_boundary_image.XResolution()-1; i >= 0; i--) {
      output_boundary_image.SetGridValue(i, j, RGBD_BORDER_BOUNDARY);
      if (RNIsPositive(input_depth_image.GridValue(i, j))) break;
    }
  }

  // Create copy of depth image with holes filled
  R2Grid filled_input_depth_image(input_depth_image);
  filled_input_depth_image.Substitute(0, R2_GRID_UNKNOWN_VALUE);
  filled_input_depth_image.FillHoles();

  // Mark interior boundaries, silhouettes, and shadows
  for (int i = 1; i < output_boundary_image.XResolution()-1; i++) {
    for (int j = 1; j < output_boundary_image.YResolution()-1; j++) {
      // Get original depth
      RNScalar depth = input_depth_image.GridValue(i, j);

      // Check if in hole
      if (RNIsNegativeOrZero(depth)) {
        output_boundary_image.SetGridValue(i, j, RGBD_BORDER_BOUNDARY);
        continue;
      }

      // Get filled depth
      depth = filled_input_depth_image.GridValue(i, j);
      if (RNIsNegativeOrZero(depth)) continue;

      // Check depth relative to neighbors
      for (int k = 0; k < 4; k++) {
        int s = (k < 3) ? -1 : 0;
        int t = (k < 3) ? k-1 : -1;

        // Get depth on one side
        RNScalar depthA = filled_input_depth_image.GridValue(i-s, j-t);
        if (RNIsNegativeOrZero(depthA)) {
          output_boundary_image.SetGridValue(i, j, RGBD_BORDER_BOUNDARY);
          break;
        }

        // Get depth on other side
        RNScalar depthB = filled_input_depth_image.GridValue(i+s, j+t);
        if (RNIsNegativeOrZero(depthB)) {
          output_boundary_image.SetGridValue(i, j, RGBD_BORDER_BOUNDARY);
          break;
        }

        // Check differences of depth for shadow/silhouette
        RNScalar deltaA = depth - depthA;
        RNScalar deltaB = depthB - depth;
        RNScalar threshold = depth * depth_threshold;
        if (threshold < 0.1) threshold = 0.1;
        if (deltaA < -threshold) {
          if (deltaA < 4*deltaB) {
            output_boundary_image.SetGridValue(i-s, j-t, RGBD_SHADOW_BOUNDARY);
            output_boundary_image.SetGridValue(i, j, RGBD_SILHOUETTE_BOUNDARY);
          }
        }
        else if (deltaA > threshold) {
          if (deltaA > 4*deltaB) {
            output_boundary_image.SetGridValue(i-s, j-t, RGBD_SILHOUETTE_BOUNDARY);
            output_boundary_image.SetGridValue(i, j, RGBD_SHADOW_BOUNDARY);
          }
        }
        if (deltaB < -threshold) {
          if (deltaB < 4*deltaA) {
            output_boundary_image.SetGridValue(i+s, j+t, RGBD_SILHOUETTE_BOUNDARY);
            output_boundary_image.SetGridValue(i, j, RGBD_SHADOW_BOUNDARY);
          }
        }
        else if (deltaB > threshold) {
          if (deltaB > 4*deltaA) {
            output_boundary_image.SetGridValue(i+s, j+t, RGBD_SHADOW_BOUNDARY);
            output_boundary_image.SetGridValue(i, j, RGBD_SILHOUETTE_BOUNDARY);
          }
        }
      }
    }
  }

  // Return success 
  return 1;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x128, %rsp            # imm = 0x128
movsd %xmm0, 0x20(%rsp)
movq %rsi, %rbx
movq %rdi, %rsi
movq %rbx, %rdi
movq %rsi, 0x10(%rsp)
callq 0x5872a
movsd 0x87e92(%rip), %xmm0    # 0xa8010
movq %rbx, %rdi
callq 0x59dcc
movslq 0xc0(%rbx), %rax
movq %rbx, 0x8(%rsp)
movslq 0xc4(%rbx), %rsi
xorl %edi, %edi
testl %esi, %esi
movl $0x0, %ecx
cmovgl %esi, %ecx
testl %eax, %eax
movl $0x0, %edx
cmovgl %eax, %edx
leaq 0x1(%rcx), %r8
leaq -0x8(,%rsi,8), %r9
incq %rsi
movabsq $0x3ff0000000000000, %r13 # imm = 0x3FF0000000000000
xorl %r10d, %r10d
cmpq %rdx, %r10
je 0x202a6
movq 0x8(%rsp), %r15
movslq 0xc8(%r15), %r11
movq 0x10(%rsp), %r14
movslq 0xc8(%r14), %rbx
movq 0xb8(%r14), %r14
addq %rdi, %r14
shlq $0x3, %rbx
movq 0xb8(%r15), %r15
addq %rdi, %r15
shlq $0x3, %r11
movq %r8, %r12
decq %r12
je 0x2022c
movq %r13, (%r15)
addq %r11, %r15
movsd (%r14), %xmm0
addq %rbx, %r14
leaq 0xd7ad3(%rip), %rbp     # 0xf7cf8
ucomisd (%rbp), %xmm0
jbe 0x2020b
movq 0x8(%rsp), %r12
movslq 0xc8(%r12), %r11
movq 0x10(%rsp), %r15
movslq 0xc8(%r15), %rbx
movq %r9, %r14
imulq %rbx, %r14
addq %rdi, %r14
addq 0xb8(%r15), %r14
shlq $0x3, %rbx
movq %r9, %r15
imulq %r11, %r15
addq %rdi, %r15
addq 0xb8(%r12), %r15
negq %rbx
shlq $0x3, %r11
negq %r11
movq %rsi, %r12
decq %r12
jle 0x2029a
movq %r13, (%r15)
addq %r11, %r15
movsd (%r14), %xmm0
addq %rbx, %r14
leaq 0xd7a65(%rip), %rbp     # 0xf7cf8
ucomisd (%rbp), %xmm0
jbe 0x20279
incq %r10
addq $0x8, %rdi
jmp 0x201cb
xorl %esi, %esi
cmpl %ecx, %esi
je 0x2037c
movq 0x10(%rsp), %r8
movl 0xc8(%r8), %edi
imull %esi, %edi
movslq %edi, %rdi
shlq $0x3, %rdi
addq 0xb8(%r8), %rdi
movq 0x8(%rsp), %r9
movl 0xc8(%r9), %r8d
imull %esi, %r8d
movslq %r8d, %r8
shlq $0x3, %r8
addq 0xb8(%r9), %r8
xorl %r9d, %r9d
cmpq %r9, %rdx
je 0x2030e
movq %r13, (%r8,%r9,8)
movsd (%rdi,%r9,8), %xmm0
incq %r9
leaq 0xd79f1(%rip), %r10     # 0xf7cf8
ucomisd (%r10), %xmm0
jbe 0x202ee
movq 0x8(%rsp), %r10
movq 0xb8(%r10), %r8
movq 0x10(%rsp), %r9
movq 0xb8(%r9), %rdi
movl 0xc8(%r9), %r9d
imull %esi, %r9d
movslq %r9d, %r9
leaq (%rdi,%r9,8), %rdi
addq $-0x8, %rdi
movl 0xc8(%r10), %r9d
imull %esi, %r9d
movslq %r9d, %r9
leaq (%r8,%r9,8), %r8
addq $-0x8, %r8
movq %rax, %r9
testq %r9, %r9
jle 0x20375
movq %r13, (%r8,%r9,8)
movsd (%rdi,%r9,8), %xmm0
decq %r9
leaq 0xd798a(%rip), %r10     # 0xf7cf8
ucomisd (%r10), %xmm0
jbe 0x20355
incl %esi
jmp 0x202a8
leaq 0x58(%rsp), %r15
movq %r15, %rdi
movq 0x10(%rsp), %rsi
callq 0x58808
movsd 0x87c7a(%rip), %xmm1    # 0xa8010
xorpd %xmm0, %xmm0
movq %r15, %rdi
callq 0x5c1ba
leaq 0x58(%rsp), %rdi
callq 0x594e0
movq 0x8(%rsp), %rax
movslq 0xc0(%rax), %rcx
decq %rcx
movq %rcx, 0x18(%rsp)
movslq 0xc4(%rax), %rax
decq %rax
movq %rax, 0x50(%rsp)
pushq $0x1
popq %r8
movsd 0x87c55(%rip), %xmm0    # 0xa8030
movapd 0x87c6d(%rip), %xmm1    # 0xa8050
movsd 0x88c25(%rip), %xmm2    # 0xa9010
movsd 0x88c0d(%rip), %xmm3    # 0xa9000
cmpq 0x18(%rsp), %r8
jge 0x20638
movq 0x10(%rsp), %rcx
movslq 0xc8(%rcx), %rax
movq %rax, 0x48(%rsp)
movq 0x8(%rsp), %rax
movslq 0xc8(%rax), %rdx
movq %rdx, 0x38(%rsp)
movq 0x110(%rsp), %r11
movslq 0x120(%rsp), %r15
leaq (,%r8,8), %rdx
movq 0xb8(%rcx), %rcx
addq %rdx, %rcx
movq %rcx, 0x40(%rsp)
leaq (%r11,%r8,8), %rcx
movq %rcx, 0x28(%rsp)
addq 0xb8(%rax), %rdx
movq %rdx, 0x30(%rsp)
pushq $0x1
popq %rsi
cmpq 0x50(%rsp), %rsi
jge 0x20630
movq %rsi, %rax
imulq 0x48(%rsp), %rax
leaq 0xd787e(%rip), %rcx     # 0xf7cf8
movsd (%rcx), %xmm5
movq 0x40(%rsp), %rcx
ucomisd (%rcx,%rax,8), %xmm5
jae 0x2060c
movq %rsi, %rax
imulq %r15, %rax
movq 0x28(%rsp), %rcx
movsd (%rcx,%rax,8), %xmm4
ucomisd %xmm4, %xmm5
jae 0x20628
movapd %xmm4, %xmm6
mulsd 0x20(%rsp), %xmm6
movapd %xmm0, %xmm5
maxsd %xmm6, %xmm5
movapd %xmm5, %xmm6
xorpd %xmm1, %xmm6
movq 0x8(%rsp), %rax
movq 0xb8(%rax), %r14
movl 0xc8(%rax), %ebx
movl %ebx, %eax
imull %esi, %eax
cltq
leaq (%r14,%r8,8), %r12
xorl %r10d, %r10d
pushq $0x4
popq %rbp
subl $0x1, %ebp
jb 0x20628
leal -0x1(%r10), %ecx
xorl %r9d, %r9d
cmpl $0x3, %r10d
pushq $-0x1
popq %rdx
cmovel %edx, %ecx
setne %r9b
leal (%r8,%r9), %edx
movl %esi, %r13d
subl %ecx, %r13d
movl %r13d, %edi
imull %r15d, %edi
addl %edx, %edi
movslq %edi, %rdi
movsd (%r11,%rdi,8), %xmm9
leaq 0xd77d1(%rip), %rdi     # 0xf7cf8
movsd (%rdi), %xmm8
ucomisd %xmm9, %xmm8
jae 0x2060c
negl %r9d
addl %r8d, %r9d
addl %esi, %ecx
movl %ecx, %edi
imull %r15d, %edi
addl %r9d, %edi
movslq %edi, %rdi
movsd (%r11,%rdi,8), %xmm7
ucomisd %xmm7, %xmm8
jae 0x2060c
movapd %xmm4, %xmm8
subsd %xmm9, %xmm8
subsd %xmm4, %xmm7
ucomisd %xmm8, %xmm6
movapd %xmm7, %xmm9
mulsd %xmm2, %xmm9
jbe 0x2058e
ucomisd %xmm8, %xmm9
movapd %xmm2, %xmm9
movapd %xmm3, %xmm10
ja 0x205a6
jmp 0x205bc
ucomisd %xmm5, %xmm8
jbe 0x205bc
ucomisd %xmm9, %xmm8
movapd %xmm3, %xmm9
movapd %xmm2, %xmm10
jbe 0x205bc
imull %ebx, %r13d
addl %edx, %r13d
movslq %r13d, %rdx
movsd %xmm9, (%r14,%rdx,8)
movsd %xmm10, (%r12,%rax,8)
ucomisd %xmm7, %xmm6
mulsd %xmm2, %xmm8
jbe 0x205d9
ucomisd %xmm7, %xmm8
movapd %xmm3, %xmm7
movapd %xmm2, %xmm8
ja 0x205ef
jmp 0x20604
ucomisd %xmm5, %xmm7
jbe 0x20604
ucomisd %xmm8, %xmm7
movapd %xmm2, %xmm7
movapd %xmm3, %xmm8
jbe 0x20604
imull %ebx, %ecx
addl %r9d, %ecx
movslq %ecx, %rcx
movsd %xmm7, (%r14,%rcx,8)
movsd %xmm8, (%r12,%rax,8)
incl %r10d
jmp 0x204e6
movq %rsi, %rax
imulq 0x38(%rsp), %rax
movabsq $0x3ff0000000000000, %rcx # imm = 0x3FF0000000000000
movq 0x30(%rsp), %rdx
movq %rcx, (%rdx,%rax,8)
incq %rsi
jmp 0x2045f
incq %r8
jmp 0x203f3
leaq 0x58(%rsp), %rdi
callq 0x589c0
pushq $0x1
popq %rax
addq $0x128, %rsp            # imm = 0x128
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %rax, %rbx
leaq 0x58(%rsp), %rdi
callq 0x589c0
movq %rbx, %rdi
callq 0x11a80