// File: tomfunkhouser[P]gaps/pkgs/GSV/GSVMesh.cpp
// Function: gaps::GSVMesh::WritePlyFile(gaps::GSVScan*, char const*, int) const
int GSVMesh::
WritePlyFile(GSVScan *scan, const char *filename, RNBoolean binary) const
{
  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;

  // Element names
  char *elem_names[] = { (char *) "vertex", (char *) "face" };

  // 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 ply file
  float version;
  int file_type = (binary) ? PLY_BINARY_NATIVE : PLY_ASCII;
  PlyFile *ply = ply_open_for_writing((char *) filename, 2, elem_names, file_type, &version);
  if (!ply) return -1;

  // Describe vertex properties
  ply_element_count(ply, (char *) "vertex", NVertices());
  for (unsigned int i = 0; i < sizeof(vert_props) / sizeof(PlyProperty); i++) {
    ply_describe_property(ply, (char *) "vertex", &vert_props[i]);
  }

  // Describe face properties
  ply_element_count(ply, (char *) "face", NFaces());
  for (unsigned int i = 0; i < sizeof(face_props) / sizeof(PlyProperty); i++) {
    ply_describe_property(ply, (char *) "face", &face_props[i]);
  }

  // Describe scan properties
  char buffer[1024];
  GSVSegment *segment = (scan) ? scan->Segment() : NULL;
  GSVRun *run = (segment) ? segment->Run() : NULL;
  sprintf(buffer, "run_name %s", (run) ? run->Name() : "None");
  ply_put_obj_info(ply, buffer);
  sprintf(buffer, "segment_index %d", (segment) ? segment->RunIndex() : -1);
  ply_put_obj_info(ply, buffer);
  sprintf(buffer, "scan_index %d", (scan) ? scan->SegmentIndex() : -1);
  ply_put_obj_info(ply, buffer);

  // Complete header
  ply_header_complete(ply);

  // Write vertices
  ply_put_element_setup(ply, (char *) "vertex");
  for (int i = 0; i < NVertices(); i++) {
    GSVMeshVertex *v = (GSVMeshVertex *) Vertex(i);
    const R3Point& position = VertexPosition(v);
    PlyVertex ply_vertex;
    ply_vertex.x = position.X();
    ply_vertex.y = position.Y();
    ply_vertex.z = position.Z();
    ply_vertex.scanline_index = (v->scanline) ? v->scanline->ScanIndex() : -1;
    ply_vertex.point_index = v->point_index;
    ply_vertex.boundary_type = v->boundary_type;
    ply_put_element(ply, (void *) &ply_vertex);
  }

  // Write faces
  ply_put_element_setup(ply, (char *) "face");
  for (int i = 0; i < NFaces(); i++) {
    R3MeshFace *f = Face(i);
    static int verts[3];
    static PlyFace ply_face = { 3, verts, 0 };
    ply_face.verts[0] = VertexID(VertexOnFace(f, 0));
    ply_face.verts[1] = VertexID(VertexOnFace(f, 1));
    ply_face.verts[2] = VertexID(VertexOnFace(f, 2));
    ply_face.segment = FaceSegment(f);
    ply_put_element(ply, (void *) &ply_face);
  }

  // Close the file 
  ply_close(ply);

  // Return number of faces written
  return NFaces();
}

