// File: /workspace/github_cpp_makefile_star2_O2/tomfunkhouser[P]gaps/pkgs/R3Shapes/R3Mesh.cpp
// Function: gaps::R3Mesh::WritePlyStream(_IO_FILE*, int) const
int R3Mesh::
WritePlyStream(FILE *fp, RNBoolean binary)  const
{
  typedef struct PlyVertex {
    float x, y, z;
    float nx, ny, nz;
    float tx, ty;
    unsigned char red, green, blue;
  } PlyVertex;

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

  // Gather info about what vertex info to write
  RNBoolean has_vertex_normals = FALSE;
  RNBoolean has_vertex_texcoords = FALSE;
  RNBoolean has_vertex_colors = FALSE;
  for (int i = 0; i < NVertices(); i++) {
    R3MeshVertex *v = Vertex(i);
    if (v->flags[R3_MESH_VERTEX_NORMAL_UPTODATE]) has_vertex_normals = TRUE;
    if (!v->texcoords.IsZero()) has_vertex_texcoords = TRUE;
    if (!v->color.IsBlack()) has_vertex_colors = TRUE;
  }

  // Gather info about what face info to write
  RNBoolean has_face_materials = FALSE;
  RNBoolean has_face_segments = FALSE;
  RNBoolean has_face_categories = FALSE;
  for (int i = 0; i < NFaces(); i++) {
    R3MeshFace *f = Face(i);
    if (f->material != -1) has_face_materials = TRUE;
    if (f->segment != -1) has_face_segments = TRUE;
    if (f->category != -1) has_face_categories = TRUE;
  }
  
  // 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 *) "nx", PLY_FLOAT, PLY_FLOAT, offsetof(PlyVertex,nx), 0, 0, 0, 0},
    {(char *) "ny", PLY_FLOAT, PLY_FLOAT, offsetof(PlyVertex,ny), 0, 0, 0, 0},
    {(char *) "nz", PLY_FLOAT, PLY_FLOAT, offsetof(PlyVertex,nz), 0, 0, 0, 0},
    {(char *) "tx", PLY_FLOAT, PLY_FLOAT, offsetof(PlyVertex,tx), 0, 0, 0, 0},
    {(char *) "ty", PLY_FLOAT, PLY_FLOAT, offsetof(PlyVertex,ty), 0, 0, 0, 0},
    {(char *) "red", PLY_UCHAR, PLY_UCHAR, offsetof(PlyVertex,red), 0, 0, 0, 0},
    {(char *) "green", PLY_UCHAR, PLY_UCHAR, offsetof(PlyVertex,green), 0, 0, 0, 0},
    {(char *) "blue", PLY_UCHAR, PLY_UCHAR, offsetof(PlyVertex,blue), 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 *) "material_id", PLY_INT, PLY_INT, offsetof(PlyFace,material), 0, 0, 0, 0},
    {(char *) "segment_id", PLY_INT, PLY_INT, offsetof(PlyFace,segment), 0, 0, 0, 0},
    {(char *) "category_id", PLY_INT, PLY_INT, offsetof(PlyFace,category), 0, 0, 0, 0}
  };

  // Open ply file
  int file_type = (binary) ? PLY_BINARY_NATIVE : PLY_ASCII;
  PlyFile *ply = ply_write (fp, 2, elem_names, file_type);
  if (!ply) return 0;

  // Describe vertex properties
  ply_element_count(ply, (char *) "vertex", NVertices());
  ply_describe_property(ply, (char *) "vertex", &vert_props[0]);
  ply_describe_property(ply, (char *) "vertex", &vert_props[1]);
  ply_describe_property(ply, (char *) "vertex", &vert_props[2]);
  if (has_vertex_normals) {
    ply_describe_property(ply, (char *) "vertex", &vert_props[3]);
    ply_describe_property(ply, (char *) "vertex", &vert_props[4]);
    ply_describe_property(ply, (char *) "vertex", &vert_props[5]);
  }
  if (has_vertex_texcoords) {
    ply_describe_property(ply, (char *) "vertex", &vert_props[6]);
    ply_describe_property(ply, (char *) "vertex", &vert_props[7]);
  }
  if (has_vertex_colors) {
    ply_describe_property(ply, (char *) "vertex", &vert_props[8]);
    ply_describe_property(ply, (char *) "vertex", &vert_props[9]);
    ply_describe_property(ply, (char *) "vertex", &vert_props[10]);
  }

  // Describe face properties
  ply_element_count(ply, (char *) "face", NFaces());
  ply_describe_property(ply, (char *) "face", &face_props[0]);
  if (has_face_materials) {
    ply_describe_property(ply, (char *) "face", &face_props[1]);
  }
  if (has_face_segments) {
    ply_describe_property(ply, (char *) "face", &face_props[2]);
  }
  if (has_face_categories) {
    ply_describe_property(ply, (char *) "face", &face_props[3]);
  }
  
  // Complete header
  ply_header_complete(ply);

  // Write vertices
  ply_put_element_setup(ply, (char *) "vertex");
  for (int i = 0; i < NVertices(); i++) {
    R3MeshVertex *v = Vertex(i);
    const R3Point& p = VertexPosition(v);
    const R3Vector& n = VertexNormal(v);
    const R2Point& t = VertexTextureCoords(v);
    const RNRgb& c = VertexColor(v);
    PlyVertex ply_vertex;
    ply_vertex.x = p.X();
    ply_vertex.y = p.Y();
    ply_vertex.z = p.Z();
    ply_vertex.nx = n.X();
    ply_vertex.ny = n.Y();
    ply_vertex.nz = n.Z();
    ply_vertex.tx = t.X();
    ply_vertex.ty = t.Y();
    ply_vertex.red = (unsigned char) (255.0 * c.R());
    ply_vertex.green = (unsigned char) (255.0 * c.G());
    ply_vertex.blue = (unsigned char) (255.0 * c.B());
    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.material = FaceMaterial(f);
    ply_face.segment = FaceSegment(f);
    ply_face.category = FaceCategory(f);
    ply_put_element(ply, (void *) &ply_face);
  }

  // Free the memory
  free(ply);

  // Return success
  return 1;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x58, %rsp
