// File: /workspace/github_cpp_makefile_star2_O2/tomfunkhouser[P]gaps/pkgs/R3Surfels/R3SurfelBlock.cpp
// Function: gaps::R3SurfelBlock::Draw(gaps::RNFlags, int) const
void R3SurfelBlock::
Draw(RNFlags flags, int subsampling_factor) const
{
  // Just checking
  if (nsurfels == 0) return;
  if (subsampling_factor < 1) subsampling_factor = 1;
  int c = flags[R3_SURFEL_COLOR_DRAW_FLAG];
  
  // Push translation to position_origin
  glPushMatrix();
  glTranslated(position_origin[0], position_origin[1], position_origin[2]);

#if (R3_SURFEL_BLOCK_DRAW_METHOD == R3_SURFEL_BLOCK_DRAW_WITH_DISPLAY_LIST)
  // Create a display list id to use to detect errors
  static GLuint error_id = 0;
  if (error_id == 0) error_id = glGenLists(1);

  // Create display list for block
  if (opengl_id == 0) {
    R3SurfelBlock *block = (R3SurfelBlock *) this;
    block->opengl_id = error_id;
    glGetError();
    GLuint id = glGenLists(2);
    if ((id > 0) && (glGetError() == GL_NO_ERROR)) {
      glNewList(id, GL_COMPILE);
#     if 1
        // Draw without color using arrays
        glEnableClientState(GL_VERTEX_ARRAY);
        glVertexPointer(3, GL_FLOAT, sizeof(R3Surfel), surfels);
        glDrawArrays(GL_POINTS, 0, NSurfels());
        glDisableClientState(GL_VERTEX_ARRAY);
#     else
        // Draw without color using RNGrfxBegin and RNGrfxEnd
        RNGrfxBegin(RN_GRFX_POINTS);
        for (int i = 0; i < NSurfels(); i++) {
          const R3Surfel& surfel = surfels[i];
          R3LoadPoint(surfel.PositionPtr());
        }
        RNGrfxEnd();
#     endif
      RNGrfxEndList();
      if (glGetError() == GL_NO_ERROR) {
        glNewList(id+1, GL_COMPILE);
#       if 0
          // Draw with color using arrays
          glEnableClientState(GL_VERTEX_ARRAY);
          glEnableClientState(GL_COLOR_ARRAY);
          glVertexPointer(3, GL_FLOAT, sizeof(R3Surfel), surfels);
          glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(R3Surfel), surfels[0].ColorPtr());
          glDrawArrays(GL_POINTS, 0, NSurfels());
          glDisableClientState(GL_VERTEX_ARRAY);
          glDisableClientState(GL_COLOR_ARRAY);
#       else
          // Draw with color using RNGrfxBegin and RNGrfxEnd
          RNGrfxBegin(RN_GRFX_POINTS);
          for (int i = 0; i < NSurfels(); i++) {
            const R3Surfel& surfel = surfels[i];
            RNLoadRgb(surfel.ColorPtr());
            R3LoadPoint(surfel.PositionPtr());
          }
          RNGrfxEnd();
#       endif
        RNGrfxEndList();
        if (glGetError() == GL_NO_ERROR) {
          block->opengl_id = id;
        }
      }
      if (opengl_id == error_id) {
        glDeleteLists(id, 2);
      }
    }
  }

  // Draw surfels
  if (opengl_id != error_id) {
    // Use display list if available
    glCallList((c) ? opengl_id + 1 : opengl_id);
  }
  else {
    // Draw surfels the slow way
    if (c) {
      // Draw surfels (with color)
      RNGrfxBegin(RN_GRFX_POINTS);
      for (int i = 0; i < NSurfels(); i++) {
        const R3Surfel& surfel = surfels[i];
        RNLoadRgb(surfel.ColorPtr());
        R3LoadPoint(surfel.PositionPtr());
      }
      RNGrfxEnd();
    }
    else {
      // Draw surfels without color
      RNGrfxBegin(RN_GRFX_POINTS);
      for (int i = 0; i < NSurfels(); i++) {
        const R3Surfel& surfel = surfels[i];
        R3LoadPoint(surfel.PositionPtr());
      }
      RNGrfxEnd();
    }
  }