// Assembly:
subq $0x508, %rsp            # imm = 0x508
movq %rdi, 0x4f8(%rsp)
movq %rsi, 0x4f0(%rsp)
movq %rdx, 0x4e8(%rsp)
movl %ecx, 0x4e4(%rsp)
movq 0x4f8(%rsp), %rax
movq %rax, 0x58(%rsp)
movq 0x289ce6(%rip), %rax    # 0x2e6e80
movq %rax, 0x4d0(%rsp)
movq 0x289cdf(%rip), %rax    # 0x2e6e88
movq %rax, 0x4d8(%rsp)
movl 0x4e4(%rsp), %edx
movl $0x1, %eax
movl $0x4, %ecx
cmpl $0x0, %edx
cmovnel %ecx, %eax
movl %eax, 0x4c8(%rsp)
movq 0x4e8(%rsp), %rdi
leaq 0x4d0(%rsp), %rdx
movl 0x4c8(%rsp), %ecx
movl $0x2, %esi
leaq 0x4cc(%rsp), %r8
callq 0x189e90
movq %rax, 0x4c0(%rsp)
cmpq $0x0, 0x4c0(%rsp)
jne 0x5d21b
movl $0xffffffff, 0x504(%rsp) # imm = 0xFFFFFFFF
jmp 0x5d72b
movq 0x58(%rsp), %rdi
movq 0x4c0(%rsp), %rax
movq %rax, 0x50(%rsp)
callq 0x391c0
movq 0x50(%rsp), %rdi
movl %eax, %edx
leaq 0x20da8a(%rip), %rsi    # 0x26acca
callq 0x18a5b0
movl $0x0, 0x4bc(%rsp)
movl 0x4bc(%rsp), %eax
cmpq $0x6, %rax
jae 0x5d299
movq 0x4c0(%rsp), %rdi
movl 0x4bc(%rsp), %eax
leaq 0x292a8d(%rip), %rdx    # 0x2efd00
imulq $0x28, %rax, %rax
addq %rax, %rdx
leaq 0x20da49(%rip), %rsi    # 0x26acca
callq 0x18a240
movl 0x4bc(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x4bc(%rsp)
jmp 0x5d250
movq 0x58(%rsp), %rdi
movq 0x4c0(%rsp), %rax
movq %rax, 0x48(%rsp)
callq 0x39030
movq 0x48(%rsp), %rdi
movl %eax, %edx
leaq 0x20a33b(%rip), %rsi    # 0x2675f9
callq 0x18a5b0
movl $0x0, 0x4b8(%rsp)
movl 0x4b8(%rsp), %eax
cmpq $0x2, %rax
jae 0x5d317
movq 0x4c0(%rsp), %rdi
movl 0x4b8(%rsp), %eax
leaq 0x292aff(%rip), %rdx    # 0x2efdf0
imulq $0x28, %rax, %rax
addq %rax, %rdx
leaq 0x20a2fa(%rip), %rsi    # 0x2675f9
callq 0x18a240
movl 0x4b8(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x4b8(%rsp)
jmp 0x5d2ce
cmpq $0x0, 0x4f0(%rsp)
je 0x5d336
movq 0x4f0(%rsp), %rdi
callq 0x542a0
movq %rax, 0x40(%rsp)
jmp 0x5d33f
xorl %eax, %eax
movq %rax, 0x40(%rsp)
jmp 0x5d33f
movq 0x40(%rsp), %rax
movq %rax, 0xa8(%rsp)
cmpq $0x0, 0xa8(%rsp)
je 0x5d36b
movq 0xa8(%rsp), %rdi
callq 0x4f380
movq %rax, 0x38(%rsp)
jmp 0x5d374
xorl %eax, %eax
movq %rax, 0x38(%rsp)
jmp 0x5d374
movq 0x38(%rsp), %rax
movq %rax, 0xa0(%rsp)
leaq 0xb0(%rsp), %rax
movq %rax, 0x30(%rsp)
cmpq $0x0, 0xa0(%rsp)
je 0x5d3ad
movq 0xa0(%rsp), %rdi
callq 0x44310
movq %rax, 0x28(%rsp)
jmp 0x5d3bb
leaq 0x20a256(%rip), %rax    # 0x26760a
movq %rax, 0x28(%rsp)
jmp 0x5d3bb
movq 0x30(%rsp), %rdi
movq 0x28(%rsp), %rdx
leaq 0x20a232(%rip), %rsi    # 0x2675fe
movb $0x0, %al
callq 0x2a280
movq 0x4c0(%rsp), %rdi
leaq 0xb0(%rsp), %rsi
callq 0x18b3c0
leaq 0xb0(%rsp), %rax
movq %rax, 0x20(%rsp)
cmpq $0x0, 0xa8(%rsp)
je 0x5d413
movq 0xa8(%rsp), %rdi
callq 0x4a640
movl %eax, 0x1c(%rsp)
jmp 0x5d41e
movl $0xffffffff, %eax       # imm = 0xFFFFFFFF
movl %eax, 0x1c(%rsp)
jmp 0x5d41e
movq 0x20(%rsp), %rdi
movl 0x1c(%rsp), %edx
leaq 0x20a1e1(%rip), %rsi    # 0x26760f
movb $0x0, %al
callq 0x2a280
movq 0x4c0(%rsp), %rdi
leaq 0xb0(%rsp), %rsi
callq 0x18b3c0
leaq 0xb0(%rsp), %rax
movq %rax, 0x10(%rsp)
cmpq $0x0, 0x4f0(%rsp)
je 0x5d475
movq 0x4f0(%rsp), %rdi
callq 0x54480
movl %eax, 0xc(%rsp)
jmp 0x5d480
movl $0xffffffff, %eax       # imm = 0xFFFFFFFF
movl %eax, 0xc(%rsp)
jmp 0x5d480
movq 0x10(%rsp), %rdi
movl 0xc(%rsp), %edx
leaq 0x20a190(%rip), %rsi    # 0x267620
movb $0x0, %al
callq 0x2a280
movq 0x4c0(%rsp), %rdi
leaq 0xb0(%rsp), %rsi
callq 0x18b3c0
movq 0x4c0(%rsp), %rdi
callq 0x18a620
movq 0x4c0(%rsp), %rdi
leaq 0x20d802(%rip), %rsi    # 0x26acca
callq 0x18a950
movl $0x0, 0x9c(%rsp)
movq 0x58(%rsp), %rdi
movl 0x9c(%rsp), %eax
movl %eax, 0x8(%rsp)
callq 0x391c0
movl %eax, %ecx
movl 0x8(%rsp), %eax
cmpl %ecx, %eax
jge 0x5d604
movq 0x58(%rsp), %rdi
movl 0x9c(%rsp), %esi
callq 0x5e390
movq 0x58(%rsp), %rdi
movq %rax, 0x90(%rsp)
movq 0x90(%rsp), %rsi
callq 0x391a0
movq %rax, 0x88(%rsp)
movq 0x88(%rsp), %rdi
callq 0x38bb0
cvtsd2ss %xmm0, %xmm0
movss %xmm0, 0x70(%rsp)
movq 0x88(%rsp), %rdi
callq 0x38c10
cvtsd2ss %xmm0, %xmm0
movss %xmm0, 0x74(%rsp)
movq 0x88(%rsp), %rdi
callq 0x38c20
cvtsd2ss %xmm0, %xmm0
movss %xmm0, 0x78(%rsp)
movq 0x90(%rsp), %rax
cmpq $0x0, 0x98(%rax)
je 0x5d59f
movq 0x90(%rsp), %rax
movq 0x98(%rax), %rdi
callq 0x565d0
movl %eax, 0x4(%rsp)
jmp 0x5d5aa
movl $0xffffffff, %eax       # imm = 0xFFFFFFFF
movl %eax, 0x4(%rsp)
jmp 0x5d5aa
movl 0x4(%rsp), %eax
movl %eax, 0x7c(%rsp)
movq 0x90(%rsp), %rax
movl 0xa0(%rax), %eax
movl %eax, 0x80(%rsp)
movq 0x90(%rsp), %rax
movl 0xa4(%rax), %eax
movl %eax, 0x84(%rsp)
movq 0x4c0(%rsp), %rdi
leaq 0x70(%rsp), %rsi
callq 0x18a9c0
movl 0x9c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x9c(%rsp)
jmp 0x5d4d8
movq 0x4c0(%rsp), %rdi
leaq 0x209fe6(%rip), %rsi    # 0x2675f9
callq 0x18a950
movl $0x0, 0x6c(%rsp)
movq 0x58(%rsp), %rdi
movl 0x6c(%rsp), %eax
movl %eax, (%rsp)
callq 0x39030
movl %eax, %ecx
movl (%rsp), %eax
cmpl %ecx, %eax
jge 0x5d70d
movq 0x58(%rsp), %rdi
movl 0x6c(%rsp), %esi
callq 0x39050
movq 0x58(%rsp), %rdi
movq %rax, 0x60(%rsp)
movq 0x60(%rsp), %rsi
xorl %edx, %edx
callq 0x5e1f0
movq 0x58(%rsp), %rdi
movq %rax, %rsi
callq 0x5e3b0
movq 0x58(%rsp), %rdi
movl %eax, %ecx
movq 0x2927cb(%rip), %rax    # 0x2efe48
movl %ecx, (%rax)
movq 0x60(%rsp), %rsi
movl $0x1, %edx
callq 0x5e1f0
movq 0x58(%rsp), %rdi
movq %rax, %rsi
callq 0x5e3b0
movq 0x58(%rsp), %rdi
movl %eax, %ecx
movq 0x29279f(%rip), %rax    # 0x2efe48
movl %ecx, 0x4(%rax)
movq 0x60(%rsp), %rsi
movl $0x2, %edx
callq 0x5e1f0
movq 0x58(%rsp), %rdi
movq %rax, %rsi
callq 0x5e3b0
movq 0x58(%rsp), %rdi
movl %eax, %ecx
movq 0x292772(%rip), %rax    # 0x2efe48
movl %ecx, 0x8(%rax)
movq 0x60(%rsp), %rsi
callq 0x390a0
movl %eax, 0x292767(%rip)    # 0x2efe50
movq 0x4c0(%rsp), %rdi
leaq 0x292748(%rip), %rsi    # 0x2efe40
callq 0x18a9c0
movl 0x6c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x6c(%rsp)
jmp 0x5d620
movq 0x4c0(%rsp), %rdi
callq 0x18d640
movq 0x58(%rsp), %rdi
callq 0x39030
movl %eax, 0x504(%rsp)
movl 0x504(%rsp), %eax
addq $0x508, %rsp            # imm = 0x508
retq
nopw (%rax,%rax)