movl %edx, 0xc(%rsp)
movq %rsi, (%rsp)
movq %rdi, %rbx
xorl %r14d, %r14d
pushq $0x1
popq %r15
xorl %r13d, %r13d
xorl %ecx, %ecx
xorl %ebp, %ebp
movslq 0x14(%rbx), %rax
cmpq %rax, %r14
jge 0x20081
movq 0x8(%rbx), %rax
movq (%rax,%r14,8), %rdi
testb $0x2, 0x78(%rdi)
cmovnel %r15d, %ebp
movsd 0x50(%rdi), %xmm0
movsd 0x48(%rdi), %xmm1
xorpd %xmm2, %xmm2
cmpneqpd %xmm2, %xmm1
cmpneqpd %xmm2, %xmm0
orpd %xmm1, %xmm0
movd %xmm0, %eax
movl %r15d, %r12d
testb $0x1, %al
jne 0x2006a
movl %ecx, %r12d
addq $0x58, %rdi
callq 0x2236e
testl %eax, %eax
cmovel %r15d, %r13d
incq %r14
movl %r12d, %ecx
jmp 0x20027
movl %ecx, 0x8(%rsp)
movl 0x34(%rbx), %eax
movq 0x28(%rbx), %rcx
xorl %edx, %edx
testl %eax, %eax
cmovlel %edx, %eax
pushq $0x1
popq %rdi
xorl %r12d, %r12d
xorl %r15d, %r15d
xorl %r14d, %r14d
cmpq %rdx, %rax
je 0x200ce
movq (%rcx,%rdx,8), %rsi
cmpl $-0x1, 0x98(%rsi)
cmovnel %edi, %r14d
cmpl $-0x1, 0x9c(%rsi)
cmovnel %edi, %r15d
cmpl $-0x1, 0xa0(%rsi)
cmovnel %edi, %r12d
incq %rdx
jmp 0x2009f
movapd 0xb661a(%rip), %xmm0    # 0xd66f0
leaq 0x40(%rsp), %rdx
movapd %xmm0, (%rdx)
xorl %eax, %eax
cmpl $0x0, 0xc(%rsp)
setne %al
leal 0x1(%rax,%rax,2), %ecx
pushq $0x2
popq %rsi
movq (%rsp), %rdi
callq 0x38de4
testq %rax, %rax
je 0x203ee
movl 0x14(%rbx), %edx
leaq 0x734e3(%rip), %rsi     # 0x935ef
movq %rax, %rdi
movq %rax, (%rsp)
callq 0x3941f
leaq 0xba671(%rip), %rdx     # 0xda790
movq (%rsp), %rdi
leaq 0x734c5(%rip), %rsi     # 0x935ef
callq 0x39203
leaq 0xba682(%rip), %rdx     # 0xda7b8
movq (%rsp), %rdi
leaq 0x734ae(%rip), %rsi     # 0x935ef
callq 0x39203
leaq 0xba693(%rip), %rdx     # 0xda7e0
movq (%rsp), %rdi
leaq 0x73497(%rip), %rsi     # 0x935ef
callq 0x39203
testl %ebp, %ebp
movq (%rsp), %rbp
je 0x201a7
leaq 0x73483(%rip), %rsi     # 0x935ef
leaq 0xba695(%rip), %rdx     # 0xda808
movq %rbp, %rdi
callq 0x39203
leaq 0xba6ae(%rip), %rdx     # 0xda830
movq %rbp, %rdi
leaq 0x73463(%rip), %rsi     # 0x935ef
callq 0x39203
leaq 0xba6c0(%rip), %rdx     # 0xda858
movq %rbp, %rdi
leaq 0x7344d(%rip), %rsi     # 0x935ef
callq 0x39203
cmpl $0x0, 0x8(%rsp)
je 0x201da
leaq 0x7343a(%rip), %rsi     # 0x935ef
leaq 0xba6c4(%rip), %rdx     # 0xda880
movq %rbp, %rdi
callq 0x39203
leaq 0xba6dd(%rip), %rdx     # 0xda8a8
movq %rbp, %rdi
leaq 0x7341a(%rip), %rsi     # 0x935ef
callq 0x39203
testl %r13d, %r13d
je 0x2021c
leaq 0x73409(%rip), %r13     # 0x935ef
leaq 0xba6e3(%rip), %rdx     # 0xda8d0
movq %rbp, %rdi
movq %r13, %rsi
callq 0x39203
leaq 0xba6f9(%rip), %rdx     # 0xda8f8
movq %rbp, %rdi
movq %r13, %rsi
callq 0x39203
leaq 0xba70f(%rip), %rdx     # 0xda920
movq %rbp, %rdi
movq %r13, %rsi
callq 0x39203
movl 0x34(%rbx), %edx
leaq 0x733d0(%rip), %r13     # 0x935f6
movq %rbp, %rdi
movq %r13, %rsi
callq 0x3941f
leaq 0xba718(%rip), %rdx     # 0xda950
movq %rbp, %rdi
movq %r13, %rsi
callq 0x39203
testl %r14d, %r14d
je 0x2025e
leaq 0x733a7(%rip), %rsi     # 0x935f6
leaq 0xba722(%rip), %rdx     # 0xda978
movq %rbp, %rdi
callq 0x39203
testl %r15d, %r15d
je 0x20279
leaq 0x7338c(%rip), %rsi     # 0x935f6
leaq 0xba72f(%rip), %rdx     # 0xda9a0
movq %rbp, %rdi
callq 0x39203
testl %r12d, %r12d
je 0x20294
leaq 0x73371(%rip), %rsi     # 0x935f6
leaq 0xba73c(%rip), %rdx     # 0xda9c8
movq %rbp, %rdi
callq 0x39203
movq %rbp, %rdi
callq 0x3945e
leaq 0x7334c(%rip), %rsi     # 0x935ef
movq %rbp, %rdi
callq 0x39682
xorl %r14d, %r14d
leaq 0x10(%rsp), %r15
movslq 0x14(%rbx), %rax
cmpq %rax, %r14
jge 0x20369
movq 0x8(%rbx), %rax
movq (%rax,%r14,8), %r12
movq %rbx, %rdi
movq %r12, %rsi
callq 0x21234
movupd 0x18(%r12), %xmm0
movsd 0x28(%r12), %xmm1
movhpd (%rax), %xmm1           # xmm1 = xmm1[0],mem[0]
cvtpd2ps %xmm1, %xmm1
cvtpd2ps %xmm0, %xmm0
unpcklpd %xmm1, %xmm0            # xmm0 = xmm0[0],xmm1[0]
movapd %xmm0, 0x10(%rsp)
movupd 0x8(%rax), %xmm0
movupd 0x48(%r12), %xmm1
cvtpd2ps %xmm1, %xmm1
cvtpd2ps %xmm0, %xmm0
unpcklpd %xmm1, %xmm0            # xmm0 = xmm0[0],xmm1[0]
movapd %xmm0, 0x20(%rsp)
movsd 0x58(%r12), %xmm0
movsd 0x72ef4(%rip), %xmm1    # 0x93218
mulsd %xmm1, %xmm0
cvttsd2si %xmm0, %eax
movb %al, 0x30(%rsp)
movsd 0x60(%r12), %xmm0
mulsd %xmm1, %xmm0
cvttsd2si %xmm0, %eax
movb %al, 0x31(%rsp)
movsd 0x68(%r12), %xmm0
mulsd %xmm1, %xmm0
cvttsd2si %xmm0, %eax
movb %al, 0x32(%rsp)
movq %rbp, %rdi
movq %r15, %rsi
callq 0x396c5
incq %r14
jmp 0x202b3
leaq 0x73286(%rip), %rsi     # 0x935f6
movq %rbp, %rdi
callq 0x39682
xorl %r14d, %r14d
leaq 0xba66e(%rip), %r15     # 0xda9f0
movslq 0x34(%rbx), %rax
cmpq %rax, %r14
jge 0x203e1
movq 0x28(%rbx), %rax
movq (%rax,%r14,8), %rax
movq 0x8(%rax), %rcx
movl 0x70(%rcx), %ecx
movq 0xba657(%rip), %rdx     # 0xda9f8
movl %ecx, (%rdx)
movq 0x10(%rax), %rcx
movl 0x70(%rcx), %ecx
movl %ecx, 0x4(%rdx)
movq 0x18(%rax), %rcx
movl 0x70(%rcx), %ecx
movl %ecx, 0x8(%rdx)
movq 0x98(%rax), %rcx
movq %rcx, 0xba63b(%rip)     # 0xdaa00
movl 0xa0(%rax), %eax
movl %eax, 0xba637(%rip)     # 0xdaa08
movq %rbp, %rdi
movq %r15, %rsi
callq 0x396c5
incq %r14
jmp 0x20382
movq %rbp, %rdi
callq 0xe560
pushq $0x1
popq %rax
jmp 0x203f0
xorl %eax, %eax
addq $0x58, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
nop