// File: /workspace/github_cpp_makefile_star2_O3/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 $0x68, %rsp
movq %rdi, %rbx
movslq 0x14(%rdi), %rax
movb $0x1, 0xf(%rsp)
movb $0x1, %r12b
movb $0x1, %r13b
movb $0x1, %bpl
testq %rax, %rax
jle 0x22811
movq 0x8(%rbx), %rcx
xorl %edi, %edi
xorpd %xmm0, %xmm0
xorl %r9d, %r9d
xorl %ebp, %ebp
xorl %r8d, %r8d
movl $0x1, %r10d
movq (%rcx,%rdi,8), %r14
testb $0x2, 0x78(%r14)
cmovnel %r10d, %r9d
movsd 0x50(%r14), %xmm1
movsd 0x48(%r14), %xmm2
cmpneqpd %xmm0, %xmm2
cmpneqpd %xmm0, %xmm1
orpd %xmm2, %xmm1
movd %xmm1, %r15d
movl $0x1, %r11d
testb $0x1, %r15b
jne 0x227b9
movl %ebp, %r11d
movsd 0x60(%r14), %xmm1
movsd 0x58(%r14), %xmm2
cmpneqpd %xmm0, %xmm2
cmpneqpd %xmm0, %xmm1
orpd %xmm2, %xmm1
movsd 0x68(%r14), %xmm2
ucomisd %xmm0, %xmm2
cmovnel %r10d, %r8d
cmovpl %r10d, %r8d
movd %xmm1, %ebp
testb $0x1, %bpl
cmovnel %r10d, %r8d
incq %rdi
movl %r11d, %ebp
cmpq %rdi, %rax
jne 0x2277e
testl %r9d, %r9d
sete %bpl
testl %r11d, %r11d
sete %r13b
testl %r8d, %r8d
sete %r12b
movslq 0x34(%rbx), %rax
testq %rax, %rax
jle 0x2288b
movq 0x28(%rbx), %rcx
xorpd %xmm2, %xmm2
xorl %edi, %edi
pcmpeqd %xmm0, %xmm0
movapd 0x7faa0(%rip), %xmm1    # 0xa22d0
movl $0x1, %r9d
xorl %r8d, %r8d
movq (%rcx,%rdi,8), %r10
movapd %xmm2, %xmm3
movq 0x98(%r10), %xmm2
pcmpeqd %xmm0, %xmm2
andpd %xmm2, %xmm3
andnpd %xmm1, %xmm2
orpd %xmm3, %xmm2
cmpl $-0x1, 0xa0(%r10)
cmovnel %r9d, %r8d
incq %rdi
cmpq %rdi, %rax
jne 0x22839
pshufd $0xd4, %xmm2, %xmm0     # xmm0 = xmm2[0,1,1,3]
xorpd %xmm1, %xmm1
pcmpeqd %xmm0, %xmm1
movdqa %xmm1, 0x10(%rsp)
testl %r8d, %r8d
sete 0xf(%rsp)
jmp 0x22899
movdqa 0x7fa2d(%rip), %xmm0    # 0xa22c0
movdqa %xmm0, 0x10(%rsp)
movdqa 0xbee3f(%rip), %xmm0    # 0xe16e0
leaq 0x50(%rsp), %rax
movdqa %xmm0, (%rax)
xorl %ecx, %ecx
testl %edx, %edx
setne %cl
leal 0x1(%rcx,%rcx,2), %ecx
movq %rsi, %rdi
movl $0x2, %esi
movq %rax, %rdx
callq 0x3dd98
testq %rax, %rax
je 0x22bcc
movq %rax, %r14
movl 0x14(%rbx), %edx
leaq 0x7fd64(%rip), %r15     # 0xa263f
movq %rax, %rdi
movq %r15, %rsi
callq 0x3e38a
leaq 0xc2e93(%rip), %rdx     # 0xe5780
movq %r14, %rdi
movq %r15, %rsi
callq 0x3e168
leaq 0xc2ea9(%rip), %rdx     # 0xe57a8
movq %r14, %rdi
movq %r15, %rsi
callq 0x3e168
leaq 0xc2ebf(%rip), %rdx     # 0xe57d0
movq %r14, %rdi
movq %r15, %rsi
callq 0x3e168
testb %bpl, %bpl
jne 0x2295e
leaq 0x7fd17(%rip), %r15     # 0xa263f
leaq 0xc2ec9(%rip), %rdx     # 0xe57f8
movq %r14, %rdi
movq %r15, %rsi
callq 0x3e168
leaq 0xc2edf(%rip), %rdx     # 0xe5820
movq %r14, %rdi
movq %r15, %rsi
callq 0x3e168
leaq 0xc2ef5(%rip), %rdx     # 0xe5848
movq %r14, %rdi
movq %r15, %rsi
callq 0x3e168
testb %r13b, %r13b
jne 0x2298e
leaq 0x7fcd5(%rip), %r15     # 0xa263f
leaq 0xc2eff(%rip), %rdx     # 0xe5870
movq %r14, %rdi
movq %r15, %rsi
callq 0x3e168
leaq 0xc2f15(%rip), %rdx     # 0xe5898
movq %r14, %rdi
movq %r15, %rsi
callq 0x3e168
testb %r12b, %r12b
jne 0x229d0
leaq 0x7fca5(%rip), %r15     # 0xa263f
leaq 0xc2f1f(%rip), %rdx     # 0xe58c0
movq %r14, %rdi
movq %r15, %rsi
callq 0x3e168
leaq 0xc2f35(%rip), %rdx     # 0xe58e8
movq %r14, %rdi
movq %r15, %rsi
callq 0x3e168
leaq 0xc2f4b(%rip), %rdx     # 0xe5910
movq %r14, %rdi
movq %r15, %rsi
callq 0x3e168
movl 0x34(%rbx), %edx
leaq 0x7fc6c(%rip), %r15     # 0xa2646
movq %r14, %rdi
movq %r15, %rsi
callq 0x3e38a
leaq 0xc2f54(%rip), %rdx     # 0xe5940
movq %r14, %rdi
movq %r15, %rsi
callq 0x3e168
movdqa 0x10(%rsp), %xmm0
movd %xmm0, %eax
testb $0x1, %al
jne 0x22a1b
leaq 0x7fc3a(%rip), %rsi     # 0xa2646
leaq 0xc2f55(%rip), %rdx     # 0xe5968
movq %r14, %rdi
callq 0x3e168
movdqa 0x10(%rsp), %xmm0
pextrw $0x4, %xmm0, %eax
testb $0x1, %al
jne 0x22a40
leaq 0x7fc15(%rip), %rsi     # 0xa2646
leaq 0xc2f58(%rip), %rdx     # 0xe5990
movq %r14, %rdi
callq 0x3e168
cmpb $0x0, 0xf(%rsp)
jne 0x22a5d
leaq 0x7fbf8(%rip), %rsi     # 0xa2646
leaq 0xc2f63(%rip), %rdx     # 0xe59b8
movq %r14, %rdi
callq 0x3e168
movq %r14, %rdi
callq 0x3e3b0
leaq 0x7fbd3(%rip), %rsi     # 0xa263f
movq %r14, %rdi
callq 0x3e5c9
cmpl $0x0, 0x14(%rbx)
jle 0x22b41
xorl %r13d, %r13d
leaq 0x20(%rsp), %r15
movq 0x8(%rbx), %rax
movq (%rax,%r13,8), %r12
testb $0x2, 0x78(%r12)
jne 0x22aa5
movq (%rbx), %rax
movq %rbx, %rdi
movq %r12, %rsi
callq *0x2b0(%rax)
movupd 0x18(%r12), %xmm0
movupd 0x28(%r12), %xmm1
cvtpd2ps %xmm1, %xmm1
cvtpd2ps %xmm0, %xmm0
unpcklpd %xmm1, %xmm0            # xmm0 = xmm0[0],xmm1[0]
movapd %xmm0, 0x20(%rsp)
movupd 0x38(%r12), %xmm0
movupd 0x48(%r12), %xmm1
cvtpd2ps %xmm1, %xmm1
cvtpd2ps %xmm0, %xmm0
unpcklpd %xmm1, %xmm0            # xmm0 = xmm0[0],xmm1[0]
movapd %xmm0, 0x30(%rsp)
movsd 0x58(%r12), %xmm0
movsd 0x7f724(%rip), %xmm1    # 0xa2218
mulsd %xmm1, %xmm0
cvttsd2si %xmm0, %eax
movb %al, 0x40(%rsp)
movsd 0x60(%r12), %xmm0
mulsd %xmm1, %xmm0
cvttsd2si %xmm0, %eax
movb %al, 0x41(%rsp)
movsd 0x68(%r12), %xmm0
mulsd %xmm1, %xmm0
cvttsd2si %xmm0, %eax
movb %al, 0x42(%rsp)
movq %r14, %rdi
movq %r15, %rsi
callq 0x3e5f1
incq %r13
movslq 0x14(%rbx), %rax
cmpq %rax, %r13
jl 0x22a86
leaq 0x7fafe(%rip), %rsi     # 0xa2646
movq %r14, %rdi
callq 0x3e5c9
cmpl $0x0, 0x34(%rbx)
jle 0x22bbd
xorl %r12d, %r12d
leaq 0xc2e80(%rip), %r15     # 0xe59e0
movq 0x28(%rbx), %rax
movq (%rax,%r12,8), %rax
movq 0x8(%rax), %rcx
movl 0x70(%rcx), %ecx
movq 0xc2e72(%rip), %rdx     # 0xe59e8
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, 0xc2e56(%rip)     # 0xe59f0
movl 0xa0(%rax), %eax
movl %eax, 0xc2e52(%rip)     # 0xe59f8
movq %r14, %rdi
movq %r15, %rsi
callq 0x3e5f1
incq %r12
movslq 0x34(%rbx), %rax
cmpq %rax, %r12
jl 0x22b60
movq %r14, %rdi
callq 0xe540
movl $0x1, %eax
jmp 0x22bce
xorl %eax, %eax
addq $0x68, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
nop