#elif (R3_SURFEL_BLOCK_DRAW_METHOD == R3_SURFEL_BLOCK_DRAW_WITH_VBO)
  // Create a VBO id to use to detect errors
  static GLuint error_buffer_id = 0;
  if (error_buffer_id == 0) {
    glGenBuffers(1, &error_buffer_id);
    if (glGetError() != GL_NO_ERROR) {
      printf("Error in glGenBuffers\n");
    }
  }
  
  // Create a VBO for block
  if (opengl_id == 0) {
    GLuint buffer_id;
    ((R3SurfelBlock *) this)->opengl_id = error_buffer_id;
    glGenBuffers(1, &buffer_id);
    if (buffer_id > 0) {
      glBindBuffer(GL_ARRAY_BUFFER, buffer_id);
      glBufferData(GL_ARRAY_BUFFER, NSurfels() * sizeof(R3Surfel), surfels, GL_STATIC_DRAW);
      if (glGetError() == GL_NO_ERROR) {
        ((R3SurfelBlock *) this)->opengl_id = buffer_id;
      }
    }
  }

  // Draw surfels
  glEnableClientState(GL_VERTEX_ARRAY);
  if (c) glEnableClientState(GL_COLOR_ARRAY);
  else glDisableClientState(GL_COLOR_ARRAY);
  if (opengl_id != error_buffer_id) {
    // Draw surfels using VBO arrays
    static R3Surfel tmp;
    static unsigned long int position_offset = (unsigned char *) tmp.PositionPtr() - (unsigned char *) &tmp;
    static unsigned long int color_offset = (unsigned char *) tmp.ColorPtr() - (unsigned char *) &tmp;
    glBindBuffer(GL_ARRAY_BUFFER, opengl_id);
    glVertexPointer(3, GL_FLOAT, sizeof(R3Surfel), (const void *) position_offset);
    if (c) glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(R3Surfel), (const void *)color_offset);
  }
  else {
    // Draw surfels using client-side arrays
    glVertexPointer(3, GL_FLOAT, sizeof(R3Surfel), surfels[0].PositionPtr());
    if (c) glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(R3Surfel), surfels[0].ColorPtr());
  }
  glDrawArrays(GL_POINTS, 0, NSurfels());
#elif (R3_SURFEL_BLOCK_DRAW_METHOD == R3_SURFEL_BLOCK_DRAW_WITH_ARRAYS)
  // Draw surfels using arrays
  glEnableClientState(GL_VERTEX_ARRAY);
  if (c) glEnableClientState(GL_COLOR_ARRAY);
  else glDisableClientState(GL_COLOR_ARRAY);
  glVertexPointer(3, GL_FLOAT, sizeof(R3Surfel), surfels[0].PositionPtr());
  if (c) glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(R3Surfel), surfels[0].ColorPtr());
  glDrawArrays(GL_POINTS, 0, NSurfels());
#else
  // Get convenient variables
  int n = flags[R3_SURFEL_NORMAL_DRAW_FLAG];
  int id = flags[R3_SURFEL_IDENTIFIER_DRAW_FLAG];

  // Draw surfels using RNGrfxBegin ... RNGrfxEnd
  if (flags[R3_SURFEL_DISC_DRAW_FLAG] && HasNormals() && HasTangents()) {
    // Draw discs
    const int nsides = 6;
    RNGrfxBegin(RN_GRFX_TRIANGLES);
    for (int i = 0; i < NSurfels(); i += subsampling_factor) {
      const R3Surfel& surfel = surfels[i];
      R3Vector normal(surfel.NX(), surfel.NY(), surfel.NZ());
      R3Vector tangent1(surfel.TX(), surfel.TY(), surfel.TZ());
      R3Vector tangent2 = normal % tangent1;
      double r1 = surfel.Radius(0);
      double r2 = surfel.Radius(1);
      if (r1 <= 0) r1 = 0.1;
      if (r2 <= 0) r2 = r1;
      if (c) RNLoadRgb(surfel.ColorPtr());
      if (id) RNLoadRgba(surfel.Identifier());
      else if (n) R3LoadNormal(normal);
      R3Point p[nsides];
      for (int j = 0; j < nsides; j++) {
        double angle = RN_TWO_PI*j/nsides;
        p[j].Reset(surfel.PX(), surfel.PY(), surfel.PZ());
        p[j] += cos(angle) * r1 * tangent1;
        p[j] += sin(angle) * r2 * tangent2;
      }
      for (int j = 0; j < nsides; j++) {
        R3LoadPoint(surfel.PositionPtr());
        R3LoadPoint(p[j]);
        R3LoadPoint(p[(j+1)%nsides]);
      }
    }
    RNGrfxEnd();        
  }
  else {
    // Draw points
    RNGrfxBegin(RN_GRFX_POINTS);
    for (int i = 0; i < NSurfels(); i += subsampling_factor) {
      const R3Surfel& surfel = surfels[i];
      if (c) RNLoadRgb(surfel.ColorPtr());
      if (id) RNLoadRgba(surfel.Identifier());
      else if (n) R3LoadNormal(surfel.NX(), surfel.NY(), surfel.NZ());
      R3LoadPoint(surfel.PositionPtr());
    }
    RNGrfxEnd();
  }
