// File: tomfunkhouser[P]gaps/pkgs/R3Graphics/R3Scene.cpp
// Function: gaps::R3Scene::ReadGrammarHierarchyFile(char const*, gaps::R3SceneNode*)
int R3Scene::
ReadGrammarHierarchyFile(const char *filename, R3SceneNode *parent_node)
{
  // Get/set parent node
  if (!parent_node) parent_node = root;

  // Open file
  FILE *fp;
  if (!(fp = fopen(filename, "r"))) {
    RNFail("Unable to open file %s", filename);
    return 0;
  }

  // Extract base name
  char basename[1024] = { '\0' };
  const char *startp = strrchr(filename, '/');
  if (!startp) startp = filename;
  else startp++;
  const char *endp = strrchr(filename, '.');
  if (!endp) endp = startp + strlen(startp);
  int basename_length = endp - startp;
  if (basename_length > 1023) basename_length = 1023;
  strncpy(basename, startp, basename_length);

  // Read scene
  char buffer[1024];
  int line_count = 0;
  RNBoolean leaf = TRUE;
  RNArray<R3SceneNode *> parsed_nodes;
  R3SceneNode *current_node = NULL;
  while (fgets(buffer, 1023, fp)) {
    // Increment line counter
    line_count++;

    // Skip white space
    char *bufferp = buffer;
    while (isspace(*bufferp)) bufferp++;

    // Skip blank lines and comments
    if (*bufferp == '#') continue;
    if (*bufferp == '\0') continue;

    // Get keyword
    char keyword[256];
    if (sscanf(bufferp, "%s", keyword) != 1) {
      RNFail("Syntax error on line %d in file %s", line_count, filename);
      return 0;
    }

    // Check keyword
    if (!strcmp(keyword, "newModel")) {
      // Read fields
      int model_index;
      if (sscanf(bufferp, "%s%d", keyword, &model_index) != (unsigned int) 2) {
        RNFail("Syntax error on line %d in file %s", line_count, filename);
        return 0;
      }

      // Create node
      while (parsed_nodes.NEntries() <= model_index) {
        char node_name[4096];
        sprintf(node_name, "%d", parsed_nodes.NEntries());
        R3SceneNode *node = new R3SceneNode(this);
        node->SetName(node_name);
        parsed_nodes.Insert(node);
      }

      // Remember current node
      current_node = parsed_nodes.Kth(model_index);
    }
    else if (!strcmp(keyword, "root")) {
      // Read fields
      int root_index;
      if (sscanf(bufferp, "%s%d", keyword, &root_index) != (unsigned int) 2) {
        RNFail("Syntax error on line %d in file %s", line_count, filename);
        return 0;
      }

      // Create node
      while (parsed_nodes.NEntries() <= root_index) {
        char node_name[4096];
        sprintf(node_name, "%d", parsed_nodes.NEntries());
        R3SceneNode *node = new R3SceneNode(this);
        node->SetName(node_name);
        parsed_nodes.Insert(node);
      }

      // Insert root of this parse as child of root
      R3SceneNode *node = parsed_nodes.Kth(root_index);
      parent_node->InsertChild(node);
    }
    else if (!strcmp(keyword, "parent")) {
      // Read fields
      int parent_index;
      if (sscanf(bufferp, "%s%d", keyword, &parent_index) != (unsigned int) 2) {
        RNFail("Syntax error on line %d in file %s", line_count, filename);
        return 0;
      }

      // Check parent index
      if (parent_index >= 0) {
        // Create parent node
        while (parsed_nodes.NEntries() <= parent_index) {
          char node_name[4096];
          sprintf(node_name, "I%d", parsed_nodes.NEntries());
          R3SceneNode *node = new R3SceneNode(this);
          node->SetName(node_name);
          parsed_nodes.Insert(node);
        }
      
        // Set last node's parent
        R3SceneNode *parent = parsed_nodes.Kth(parent_index);
        parent->InsertChild(current_node);
      }
    }
    else if (!strcmp(keyword, "children")) {
      const char *token = strtok(bufferp, " \n\t");
      assert(token && (!strcmp(token, "children")));
      token = strtok(NULL, " \n\t");
      leaf = (token) ? FALSE : TRUE;
    }
    else if (!strcmp(keyword, "leaf_group")) {
      // Check current node
      if (!current_node) {
        RNFail("leaf_group before first newModel at line %d in %s\n", line_count, filename);
        return 0;
      }

      // Read models
      if (leaf) {
        const char *token = strtok(bufferp, " \n\t");
        assert(token && (!strcmp(token, "leaf_group")));
        while (TRUE) {
          token = strtok(NULL, " \n\t");
          if (!token) break;
          int model_index = atoi(token);
          // char node_name[4096];
          // sprintf(node_name, "L%d", model_index);
          // R3SceneNode *node = new R3SceneNode(this);
          // node->SetName(node_name);
          // current_node->InsertChild(node);
          char model_filename[2048];
          sprintf(model_filename, "models/%s/%d.off", basename, model_index);
          R3TriangleArray *shape = ReadMesh(model_filename);
          if (shape) {
            R3SceneElement *element = new R3SceneElement();
            element->SetMaterial(&R3default_material);
            element->InsertShape(shape);
            current_node->InsertElement(element);
          }
        }    
      }    
    }
  }

  // Close file
  fclose(fp);

  // Return success
  return 1;
}

