// File: /workspace/github_cpp_makefile_star2_O2/tomfunkhouser[P]gaps/pkgs/GSV/GSVMesh.cpp
// Function: gaps::GSVMesh::ReadPlyFile(gaps::GSVScan*, char const*)
int GSVMesh::
ReadPlyFile(GSVScan *scan, const char *filename)
{
  FILE *fp;
  int i,j;
  PlyFile *ply;
  int nelems;
  PlyProperty **plist;
  char **elist;
  int file_type;
  int nprops;
  int num_elems;
  char *elem_name;
  float version;

  typedef struct PlyVertex {
    float x, y, z;
    int scanline_index;
    int point_index;
    int boundary_type;
  } PlyVertex;

  typedef struct PlyFace {
    unsigned char nverts;
    int *verts;
    int segment;
  } PlyFace;

  // List of property information for a vertex 
  // List of property information for a vertex 
  static PlyProperty vert_props[] = { 
    {(char *) "x", PLY_FLOAT, PLY_FLOAT, offsetof(PlyVertex,x), 0, 0, 0, 0},
    {(char *) "y", PLY_FLOAT, PLY_FLOAT, offsetof(PlyVertex,y), 0, 0, 0, 0},
    {(char *) "z", PLY_FLOAT, PLY_FLOAT, offsetof(PlyVertex,z), 0, 0, 0, 0},
    {(char *) "scanline_index", PLY_INT, PLY_INT, offsetof(PlyVertex,scanline_index), 0, 0, 0, 0},
    {(char *) "point_index", PLY_INT, PLY_INT, offsetof(PlyVertex,point_index), 0, 0, 0, 0},
    {(char *) "boundary_type", PLY_INT, PLY_INT, offsetof(PlyVertex,boundary_type), 0, 0, 0, 0}
  };

  // List of property information for a vertex 
  static PlyProperty face_props[] = { 
    {(char *) "vertex_indices", PLY_INT, PLY_INT, offsetof(PlyFace,verts), 1, PLY_UCHAR, PLY_UCHAR, offsetof(PlyFace,nverts)},
    {(char *) "segment", PLY_INT, PLY_INT, offsetof(PlyFace,segment), 0, 0, 0, 0}
  };

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

  // Read PLY header
  ply = ply_read (fp, &nelems, &elist);
  if (!ply) {
    RNFail("Unable to read ply file: %s", filename);
    fclose(fp);
    return 0;
  }
  
  // Get header info
  ply_get_info (ply, &version, &file_type);

  // Read obj infos
  int scan_index = 0;
  int segment_index = 0;
  char run_name[1024];
  int num_obj_infos = 0;
  char **obj_infos = ply_get_obj_info(ply, &num_obj_infos);
  for (int i = 0; i < num_obj_infos; i++) {
    char obj_info[1024];
    strncpy(obj_info, obj_infos[i], 1023);
    char *info_type = strtok(obj_info, " ");
    if (!info_type) continue;
    char *valuep = strtok(NULL, " ");
    if (!strcmp(info_type, "scan_index")) scan_index = atoi(valuep);
    else if (!strcmp(info_type, "segment_index")) segment_index = atoi(valuep);
    else if (!strcmp(info_type, "run_name")) strcpy(run_name, valuep);
  }

  // To silence compiler about unused variables
  if (scan_index == -146) printf("Wow\n");
  if (segment_index == -146) printf("Wow\n");

  // Read all elements
  for (i = 0; i < nelems; i++) {
    // Get the description of the element 
    elem_name = elist[i];
    plist = ply_get_element_description (ply, elem_name, &num_elems, &nprops);

    // Check element type
    if (equal_strings ("vertex", elem_name)) {
      // Allocate block of vertices
      gsv_vertex_block = new GSVMeshVertex [num_elems];
      if (!gsv_vertex_block) {
        RNFail("Unable to allocate vertex matrix\n");
        return 0;
      }

      // Resize array of vertices
      vertices.Resize(num_elems);

      // set up for getting vertex elements 
      for (j = 0; j < nprops; j++) {
	if (equal_strings("x", plist[j]->name)) ply_get_property (ply, elem_name, &vert_props[0]);
	else if (equal_strings("y", plist[j]->name)) ply_get_property (ply, elem_name, &vert_props[1]);
	else if (equal_strings("z", plist[j]->name)) ply_get_property (ply, elem_name, &vert_props[2]);
	else if (equal_strings("scanline_index", plist[j]->name)) ply_get_property (ply, elem_name, &vert_props[3]);
	else if (equal_strings("point_index", plist[j]->name)) ply_get_property (ply, elem_name, &vert_props[4]);
	else if (equal_strings("boundary_type", plist[j]->name)) ply_get_property (ply, elem_name, &vert_props[5]);
      }

      // Grab all the vertex elements 
      for (j = 0; j < num_elems; j++) {
        // Read vertex into local struct
        PlyVertex plyvertex;
        plyvertex.scanline_index = -1;
        plyvertex.point_index = -1;
        plyvertex.boundary_type = 0;
        ply_get_element(ply, (void *) &plyvertex);

        // Create mesh vertex
        R3Point position(plyvertex.x, plyvertex.y, plyvertex.z);
        GSVMeshVertex *v = (GSVMeshVertex *) CreateVertex(position, &gsv_vertex_block[j]);
        v->scanline = (scan && (plyvertex.scanline_index >= 0)) ? scan->Scanline(plyvertex.scanline_index) : NULL;
        v->point_index = plyvertex.point_index;
        v->boundary_type = plyvertex.boundary_type;
      }
    }
    else if (equal_strings ("face", elem_name)) {
      // Resize array of faces
      faces.Resize(num_elems);

      // set up for getting face elements 
      for (j = 0; j < nprops; j++) {
	if (equal_strings("vertex_indices", plist[j]->name)) ply_get_property (ply, elem_name, &face_props[0]);
	else if (equal_strings("segment", plist[j]->name)) ply_get_property (ply, elem_name, &face_props[1]);
      }

      // grab all the face elements 
      for (j = 0; j < num_elems; j++) {
        // Read face into local struct
        PlyFace plyface;
        plyface.nverts = 0;
        plyface.verts = NULL;
        plyface.segment = 0;
        ply_get_element(ply, (void *) &plyface);

        // Create mesh face(s)
        R3MeshVertex *v1 = vertices[plyface.verts[0]];
        for (int k = 2; k < plyface.nverts; k++) {
          // Get vertices
          R3MeshVertex *v2 = vertices[plyface.verts[k-1]];
          R3MeshVertex *v3 = vertices[plyface.verts[k]];

          // Check plyface
          assert(plyface.verts[0] >= 0);
          assert(plyface.verts[k-1] >= 0);
          assert(plyface.verts[k] >= 0);
          assert(plyface.verts[0] < vertices.NEntries());
          assert(plyface.verts[k-1] < vertices.NEntries());
          assert(plyface.verts[k] < vertices.NEntries());

          // Check vertices
          if ((v1 == v2) || (v2 == v3) || (v1 == v3)) continue;

          // Create face
          R3MeshFace *f = CreateFace(v1, v2, v3);
          if (!f) {
            // Must have been degeneracy (e.g., three faces sharing an edge), create new vertices
            // Note: these vertices are allocated separately, and so they will not be deleted (memory leak)
            // R3MeshVertex *v1a = CreateVertex(VertexPosition(v1));
            // R3MeshVertex *v2a = CreateVertex(VertexPosition(v2));
            // R3MeshVertex *v3a = CreateVertex(VertexPosition(v3));
            // f = CreateFace(v1a, v2a, v3a);
          } 

          // Set boundary_type
          if (f) SetFaceSegment(f, plyface.segment);
        }

        // Free face data allocated by ply 
        if (plyface.verts) free(plyface.verts);
      }
    }
    else {
      ply_get_other_element (ply, elem_name, num_elems);
    }
  }

  // Close the file 
  ply_close (ply);

  // Return number of faces created
  return faces.NEntries();
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x488, %rsp            # imm = 0x488
movq %rdx, %r14
movq %rsi, %r15
movq %rdi, %rbx
leaq 0xeadae(%rip), %rsi     # 0x12bbbb
movq %rdx, %rdi
callq 0x27b20
testq %rax, %rax
je 0x4138b
movq %rax, %r12
leaq 0x3c(%rsp), %rsi
leaq 0x58(%rsp), %rdx
movq %rax, %rdi
callq 0xc575f
testq %rax, %rax
je 0x413a0
movq %rax, %rbp
leaq 0x60(%rsp), %rsi
leaq 0x64(%rsp), %rdx
movq %rax, %rdi
callq 0xc69f4
leaq 0x38(%rsp), %rsi
andl $0x0, (%rsi)
movq %rbp, %rdi
callq 0xc6503
movq %rax, 0x30(%rsp)
xorl %r12d, %r12d
leaq 0xeec37(%rip), %r14     # 0x12faa7
movl $0x0, 0x10(%rsp)
movl $0x0, 0x20(%rsp)
movq %rbp, 0x8(%rsp)
movslq 0x38(%rsp), %rax
cmpq %rax, %r12
jge 0x40f31
movq 0x30(%rsp), %rax
movq (%rax,%r12,8), %rsi
movl $0x3ff, %edx            # imm = 0x3FF
leaq 0x80(%rsp), %r13
movq %r13, %rdi
callq 0x27460
movq %r13, %rdi
movq %r14, %rsi
callq 0x27f90
testq %rax, %rax
je 0x40f0b
movq %rax, %rbp
movq %rbx, %r13
xorl %edi, %edi
movq %r14, %rbx
movq %r14, %rsi
callq 0x27f90
movq %rax, %r14
movq %rbp, %rdi
leaq 0xeb4f6(%rip), %rsi     # 0x12c3d7
callq 0x27db0
testl %eax, %eax
je 0x40f12
movq %rbp, %rdi
leaq 0xeb4ee(%rip), %rsi     # 0x12c3e2
callq 0x27db0
testl %eax, %eax
jne 0x40f1e
movq %r14, %rdi
callq 0x27f80
movl %eax, 0x10(%rsp)
jmp 0x40f1e
movq 0x8(%rsp), %rbp
jmp 0x40f29
movq %r14, %rdi
callq 0x27f80
movl %eax, 0x20(%rsp)
movq 0x8(%rsp), %rbp
movq %rbx, %r14
movq %r13, %rbx
incq %r12
jmp 0x40e85
cmpl $0xffffff6e, 0x20(%rsp) # imm = 0xFFFFFF6E
jne 0x40f47
leaq 0xeb7c4(%rip), %rdi     # 0x12c706
callq 0x27f50
cmpl $0xffffff6e, 0x10(%rsp) # imm = 0xFFFFFF6E
jne 0x40f5d
leaq 0xeb7ae(%rip), %rdi     # 0x12c706
callq 0x27f50
leaq 0x8(%rbx), %r12
leaq 0x28(%rbx), %rax
movq %rax, 0x40(%rsp)
xorl %ecx, %ecx
movq %rbx, 0x28(%rsp)
movq %r15, 0x48(%rsp)
movslq 0x3c(%rsp), %rax
cmpq %rax, %rcx
jge 0x4137e
movq 0x58(%rsp), %rax
movq %rcx, 0x30(%rsp)
movq (%rax,%rcx,8), %r14
movq %rbp, %rdi
movq %r14, %rsi
leaq 0x4(%rsp), %rdx
leaq 0x1c(%rsp), %rcx
callq 0xc5df6
movq %rax, %r13
leaq 0xeb43f(%rip), %rdi     # 0x12c3f0
movq %r14, %rsi
callq 0xc5b81
testl %eax, %eax
je 0x4104a
movq %r14, 0x20(%rsp)
movslq 0x4(%rsp), %r14
movq %r14, %rax
movl $0xa8, %ecx
mulq %rcx
movq %rax, %rdi
seto %al
addq $0x8, %rdi
pushq $-0x1
popq %rcx
cmovbq %rcx, %rdi
testb %al, %al
cmovneq %rcx, %rdi
movq %rdi, 0x50(%rsp)
callq 0x27040
leaq 0x8(%rax), %rcx
movq %rax, 0x10(%rsp)
movq %r14, (%rax)
testq %r14, %r14
je 0x410d3
imulq $-0xa8, %r14, %rbp
movq %rcx, %rbx
movq %rcx, %r14
xorl %r15d, %r15d
movq %r14, %rdi
callq 0x41c10
addq $-0xa8, %r15
addq $0xa8, %r14
cmpq %r15, %rbp
jne 0x4101c
movl 0x4(%rsp), %esi
movq 0x48(%rsp), %r15
movq 0x8(%rsp), %rbp
jmp 0x410d8
leaq 0xeb3a6(%rip), %rdi     # 0x12c3f7
movq %r14, %rsi
callq 0xc5b81
movl 0x4(%rsp), %edx
testl %eax, %eax
movq %r14, %rbx
je 0x4135c
movq 0x40(%rsp), %rdi
movl %edx, %esi
callq 0xe1db8
xorl %r14d, %r14d
movslq 0x1c(%rsp), %rax
cmpq %rax, %r14
jge 0x4129e
movq (%r13,%r14,8), %rax
movq (%rax), %rsi
leaq 0xeb300(%rip), %rdi     # 0x12c394
callq 0xc5b81
leaq 0x17db30(%rip), %rdx    # 0x1bebd0
testl %eax, %eax
jne 0x410c3
movq (%r13,%r14,8), %rax
movq (%rax), %rsi
leaq 0x10c0ea(%rip), %rdi    # 0x14d19d
callq 0xc5b81
leaq 0x17db39(%rip), %rdx    # 0x1bebf8
testl %eax, %eax
je 0x410ce
movq %rbp, %rdi
movq %rbx, %rsi
callq 0xc5f9e
incq %r14
jmp 0x41077
movq %rcx, %rbx
xorl %esi, %esi
movq 0x28(%rsp), %rax
movq %rbx, 0x138(%rax)
movq %r12, %rdi
callq 0xe1db8
xorl %r14d, %r14d
movq 0x20(%rsp), %rbx
movslq 0x1c(%rsp), %rax
cmpq %rax, %r14
jge 0x411d3
movq (%r13,%r14,8), %rax
movq (%rax), %rsi
leaq 0x10b3f1(%rip), %rdi    # 0x14c502
callq 0xc5b81
leaq 0x17d9c3(%rip), %rdx    # 0x1beae0
testl %eax, %eax
jne 0x411c0
movq (%r13,%r14,8), %rax
movq (%rax), %rsi
leaq 0xeac0d(%rip), %rdi     # 0x12bd41
callq 0xc5b81
leaq 0x17d9c8(%rip), %rdx    # 0x1beb08
testl %eax, %eax
jne 0x411c0
movq (%r13,%r14,8), %rax
movq (%rax), %rsi
leaq 0xea7a8(%rip), %rdi     # 0x12b8fb
callq 0xc5b81
leaq 0x17d9d1(%rip), %rdx    # 0x1beb30
testl %eax, %eax
jne 0x411c0
movq (%r13,%r14,8), %rax
movq (%rax), %rsi
leaq 0xeb1f9(%rip), %rdi     # 0x12c36b
callq 0xc5b81
leaq 0x17d9da(%rip), %rdx    # 0x1beb58
testl %eax, %eax
jne 0x411c0
movq (%r13,%r14,8), %rax
movq (%rax), %rsi
leaq 0xeb1e9(%rip), %rdi     # 0x12c37a
callq 0xc5b81
leaq 0x17d9e3(%rip), %rdx    # 0x1beb80
testl %eax, %eax
jne 0x411c0
movq (%r13,%r14,8), %rax
movq (%rax), %rsi
leaq 0xeb1d6(%rip), %rdi     # 0x12c386
callq 0xc5b81
leaq 0x17d9ec(%rip), %rdx    # 0x1beba8
testl %eax, %eax
je 0x411cb
movq %rbp, %rdi
movq %rbx, %rsi
callq 0xc5f9e
incq %r14
jmp 0x410f4
xorl %r14d, %r14d
xorl %r13d, %r13d
movslq 0x4(%rsp), %rax
cmpq %rax, %r13
jge 0x41367
testq %r15, %r15
setne %bpl
orq $-0x1, 0x8c(%rsp)
andl $0x0, 0x94(%rsp)
movq 0x8(%rsp), %rdi
leaq 0x80(%rsp), %rsi
callq 0xc6026
cvtss2sd 0x80(%rsp), %xmm0
cvtss2sd 0x84(%rsp), %xmm1
cvtss2sd 0x88(%rsp), %xmm2
movq %r15, %rbx
leaq 0x68(%rsp), %r15
movq %r15, %rdi
callq 0xc0dfc
movq 0x28(%rsp), %rdi
movq 0x138(%rdi), %rdx
addq %r14, %rdx
movq (%rdi), %rax
movq %r15, %rsi
callq *0x20(%rax)
movl 0x8c(%rsp), %ecx
testl %ecx, %ecx
setns %dl
andb %bpl, %dl
cmpb $0x1, %dl
jne 0x41274
movl %ecx, %ecx
movq 0x28(%rbx), %rdx
movq (%rdx,%rcx,8), %rcx
jmp 0x41276
xorl %ecx, %ecx
movq %rbx, %r15
movq %rcx, 0x98(%rax)
movq 0x90(%rsp), %rcx
movq %rcx, 0xa0(%rax)
incq %r13
addq $0xa8, %r14
jmp 0x411d9
xorl %ebp, %ebp
cmpl 0x4(%rsp), %ebp
jge 0x41367
movb $0x0, 0x80(%rsp)
andq $0x0, 0x88(%rsp)
andl $0x0, 0x90(%rsp)
movq 0x8(%rsp), %rdi
leaq 0x80(%rsp), %rsi
callq 0xc6026
movq 0x88(%rsp), %rax
movslq (%rax), %rax
movq (%r12), %rcx
movq (%rcx,%rax,8), %r14
pushq $0x2
popq %r13
movq 0x28(%rsp), %rbx
movzbl 0x80(%rsp), %eax
movq 0x88(%rsp), %rdi
cmpq %rax, %r13
jae 0x41350
movslq -0x4(%rdi,%r13,4), %rcx
movq (%r12), %rax
movq (%rax,%rcx,8), %rdx
cmpq %rdx, %r14
je 0x4134b
movslq (%rdi,%r13,4), %rcx
movq (%rax,%rcx,8), %rcx
cmpq %rcx, %rdx
je 0x4134b
cmpq %rcx, %r14
je 0x4134b
movq (%rbx), %rax
movq %rbx, %rdi
movq %r14, %rsi
xorl %r8d, %r8d
callq *0x48(%rax)
testq %rax, %rax
je 0x4134b
movl 0x90(%rsp), %ecx
movl %ecx, 0x9c(%rax)
incq %r13
jmp 0x412f1
callq 0x27b40
incl %ebp
jmp 0x412a0
movq %rbp, %rdi
movq %rbx, %rsi
callq 0xc66bd
movq 0x30(%rsp), %rcx
incq %rcx
movq 0x8(%rsp), %rbp
movq 0x28(%rsp), %rbx
jmp 0x40f76
movq %rbp, %rdi
callq 0xc69df
movl 0x34(%rbx), %ebx
jmp 0x413bb
leaq 0xeb011(%rip), %rdi     # 0x12c3a3
xorl %ebx, %ebx
movq %r14, %rsi
xorl %eax, %eax
callq 0xe434a
jmp 0x413bb
leaq 0xeb014(%rip), %rdi     # 0x12c3bb
xorl %ebx, %ebx
movq %r14, %rsi
xorl %eax, %eax
callq 0xe434a
movq %r12, %rdi
callq 0x27930
movl %ebx, %eax
addq $0x488, %rsp            # imm = 0x488
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %rax, %rbx
testq %r15, %r15
je 0x413f8
negq %r15
movq 0x10(%rsp), %r14
addq $-0xa0, %r14
leaq (%r14,%r15), %rdi
callq 0xa2f5c
addq $-0xa8, %r15
jne 0x413e6
movq 0x10(%rsp), %rdi
movq 0x50(%rsp), %rsi
callq 0x28360
movq %rbx, %rdi
callq 0x28170
nop