// File: /workspace/github_cpp_makefile_star2_O2/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 0x2a8ec
movq %rdi, %r14
movq 0x1a0(%rdi), %rdi
testq %rdi, %rdi
je 0x2a8ec
movq %rsi, %rbx
leaq 0xafe3a(%rip), %rsi     # 0xda6ec
pushq $0x5
popq %rdx
callq 0x223c0
testl %eax, %eax
jne 0x2a8ec
cmpl $0x3, 0x2c(%r14)
jl 0x2a8ec
movq 0x20(%r14), %r13
movq (%r13), %r15
movq 0x1a0(%r15), %rdi
testq %rdi, %rdi
je 0x2a8ec
leaq 0xafe29(%rip), %rsi     # 0xda709
pushq $0x6
popq %rdx
callq 0x223c0
testl %eax, %eax
je 0x2a900
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 0x2a8ec
leaq 0xafdf8(%rip), %rsi     # 0xda710
pushq $0x8
popq %rdx
callq 0x223c0
testl %eax, %eax
jne 0x2a8ec
movq 0x10(%r13), %rax
movq 0x1a0(%rax), %rdi
testq %rdi, %rdi
je 0x2a8ec
leaq 0xafdde(%rip), %rsi     # 0xda719
pushq $0x5
popq %rdx
callq 0x223c0
testl %eax, %eax
jne 0x2a8ec
movq %r14, %rdi
callq 0x3d966
leaq 0x38(%rsp), %rdi
movq %rax, %rsi
callq 0x6af06
movq %r15, %rdi
callq 0x3d966
leaq 0xa8(%rsp), %rdi
movq %rax, %rsi
callq 0x6af06
movq %r12, %rdi
callq 0x3d966
leaq 0xe0(%rsp), %rdi
movq %rax, %rsi
callq 0x6af06
movsd 0x125f34(%rip), %xmm0   # 0x1508c8
movaps %xmm0, (%rsp)
movsd 0x40(%rsp), %xmm1
movsd 0x50(%rsp), %xmm0
movsd 0x68(%rsp), %xmm2
movsd 0x58(%rsp), %xmm3
leaq 0x10(%rsp), %rdi
callq 0x882ba
movapd (%rsp), %xmm2
mulsd 0xaf641(%rip), %xmm2    # 0xda008
xorpd %xmm0, %xmm0
cmpeqsd %xmm2, %xmm0
movsd 0xaf6d8(%rip), %xmm1    # 0xda0b0
andpd %xmm0, %xmm1
andnpd %xmm2, %xmm0
orpd %xmm1, %xmm0
movsd 0xaf644(%rip), %xmm2    # 0xda030
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 0xaf6ce(%rip), %xmm1    # 0xda0f0
movmskpd %xmm1, %eax
xorl %ebp, %ebp
xorl $0x3, %eax
jne 0x2abf5
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 0x7cbde
leaq 0x1e8(%rsp), %rdi
leaq 0xa8(%rsp), %rdx
movq %r15, %rsi
callq 0x2aca9
leaq 0x1e8(%rsp), %rdi
movq 0xaf58a(%rip), %xmm0    # 0xda008
movsd 0xaf5fa(%rip), %xmm2    # 0xda080
xorpd %xmm1, %xmm1
callq 0x7ee70
leaq 0x118(%rsp), %rdi
leaq 0x10(%rsp), %rcx
movl %ebp, %esi
movl %r13d, %edx
callq 0x7cbde
leaq 0x70(%rsp), %rdi
leaq 0x38(%rsp), %rsi
callq 0x6af06
movslq 0x120ed4(%rip), %rax    # 0x14b990
leaq 0x121615(%rip), %rcx    # 0x14c0d8
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)
xorl %r13d, %r13d
leaq 0x70(%rsp), %rbp
movslq 0x2c(%r14), %rax
cmpq %rax, %r13
jge 0x2ab2e
movq 0x20(%r14), %rax
movq (%rax,%r13,8), %rsi
cmpq %r15, %rsi
sete %al
cmpq %r12, %rsi
sete %cl
orb %al, %cl
jne 0x2ab29
leaq 0x118(%rsp), %rdi
movq %rbp, %rdx
callq 0x2aca9
incq %r13
jmp 0x2aaf8
xorl %r13d, %r13d
leaq 0x118(%rsp), %r15
leaq 0x70(%rsp), %r12
movq 0x10(%r14), %rax
movslq 0x2c(%rax), %rcx
cmpq %rcx, %r13
jge 0x2ab69
movq 0x20(%rax), %rax
movq (%rax,%r13,8), %rsi
cmpl $0x0, 0x2c(%rsi)
jg 0x2ab64
movq %r15, %rdi
movq %r12, %rdx
callq 0x2aca9
incq %r13
jmp 0x2ab3e
leaq 0x118(%rsp), %rdi
movsd 0xaf48f(%rip), %xmm0    # 0xda008
movsd 0xaf4ff(%rip), %xmm1    # 0xda080
xorpd %xmm2, %xmm2
callq 0x7ee70
movsd 0x125d36(%rip), %xmm0   # 0x1508c8
ucomisd 0xaf50e(%rip), %xmm0    # 0xda0a8
jbe 0x2abae
divsd (%rsp), %xmm0
leaq 0x118(%rsp), %rdi
callq 0x7eeca
leaq 0x1e8(%rsp), %rsi
movq %rbx, %rdi
callq 0x7d3b6
leaq 0x118(%rsp), %rsi
movq %rbx, %rdi
callq 0x810f0
leaq 0x70(%rsp), %rdi
callq 0x6bbbe
leaq 0x118(%rsp), %rdi
callq 0x7d64c
leaq 0x1e8(%rsp), %rdi
callq 0x7d64c
pushq $0x1
popq %rbp
leaq 0x10(%rsp), %rdi
callq 0x88a2e
leaq 0xe0(%rsp), %rdi
callq 0x6bbbe
leaq 0xa8(%rsp), %rdi
callq 0x6bbbe
leaq 0x38(%rsp), %rdi
callq 0x6bbbe
jmp 0x2a8ec
movq %rax, %rbx
jmp 0x2ac59
jmp 0x2ac34
movq %rax, %rbx
jmp 0x2ac73
movq %rax, %rbx
jmp 0x2ac66
movq %rax, %rbx
jmp 0x2ac7d
jmp 0x2ac4c
movq %rax, %rbx
jmp 0x2ac8a
movq %rax, %rbx
jmp 0x2ac97
jmp 0x2ac4c
movq %rax, %rbx
leaq 0x70(%rsp), %rdi
callq 0x6bbbe
leaq 0x118(%rsp), %rdi
callq 0x7d64c
leaq 0x1e8(%rsp), %rdi
callq 0x7d64c
leaq 0x10(%rsp), %rdi
callq 0x88a2e
leaq 0xe0(%rsp), %rdi
callq 0x6bbbe
leaq 0xa8(%rsp), %rdi
callq 0x6bbbe
leaq 0x38(%rsp), %rdi
callq 0x6bbbe
movq %rbx, %rdi
callq 0x230b0