// Assembly:
subq $0x4298, %rsp           # imm = 0x4298
movq %rdi, 0x4288(%rsp)
movq %rsi, 0x4280(%rsp)
movq %rdx, 0x4278(%rsp)
movq 0x4288(%rsp), %rax
movq %rax, 0x88(%rsp)
cmpq $0x0, 0x4278(%rsp)
jne 0x33ccd
movq 0x88(%rsp), %rax
movq (%rax), %rax
movq %rax, 0x4278(%rsp)
movq 0x4280(%rsp), %rdi
leaq 0x1615c7(%rip), %rsi    # 0x1952a3
callq 0x22c10
movq %rax, 0x4270(%rsp)
cmpq $0x0, %rax
jne 0x33d15
movq 0x4280(%rsp), %rsi
leaq 0x15a9d0(%rip), %rdi    # 0x18e6ce
movb $0x0, %al
callq 0xf3b00
movl $0x0, 0x4294(%rsp)
jmp 0x346ed
leaq 0x3e70(%rsp), %rdi
xorl %esi, %esi
movl $0x400, %edx            # imm = 0x400
callq 0x224f0
movq 0x4280(%rsp), %rdi
movl $0x2f, %esi
callq 0x22b10
movq %rax, 0x3e68(%rsp)
cmpq $0x0, 0x3e68(%rsp)
jne 0x33d60
movq 0x4280(%rsp), %rax
movq %rax, 0x3e68(%rsp)
jmp 0x33d74
movq 0x3e68(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x3e68(%rsp)
movq 0x4280(%rsp), %rdi
movl $0x2e, %esi
callq 0x22b10
movq %rax, 0x3e60(%rsp)
cmpq $0x0, 0x3e60(%rsp)
jne 0x33dcc
movq 0x3e68(%rsp), %rax
movq %rax, 0x80(%rsp)
movq 0x3e68(%rsp), %rdi
callq 0x223d0
movq %rax, %rcx
movq 0x80(%rsp), %rax
addq %rcx, %rax
movq %rax, 0x3e60(%rsp)
movq 0x3e60(%rsp), %rax
movq 0x3e68(%rsp), %rcx
subq %rcx, %rax
movl %eax, 0x3e5c(%rsp)
cmpl $0x3ff, 0x3e5c(%rsp) # imm = 0x3FF
jle 0x33dfe
movl $0x3ff, 0x3e5c(%rsp) # imm = 0x3FF
leaq 0x3e70(%rsp), %rdi
movq 0x3e68(%rsp), %rsi
movslq 0x3e5c(%rsp), %rdx
callq 0x224b0
movl $0x0, 0x3a4c(%rsp)
movl $0x1, 0x3a48(%rsp)
leaq 0x3a38(%rsp), %rdi
callq 0x48140
movq $0x0, 0x3a30(%rsp)
movq 0x4270(%rsp), %rdx
leaq 0x3a50(%rsp), %rdi
movl $0x3ff, %esi            # imm = 0x3FF
callq 0x230f0
movq %rax, 0x78(%rsp)
jmp 0x33e6b
movq 0x78(%rsp), %rax
cmpq $0x0, %rax
je 0x346aa
movl 0x3a4c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x3a4c(%rsp)
leaq 0x3a50(%rsp), %rax
movq %rax, 0x3a18(%rsp)
movq 0x3a18(%rsp), %rax
movsbl (%rax), %edi
callq 0x220c0
cmpl $0x0, %eax
je 0x33edf
movq 0x3a18(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x3a18(%rsp)
jmp 0x33e9b
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x3a28(%rsp)
movl %eax, 0x3a24(%rsp)
jmp 0x346de
movq 0x3a18(%rsp), %rax
movsbl (%rax), %eax
cmpl $0x23, %eax
jne 0x33ef4
jmp 0x33e4a
movq 0x3a18(%rsp), %rax
movsbl (%rax), %eax
cmpl $0x0, %eax
jne 0x33f09
jmp 0x33e4a
movq 0x3a18(%rsp), %rdi
leaq 0x3910(%rsp), %rdx
leaq 0x17a327(%rip), %rsi    # 0x1ae247
movb $0x0, %al
callq 0x229a0
cmpl $0x1, %eax
je 0x33f66
movl 0x3a4c(%rsp), %esi
movq 0x4280(%rsp), %rdx
leaq 0x15af5e(%rip), %rdi    # 0x18eea0
xorl %eax, %eax
callq 0xf3b00
jmp 0x33f4b
movl $0x0, 0x4294(%rsp)
movl $0x1, 0x390c(%rsp)
jmp 0x346cf
leaq 0x3910(%rsp), %rdi
leaq 0x15af4e(%rip), %rsi    # 0x18eec3
callq 0x22ec0
cmpl $0x0, %eax
jne 0x340ff
movq 0x3a18(%rsp), %rdi
leaq 0x3910(%rsp), %rdx
leaq 0x15af56(%rip), %rsi    # 0x18eef0
leaq 0x3908(%rsp), %rcx
movb $0x0, %al
callq 0x229a0
cmpl $0x2, %eax
je 0x33fe8
movl 0x3a4c(%rsp), %esi
movq 0x4280(%rsp), %rdx
leaq 0x15aedc(%rip), %rdi    # 0x18eea0
xorl %eax, %eax
callq 0xf3b00
jmp 0x33fcd
movl $0x0, 0x4294(%rsp)
movl $0x1, 0x390c(%rsp)
jmp 0x346cf
jmp 0x33fea
leaq 0x3a38(%rsp), %rdi
callq 0x2b8b0
movl %eax, 0x74(%rsp)
jmp 0x33ffd
movl 0x74(%rsp), %eax
cmpl 0x3908(%rsp), %eax
jg 0x340d2
leaq 0x2900(%rsp), %rax
movq %rax, 0x68(%rsp)
leaq 0x3a38(%rsp), %rdi
callq 0x2b8b0
movl %eax, 0x70(%rsp)
jmp 0x3402e
movl 0x70(%rsp), %edx
movq 0x68(%rsp), %rdi
leaq 0x160edc(%rip), %rsi    # 0x194f1a
xorl %eax, %eax
callq 0x22160
movl $0x1b0, %edi            # imm = 0x1B0
callq 0x229e0
movq %rax, 0x60(%rsp)
jmp 0x34056
movq 0x88(%rsp), %rsi
movq 0x60(%rsp), %rdi
callq 0x555e0
jmp 0x3406a
movq 0x60(%rsp), %rax
movq %rax, 0x28f8(%rsp)
movq 0x28f8(%rsp), %rdi
leaq 0x2900(%rsp), %rsi
callq 0x57850
jmp 0x3408e
movq 0x28f8(%rsp), %rsi
leaq 0x3a38(%rsp), %rdi
callq 0x48340
jmp 0x340a5
jmp 0x33fea
movq 0x60(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x3a28(%rsp)
movl %eax, 0x3a24(%rsp)
movl $0x1b0, %esi            # imm = 0x1B0
callq 0x22a00
jmp 0x346de
movl 0x3908(%rsp), %esi
leaq 0x3a38(%rsp), %rdi
callq 0x2bd10
movq %rax, 0x58(%rsp)
jmp 0x340ed
movq 0x58(%rsp), %rax
movq %rax, 0x3a30(%rsp)
jmp 0x346a5
leaq 0x3910(%rsp), %rdi
leaq 0x15ae7a(%rip), %rsi    # 0x18ef88
callq 0x22ec0
cmpl $0x0, %eax
jne 0x342af
movq 0x3a18(%rsp), %rdi
leaq 0x3910(%rsp), %rdx
leaq 0x15adbd(%rip), %rsi    # 0x18eef0
leaq 0x28f4(%rsp), %rcx
movb $0x0, %al
callq 0x229a0
cmpl $0x2, %eax
je 0x34181
movl 0x3a4c(%rsp), %esi
movq 0x4280(%rsp), %rdx
leaq 0x15ad43(%rip), %rdi    # 0x18eea0
xorl %eax, %eax
callq 0xf3b00
jmp 0x34166
movl $0x0, 0x4294(%rsp)
movl $0x1, 0x390c(%rsp)
jmp 0x346cf
jmp 0x34183
leaq 0x3a38(%rsp), %rdi
callq 0x2b8b0
movl %eax, 0x54(%rsp)
jmp 0x34196
movl 0x54(%rsp), %eax
cmpl 0x28f4(%rsp), %eax
jg 0x3426b
leaq 0x18f0(%rsp), %rax
movq %rax, 0x48(%rsp)
leaq 0x3a38(%rsp), %rdi
callq 0x2b8b0
movl %eax, 0x50(%rsp)
jmp 0x341c7
movl 0x50(%rsp), %edx
movq 0x48(%rsp), %rdi
leaq 0x160d43(%rip), %rsi    # 0x194f1a
xorl %eax, %eax
callq 0x22160
movl $0x1b0, %edi            # imm = 0x1B0
callq 0x229e0
movq %rax, 0x40(%rsp)
jmp 0x341ef
movq 0x88(%rsp), %rsi
movq 0x40(%rsp), %rdi
callq 0x555e0
jmp 0x34203
movq 0x40(%rsp), %rax
movq %rax, 0x18e8(%rsp)
movq 0x18e8(%rsp), %rdi
leaq 0x18f0(%rsp), %rsi
callq 0x57850
jmp 0x34227
movq 0x18e8(%rsp), %rsi
leaq 0x3a38(%rsp), %rdi
callq 0x48340
jmp 0x3423e
jmp 0x34183
movq 0x40(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x3a28(%rsp)
movl %eax, 0x3a24(%rsp)
movl $0x1b0, %esi            # imm = 0x1B0
callq 0x22a00
jmp 0x346de
movl 0x28f4(%rsp), %esi
leaq 0x3a38(%rsp), %rdi
callq 0x2bd10
movq %rax, 0x38(%rsp)
jmp 0x34286
movq 0x38(%rsp), %rax
movq %rax, 0x18e0(%rsp)
movq 0x4278(%rsp), %rdi
movq 0x18e0(%rsp), %rsi
callq 0x57450
jmp 0x342aa
jmp 0x346a3
leaq 0x3910(%rsp), %rdi
leaq 0x15accf(%rip), %rsi    # 0x18ef8d
callq 0x22ec0
cmpl $0x0, %eax
jne 0x3446f
movq 0x3a18(%rsp), %rdi
leaq 0x3910(%rsp), %rdx
leaq 0x15ac0d(%rip), %rsi    # 0x18eef0
leaq 0x18dc(%rsp), %rcx
movb $0x0, %al
callq 0x229a0
cmpl $0x2, %eax
je 0x34331
movl 0x3a4c(%rsp), %esi
movq 0x4280(%rsp), %rdx
leaq 0x15ab93(%rip), %rdi    # 0x18eea0
xorl %eax, %eax
callq 0xf3b00
jmp 0x34316
movl $0x0, 0x4294(%rsp)
movl $0x1, 0x390c(%rsp)
jmp 0x346cf
cmpl $0x0, 0x18dc(%rsp)
jl 0x3446a
jmp 0x34341
leaq 0x3a38(%rsp), %rdi
callq 0x2b8b0
movl %eax, 0x34(%rsp)
jmp 0x34354
movl 0x34(%rsp), %eax
cmpl 0x18dc(%rsp), %eax
jg 0x34429
leaq 0x8d0(%rsp), %rax
movq %rax, 0x28(%rsp)
leaq 0x3a38(%rsp), %rdi
callq 0x2b8b0
movl %eax, 0x30(%rsp)
jmp 0x34385
movl 0x30(%rsp), %edx
movq 0x28(%rsp), %rdi
leaq 0x15abff(%rip), %rsi    # 0x18ef94
xorl %eax, %eax
callq 0x22160
movl $0x1b0, %edi            # imm = 0x1B0
callq 0x229e0
movq %rax, 0x20(%rsp)
jmp 0x343ad
movq 0x88(%rsp), %rsi
movq 0x20(%rsp), %rdi
callq 0x555e0
jmp 0x343c1
movq 0x20(%rsp), %rax
movq %rax, 0x8c8(%rsp)
movq 0x8c8(%rsp), %rdi
leaq 0x8d0(%rsp), %rsi
callq 0x57850
jmp 0x343e5
movq 0x8c8(%rsp), %rsi
leaq 0x3a38(%rsp), %rdi
callq 0x48340
jmp 0x343fc
jmp 0x34341
movq 0x20(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x3a28(%rsp)
movl %eax, 0x3a24(%rsp)
movl $0x1b0, %esi            # imm = 0x1B0
callq 0x22a00
jmp 0x346de
movl 0x18dc(%rsp), %esi
leaq 0x3a38(%rsp), %rdi
callq 0x2bd10
movq %rax, 0x18(%rsp)
jmp 0x34444
movq 0x18(%rsp), %rax
movq %rax, 0x8c0(%rsp)
movq 0x8c0(%rsp), %rdi
movq 0x3a30(%rsp), %rsi
callq 0x57450
jmp 0x34468
jmp 0x3446a
jmp 0x346a1
leaq 0x3910(%rsp), %rdi
leaq 0x15ab1a(%rip), %rsi    # 0x18ef98
callq 0x22ec0
cmpl $0x0, %eax
jne 0x344de
movq 0x3a18(%rsp), %rdi
leaq 0x15ab0a(%rip), %rsi    # 0x18efa1
callq 0x230a0
movq %rax, 0x8b8(%rsp)
xorl %eax, %eax
movl %eax, %edi
leaq 0x15aaf2(%rip), %rsi    # 0x18efa1
callq 0x230a0
movq %rax, 0x8b8(%rsp)
movq 0x8b8(%rsp), %rdx
movl $0x1, %eax
xorl %ecx, %ecx
cmpq $0x0, %rdx
cmovnel %ecx, %eax
movl %eax, 0x3a48(%rsp)
jmp 0x3469f
leaq 0x3910(%rsp), %rdi
leaq 0x15aab8(%rip), %rsi    # 0x18efa5
callq 0x22ec0
cmpl $0x0, %eax
jne 0x3469d
cmpq $0x0, 0x3a30(%rsp)
jne 0x34540
movl 0x3a4c(%rsp), %esi
movq 0x4280(%rsp), %rdx
leaq 0x15aa94(%rip), %rdi    # 0x18efb0
xorl %eax, %eax
callq 0xf3b00
jmp 0x34525
movl $0x0, 0x4294(%rsp)
movl $0x1, 0x390c(%rsp)
jmp 0x346cf
cmpl $0x0, 0x3a48(%rsp)
je 0x3469b
movq 0x3a18(%rsp), %rdi
leaq 0x15aa44(%rip), %rsi    # 0x18efa1
callq 0x230a0
movq %rax, 0x8b0(%rsp)
jmp 0x3456c
xorl %eax, %eax
movl %eax, %edi
leaq 0x15aa2a(%rip), %rsi    # 0x18efa1
callq 0x230a0
movq %rax, 0x8b0(%rsp)
cmpq $0x0, 0x8b0(%rsp)
jne 0x34594
jmp 0x34699
movq 0x8b0(%rsp), %rdi
callq 0x23090
movl %eax, 0x8ac(%rsp)
movl 0x8ac(%rsp), %ecx
leaq 0x15aa2d(%rip), %rsi    # 0x18efe3
xorl %eax, %eax
leaq 0xa0(%rsp), %rdi
movq %rdi, 0x8(%rsp)
leaq 0x3e70(%rsp), %rdx
callq 0x22160
movq 0x8(%rsp), %rdi
callq 0x3cd50
movq %rax, 0x10(%rsp)
jmp 0x345e3
movq 0x10(%rsp), %rax
movq %rax, 0x98(%rsp)
cmpq $0x0, 0x98(%rsp)
je 0x34694
movl $0x60, %edi
callq 0x229e0
movq %rax, (%rsp)
jmp 0x3460f
movq (%rsp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x58f20
jmp 0x3461e
movq (%rsp), %rax
movq %rax, 0x90(%rsp)
movq 0x90(%rsp), %rdi
leaq 0x1c7ec7(%rip), %rsi    # 0x1fc500
callq 0x59350
jmp 0x34640
movq 0x90(%rsp), %rdi
movq 0x98(%rsp), %rsi
callq 0x59370
jmp 0x34657
movq 0x3a30(%rsp), %rdi
movq 0x90(%rsp), %rsi
callq 0x57510
jmp 0x3466e
jmp 0x34694
movq (%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x3a28(%rsp)
movl %eax, 0x3a24(%rsp)
movl $0x60, %esi
callq 0x22a00
jmp 0x346de
jmp 0x3456a
jmp 0x3469b
jmp 0x3469d
jmp 0x3469f
jmp 0x346a1
jmp 0x346a3
jmp 0x346a5
jmp 0x33e4a
movq 0x4270(%rsp), %rdi
callq 0x229d0
jmp 0x346b9
movl $0x1, 0x4294(%rsp)
movl $0x1, 0x390c(%rsp)
leaq 0x3a38(%rsp), %rdi
callq 0x48210
jmp 0x346ed
leaq 0x3a38(%rsp), %rdi
callq 0x48210
jmp 0x346fc
movl 0x4294(%rsp), %eax
addq $0x4298, %rsp           # imm = 0x4298
retq
movq 0x3a28(%rsp), %rdi
callq 0x23290
nopl (%rax)