// File: /workspace/github_cpp_makefile_star2_O3/tomfunkhouser[P]gaps/apps/scn2cam/scn2cam.cpp
// Function: ComputeViewpointMask(gaps::R3SceneNode*, gaps::R2Grid&)
static int
ComputeViewpointMask(R3SceneNode *room_node, R2Grid& mask) 
{
  // Get/check room, wall, floor, and ceiling nodes 
  if (!room_node) return 0;
  if (!room_node->Name()) return 0;
  if (strncmp(room_node->Name(), "Room#", 5)) return 0;
  if (room_node->NChildren() < 3) return 0;
  R3SceneNode *floor_node = room_node->Child(0);
  if (!floor_node->Name()) return 0;
  if (strncmp(floor_node->Name(), "Floor#", 6)) return 0;
  R3SceneNode *ceiling_node = room_node->Child(1);
  if (!ceiling_node->Name()) return 0;
  if (strncmp(ceiling_node->Name(), "Ceiling#", 8)) return 0;
  R3SceneNode *wall_node = room_node->Child(2);
  if (!wall_node->Name()) return 0;
  if (strncmp(wall_node->Name(), "Wall#", 5)) return 0;

  // Get bounding boxes in world coordinates
  R3Box room_bbox = room_node->BBox();
  R3Box floor_bbox = floor_node->BBox();
  R3Box ceiling_bbox = ceiling_node->BBox();

  // Get/check grid extent and resolution in world coordinates
  RNScalar grid_sampling_factor = 2;
  RNScalar grid_sample_spacing = min_distance_from_obstacle / grid_sampling_factor;
  if (grid_sample_spacing == 0) grid_sample_spacing = 0.05;
  if (grid_sample_spacing > 0.1) grid_sample_spacing = 0.1;
  R2Box grid_bbox(room_bbox.ZMin(), room_bbox.XMin(), room_bbox.ZMax(), room_bbox.XMax());
  int res1 = (int) (grid_bbox.XLength() / grid_sample_spacing);
  int res2 = (int) (grid_bbox.YLength() / grid_sample_spacing);
  if ((res1 < 3) || (res2 < 3)) return 0;

  // Compute floor mask
  R2Grid floor_mask = R2Grid(res1, res2, grid_bbox);
  RasterizeIntoZXGrid(floor_mask, floor_node, floor_bbox);
  floor_mask.Threshold(0.5, 0, 1);

  // Initialize object mask
  R2Grid object_mask = R2Grid(res1, res2, grid_bbox);
  R3Box object_bbox = room_bbox;
  object_bbox[RN_LO][gravity_dimension] = floor_bbox[RN_HI][gravity_dimension] + RN_EPSILON;
  object_bbox[RN_HI][gravity_dimension] = ceiling_bbox[RN_LO][gravity_dimension] - RN_EPSILON;

  // Rasterize objects associated with this room into object mask
  for (int i = 0; i < room_node->NChildren(); i++) {
    R3SceneNode *node = room_node->Child(i);
    if ((node == floor_node) || (node == ceiling_node)) continue;
    RasterizeIntoZXGrid(object_mask, node, object_bbox);
  }

  // Rasterize objects associated with no room into object mask
  for (int i = 0; i < room_node->Parent()->NChildren(); i++) {
    R3SceneNode *node = room_node->Parent()->Child(i);
    if (node->NChildren() > 0) continue;
    RasterizeIntoZXGrid(object_mask, node, object_bbox);
  }
  
  // Reverse object mask to by 1 in areas not occupied by objects
  object_mask.Threshold(0.5, 1, 0);

  // Erode object mask to cover viewpoints at least min_distance_from_obstacle
  if (min_distance_from_obstacle > 0) {
    object_mask.Erode(min_distance_from_obstacle / grid_sample_spacing);
  }

  // Combine the two masks
  mask = floor_mask;
  mask.Mask(object_mask);
  
#if 0
  // Debugging
  char buffer[4096];
  sprintf(buffer, "%s_floor_mask.jpg", room_node->Name());
  floor_mask.WriteFile(buffer);
  sprintf(buffer, "%s_object_mask.jpg", room_node->Name());
  object_mask.WriteFile(buffer);
  sprintf(buffer, "%s_mask.jpg", room_node->Name());
  mask.WriteFile(buffer);
#endif
  
  // Return success
  return 1;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x2b8, %rsp            # imm = 0x2B8
xorl %ebp, %ebp
testq %rdi, %rdi
je 0x2bd29
movq %rdi, %r14
movq 0x1a0(%rdi), %rdi
testq %rdi, %rdi
je 0x2bd29
movq %rsi, %rbx
leaq 0xc6a01(%rip), %rsi     # 0xf26ec
movl $0x5, %edx
callq 0x223b0
testl %eax, %eax
jne 0x2bd29
cmpl $0x3, 0x2c(%r14)
jl 0x2bd29
movq 0x20(%r14), %r13
movq (%r13), %r15
movq 0x1a0(%r15), %rdi
testq %rdi, %rdi
je 0x2bd29
leaq 0xc69ee(%rip), %rsi     # 0xf2709
movl $0x6, %edx
callq 0x223b0
testl %eax, %eax
je 0x2bd3d
movl %ebp, %eax
addq $0x2b8, %rsp            # imm = 0x2B8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x8(%r13), %r12
movq 0x1a0(%r12), %rdi
testq %rdi, %rdi
je 0x2bd29
leaq 0xc69bb(%rip), %rsi     # 0xf2710
movl $0x8, %edx
callq 0x223b0
testl %eax, %eax
jne 0x2bd29
movq 0x10(%r13), %rax
movq 0x1a0(%rax), %rdi
testq %rdi, %rdi
je 0x2bd29
leaq 0xc699f(%rip), %rsi     # 0xf2719
movl $0x5, %edx
callq 0x223b0
testl %eax, %eax
jne 0x2bd29
movq %r14, %rdi
callq 0x41d4c
leaq 0x38(%rsp), %rdi
movq %rax, %rsi
callq 0x74908
movq %r15, %rdi
callq 0x41d4c
leaq 0xa8(%rsp), %rdi
movq %rax, %rsi
callq 0x74908
movq %r12, %rdi
callq 0x41d4c
leaq 0xe0(%rsp), %rdi
movq %rax, %rsi
callq 0x74908
movsd 0x135ad3(%rip), %xmm0   # 0x1618a8
movaps %xmm0, (%rsp)
movsd 0x40(%rsp), %xmm1
movsd 0x50(%rsp), %xmm0
movsd 0x68(%rsp), %xmm2
movsd 0x58(%rsp), %xmm3
leaq 0x10(%rsp), %rdi
callq 0x94a40
movapd (%rsp), %xmm2
mulsd 0xc6200(%rip), %xmm2    # 0xf2008
xorpd %xmm0, %xmm0
cmpeqsd %xmm2, %xmm0
movsd 0xc6297(%rip), %xmm1    # 0xf20b0
andpd %xmm0, %xmm1
andnpd %xmm2, %xmm0
orpd %xmm1, %xmm0
movsd 0xc6213(%rip), %xmm2    # 0xf2040
minsd %xmm0, %xmm2
movupd 0x18(%rsp), %xmm0
movupd 0x28(%rsp), %xmm1
subpd %xmm0, %xmm1
movapd %xmm2, (%rsp)
movapd %xmm2, %xmm0
unpcklpd %xmm2, %xmm0            # xmm0 = xmm0[0],xmm2[0]
divpd %xmm0, %xmm1
cvttpd2dq %xmm1, %xmm0
pshufd $0x50, %xmm0, %xmm1     # xmm1 = xmm0[0,0,1,1]
pcmpgtd 0xc628d(%rip), %xmm1    # 0xf20f0
movmskpd %xmm1, %eax
xorl %ebp, %ebp
xorl $0x3, %eax
jne 0x2c049
movd %xmm0, %ebp
pshufd $0x55, %xmm0, %xmm0     # xmm0 = xmm0[1,1,1,1]
movd %xmm0, %r13d
leaq 0x1e8(%rsp), %rdi
leaq 0x10(%rsp), %rcx
movl %ebp, %esi
movl %r13d, %edx
callq 0x8837e
leaq 0x1e8(%rsp), %rdi
leaq 0xa8(%rsp), %rdx
movq %r15, %rsi
callq 0x2c0fd
leaq 0x1e8(%rsp), %rdi
movq 0xc6149(%rip), %xmm0    # 0xf2008
movsd 0xc61d1(%rip), %xmm2    # 0xf2098
xorpd %xmm1, %xmm1
callq 0x8a89a
leaq 0x118(%rsp), %rdi
leaq 0x10(%rsp), %rcx
movl %ebp, %esi
movl %r13d, %edx
callq 0x8837e
leaq 0x70(%rsp), %rdi
leaq 0x38(%rsp), %rsi
callq 0x74908
movslq 0x130a73(%rip), %rax    # 0x15c970
leaq 0x1311b4(%rip), %rcx    # 0x15d0b8
movsd (%rcx), %xmm0
movsd 0xc8(%rsp,%rax,8), %xmm1
addsd %xmm0, %xmm1
movsd %xmm1, 0x78(%rsp,%rax,8)
movsd 0xe8(%rsp,%rax,8), %xmm1
subsd %xmm0, %xmm1
movsd %xmm1, 0x90(%rsp,%rax,8)
movl 0x2c(%r14), %eax
testl %eax, %eax
jle 0x2bf78
xorl %r13d, %r13d
leaq 0x70(%rsp), %rbp
movq 0x20(%r14), %rcx
movq (%rcx,%r13,8), %rsi
cmpq %r15, %rsi
sete %cl
cmpq %r12, %rsi
sete %dl
orb %cl, %dl
jne 0x2bf6d
leaq 0x118(%rsp), %rdi
movq %rbp, %rdx
callq 0x2c0fd
movl 0x2c(%r14), %eax
incq %r13
movslq %eax, %rcx
cmpq %rcx, %r13
jl 0x2bf41
movq 0x10(%r14), %rax
cmpl $0x0, 0x2c(%rax)
jle 0x2bfbb
xorl %r13d, %r13d
leaq 0x118(%rsp), %r15
leaq 0x70(%rsp), %r12
movq 0x20(%rax), %rcx
movq (%rcx,%r13,8), %rsi
cmpl $0x0, 0x2c(%rsi)
jg 0x2bfaf
movq %r15, %rdi
movq %r12, %rdx
callq 0x2c0fd
movq 0x10(%r14), %rax
incq %r13
movslq 0x2c(%rax), %rcx
cmpq %rcx, %r13
jl 0x2bf92
leaq 0x118(%rsp), %rdi
movsd 0xc603d(%rip), %xmm0    # 0xf2008
movsd 0xc60c5(%rip), %xmm1    # 0xf2098
xorpd %xmm2, %xmm2
callq 0x8a89a
movsd 0x1358c4(%rip), %xmm0   # 0x1618a8
ucomisd 0xc60bc(%rip), %xmm0    # 0xf20a8
jbe 0x2c000
divsd (%rsp), %xmm0
leaq 0x118(%rsp), %rdi
callq 0x8a8f6
leaq 0x1e8(%rsp), %rsi
movq %rbx, %rdi
callq 0x88bf6
leaq 0x118(%rsp), %rsi
movq %rbx, %rdi
callq 0x8ce4c
leaq 0x70(%rsp), %rdi
callq 0x75728
leaq 0x118(%rsp), %rdi
callq 0x88eb8
leaq 0x1e8(%rsp), %rdi
callq 0x88eb8
movl $0x1, %ebp
leaq 0x10(%rsp), %rdi
callq 0x952b8
leaq 0xe0(%rsp), %rdi
callq 0x75728
leaq 0xa8(%rsp), %rdi
callq 0x75728
leaq 0x38(%rsp), %rdi
callq 0x75728
jmp 0x2bd29
movq %rax, %rbx
jmp 0x2c0ad
jmp 0x2c088
movq %rax, %rbx
jmp 0x2c0c7
movq %rax, %rbx
jmp 0x2c0ba
movq %rax, %rbx
jmp 0x2c0d1
jmp 0x2c0a0
movq %rax, %rbx
jmp 0x2c0de
movq %rax, %rbx
jmp 0x2c0eb
jmp 0x2c0a0
movq %rax, %rbx
leaq 0x70(%rsp), %rdi
callq 0x75728
leaq 0x118(%rsp), %rdi
callq 0x88eb8
leaq 0x1e8(%rsp), %rdi
callq 0x88eb8
leaq 0x10(%rsp), %rdi
callq 0x952b8
leaq 0xe0(%rsp), %rdi
callq 0x75728
leaq 0xa8(%rsp), %rdi
callq 0x75728
leaq 0x38(%rsp), %rdi
callq 0x75728
movq %rbx, %rdi
callq 0x23090