#endif
  
  // Pop translation to position_origin
  glPopMatrix();
}

// Assembly:
cmpl $0x0, 0x8(%rdi)
je 0x2ba4c
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x148, %rsp            # imm = 0x148
movq %rdi, %r14
cmpl $0x2, %edx
movq %rsi, %rbx
pushq $0x1
popq %rbp
cmovgel %edx, %ebp
callq 0x13850
movsd 0x10(%r14), %xmm0
movsd 0x18(%r14), %xmm1
movsd 0x20(%r14), %xmm2
callq 0x13560
movl %ebx, %eax
shrl %eax
movl %eax, 0x8(%rsp)
movl %ebx, %eax
shrl $0x2, %eax
movl %eax, 0xc(%rsp)
movq %rbx, 0x18(%rsp)
testb $0x10, %bl
movq %r14, 0x20(%rsp)
je 0x2b98b
movq %r14, %rdi
callq 0x2abd2
testl %eax, %eax
je 0x2b98b
movq %r14, %rdi
callq 0x2abf6
testl %eax, %eax
je 0x2b98b
pushq $0x4
popq %rdi
callq 0x13130
leaq 0xa6069(%rip), %rax     # 0xd1778
movsd (%rax), %xmm0
movsd %xmm0, 0x40(%rsp)
movl %ebp, %eax
movq %rax, 0x30(%rsp)
xorl %ecx, %ecx
leaq 0x98(%rsp), %r12
leaq 0x80(%rsp), %r13
leaq 0x68(%rsp), %rbp
movslq 0x8(%r14), %rax
cmpq %rax, %rcx
jge 0x2ba31
movq (%r14), %r15
movq %rcx, 0x38(%rsp)
imulq $0x30, %rcx, %rbx
movswl 0x10(%r15,%rbx), %eax
cvtsi2ss %eax, %xmm0
movss 0x9cc9e(%rip), %xmm3    # 0xc8400
mulss %xmm3, %xmm0
cvtss2sd %xmm0, %xmm0
movswl 0x12(%r15,%rbx), %eax
cvtsi2ss %eax, %xmm1
movswl 0x14(%r15,%rbx), %eax
cvtsi2ss %eax, %xmm2
mulss %xmm3, %xmm1
cvtss2sd %xmm1, %xmm1
mulss %xmm3, %xmm2
cvtss2sd %xmm2, %xmm2
leaq 0x50(%rsp), %r14
movq %r14, %rdi
callq 0x7897c
movswl 0x16(%r15,%rbx), %eax
cvtsi2ss %eax, %xmm0
movss 0x9cc53(%rip), %xmm3    # 0xc8400
mulss %xmm3, %xmm0
cvtss2sd %xmm0, %xmm0
movswl 0x18(%r15,%rbx), %eax
cvtsi2ss %eax, %xmm1
movswl 0x1a(%r15,%rbx), %eax
cvtsi2ss %eax, %xmm2
mulss %xmm3, %xmm1
cvtss2sd %xmm1, %xmm1
mulss %xmm3, %xmm2
cvtss2sd %xmm2, %xmm2
movq %r12, %rdi
callq 0x7897c
movq %r13, %rdi
movq %r14, %rsi
movq %r12, %rdx
callq 0x7902e
movd 0x1c(%r15,%rbx), %xmm0
xorps %xmm2, %xmm2
punpcklwd %xmm2, %xmm0    # xmm0 = xmm0[0],xmm2[0],xmm0[1],xmm2[1],xmm0[2],xmm2[2],xmm0[3],xmm2[3]
cvtdq2ps %xmm0, %xmm0
mulps 0x9cbe9(%rip), %xmm0    # 0xc83f0
movaps %xmm0, %xmm1
cmpnleps %xmm2, %xmm1
unpcklps %xmm1, %xmm1            # xmm1 = xmm1[0,0,1,1]
movmskpd %xmm1, %eax
testb $0x1, %al
jne 0x2b823
movsd 0x9cb4f(%rip), %xmm1    # 0xc8370
jmp 0x2b827
cvtss2sd %xmm0, %xmm1
movsd %xmm1, 0x10(%rsp)
testb $0x2, %al
jne 0x2b839
movsd 0x10(%rsp), %xmm0
jmp 0x2b841
shufps $0x55, %xmm0, %xmm0     # xmm0 = xmm0[1,1,1,1]
cvtss2sd %xmm0, %xmm0
movsd %xmm0, 0x28(%rsp)
addq %rbx, %r15
testb $0x1, 0x18(%rsp)
je 0x2b85a
leaq 0x2c(%r15), %rdi
callq 0x13680
testb $0x1, 0xc(%rsp)
jne 0x2b874
testb $0x1, 0x8(%rsp)
je 0x2b87d
leaq 0x50(%rsp), %rdi
callq 0x137c0
jmp 0x2b87d
movl 0x20(%r15), %edi
callq 0x2d196
xorl %ebx, %ebx
leaq (%rsp,%rbx), %rdi
addq $0xb0, %rdi
callq 0x781ba
addq $0x18, %rbx
cmpq $0x90, %rbx
jne 0x2b87f
leaq 0xb0(%rsp), %rbx
xorl %r14d, %r14d
cmpq $0x6, %r14
je 0x2b92c
cvtsi2sd %r14d, %xmm0
mulsd 0x40(%rsp), %xmm0
divsd 0x9cab8(%rip), %xmm0    # 0xc8378
movsd %xmm0, 0x48(%rsp)
cvtss2sd 0x8(%r15), %xmm2
cvtps2pd (%r15), %xmm1
movups %xmm1, (%rbx)
movsd %xmm2, 0x10(%rbx)
callq 0x13990
mulsd 0x10(%rsp), %xmm0
movq %rbp, %rdi
movq %r12, %rsi
callq 0x79072
movq %rbx, %rdi
movq %rbp, %rsi
callq 0x7850c
movsd 0x48(%rsp), %xmm0
callq 0x13100
mulsd 0x28(%rsp), %xmm0
movq %rbp, %rdi
movq %r13, %rsi
callq 0x79072
movq %rbx, %rdi
movq %rbp, %rsi
callq 0x7850c
incq %r14
addq $0x18, %rbx
jmp 0x2b8a7
leaq 0xb0(%rsp), %rbx
pushq $-0x6
popq %r14
testq %r14, %r14
je 0x2b977
movq %r15, %rdi
callq 0x13370
movq %rbx, %rdi
callq 0x13150
leaq 0x7(%r14), %rax
incq %r14
movl $0x0, %ecx
cmovneq %rax, %rcx
imulq $0x18, %rcx, %rax
leaq (%rsp,%rax), %rdi
addq $0xb0, %rdi
callq 0x13150
addq $0x18, %rbx
jmp 0x2b938
movq 0x38(%rsp), %rcx
addq 0x30(%rsp), %rcx
movq 0x20(%rsp), %r14
jmp 0x2b737
xorl %ebx, %ebx
xorl %edi, %edi
callq 0x13130
movl %ebp, %r15d
imulq $0x30, %r15, %r12
pushq $0x2c
popq %r13
movq 0x18(%rsp), %rbp
movslq 0x8(%r14), %rax
cmpq %rax, %rbx
jge 0x2ba31
movq (%r14), %r14
testb $0x1, %bpl
je 0x2b9c3
leaq (%r14,%r13), %rdi
callq 0x13680
testb $0x1, 0xc(%rsp)
jne 0x2ba0a
testb $0x1, 0x8(%rsp)
je 0x2ba14
movswl -0x1c(%r14,%r13), %eax
cvtsi2ss %eax, %xmm0
movswl -0x1a(%r14,%r13), %eax
cvtsi2ss %eax, %xmm1
movss 0x9ca13(%rip), %xmm3    # 0xc8400
mulss %xmm3, %xmm0
mulss %xmm3, %xmm1
movswl -0x18(%r14,%r13), %eax
cvtsi2ss %eax, %xmm2
mulss %xmm3, %xmm2
callq 0x13410
jmp 0x2ba14
movl -0xc(%r14,%r13), %edi
callq 0x2d196
leaq (%r14,%r13), %rdi
addq $-0x2c, %rdi
callq 0x13370
addq %r15, %rbx
addq %r12, %r13
movq 0x20(%rsp), %r14
jmp 0x2b9a4
callq 0x136d0
callq 0x13980
addq $0x148, %rsp            # imm = 0x148
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
nop