// File: /workspace/github_cpp_makefile_star2_O3/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 0x2e352
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x138, %rsp            # imm = 0x138
movq %rsi, %r14
movq %rdi, %r15
cmpl $0x2, %edx
movl $0x1, %ebx
cmovgel %edx, %ebx
callq 0x13810
movsd 0x10(%r15), %xmm0
movsd 0x18(%r15), %xmm1
movsd 0x20(%r15), %xmm2
callq 0x13540
movl %r14d, %eax
shrl %eax
movl %eax, (%rsp)
movl %r14d, %eax
shrl $0x2, %eax
movl %eax, 0x4(%rsp)
testb $0x10, %r14b
movq %r14, 0x8(%rsp)
movq %r15, %r14
movq %r15, 0x10(%rsp)
je 0x2e27a
movq 0x88(%r14), %rax
testb $0x4, %al
jne 0x2e25b
movq %r14, %rdi
callq 0x2d232
movq 0x88(%r14), %rax
testb %al, %al
jns 0x2e27a
testb $0x4, %al
jne 0x2e272
movq %r14, %rdi
callq 0x2d232
movq 0x88(%r14), %rax
testb $0x8, %al
jne 0x2e353
xorl %ebp, %ebp
xorl %edi, %edi
callq 0x13130
cmpl $0x0, 0x8(%r14)
jle 0x2e337
movl %ebx, %eax
shlq $0x4, %rax
leaq (%rax,%rax,2), %r12
movl $0x2c, %r13d
leaq 0x60(%rsp), %r15
movq (%r14), %r14
testb $0x1, 0x8(%rsp)
je 0x2e2b6
leaq (%r14,%r13), %rdi
callq 0x13660
testb $0x1, 0x4(%rsp)
jne 0x2e305
testb $0x1, (%rsp)
je 0x2e316
movswl -0x1c(%r14,%r13), %eax
xorps %xmm0, %xmm0
cvtsi2ss %eax, %xmm0
movswl -0x1a(%r14,%r13), %eax
xorps %xmm1, %xmm1
cvtsi2ss %eax, %xmm1
movss 0xaf11b(%rip), %xmm3    # 0xdd400
mulss %xmm3, %xmm0
mulss %xmm3, %xmm1
movswl -0x18(%r14,%r13), %eax
xorps %xmm2, %xmm2
cvtsi2ss %eax, %xmm2
mulss %xmm3, %xmm2
callq 0x13400
jmp 0x2e316
movl -0xc(%r14,%r13), %eax
movl %eax, 0x60(%rsp)
movq %r15, %rdi
callq 0x13260
leaq (%r14,%r13), %rdi
addq $-0x2c, %rdi
callq 0x13360
addq %r12, %r13
addl %ebx, %ebp
movq 0x10(%rsp), %r14
cmpl %ebp, 0x8(%r14)
jg 0x2e2a3
callq 0x136a0
callq 0x13940
addq $0x138, %rsp            # imm = 0x138
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movl $0x4, %edi
callq 0x13130
cmpl $0x0, 0x8(%r14)
jle 0x2e337
leaq 0xb848d(%rip), %rax     # 0xe67f8
movsd (%rax), %xmm0
movsd %xmm0, 0x28(%rsp)
movl %ebx, %eax
movq %rax, 0x18(%rsp)
xorl %eax, %eax
leaq 0x120(%rsp), %r12
leaq 0x108(%rsp), %r13
leaq 0xf0(%rsp), %r15
movq (%r14), %rbp
movq %rax, 0x20(%rsp)
leaq (%rax,%rax,2), %rbx
shlq $0x4, %rbx
movswl 0x10(%rbp,%rbx), %eax
xorps %xmm0, %xmm0
cvtsi2ss %eax, %xmm0
movss 0xaf046(%rip), %xmm3    # 0xdd400
mulss %xmm3, %xmm0
cvtss2sd %xmm0, %xmm0
movswl 0x12(%rbp,%rbx), %eax
xorps %xmm1, %xmm1
cvtsi2ss %eax, %xmm1
movswl 0x14(%rbp,%rbx), %eax
xorps %xmm2, %xmm2
cvtsi2ss %eax, %xmm2
mulss %xmm3, %xmm1
cvtss2sd %xmm1, %xmm1
mulss %xmm3, %xmm2
cvtss2sd %xmm2, %xmm2
leaq 0x48(%rsp), %r14
movq %r14, %rdi
callq 0x84856
movswl 0x16(%rbp,%rbx), %eax
xorps %xmm0, %xmm0
cvtsi2ss %eax, %xmm0
movss 0xaeff5(%rip), %xmm3    # 0xdd400
mulss %xmm3, %xmm0
cvtss2sd %xmm0, %xmm0
movswl 0x18(%rbp,%rbx), %eax
xorps %xmm1, %xmm1
cvtsi2ss %eax, %xmm1
movswl 0x1a(%rbp,%rbx), %eax
xorps %xmm2, %xmm2
cvtsi2ss %eax, %xmm2
mulss %xmm3, %xmm1
cvtss2sd %xmm1, %xmm1
mulss %xmm3, %xmm2
cvtss2sd %xmm2, %xmm2
movq %r12, %rdi
callq 0x84856
movq %r13, %rdi
movq %r14, %rsi
movq %r12, %rdx
callq 0x8518a
movd 0x1c(%rbp,%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 0xaef88(%rip), %xmm0    # 0xdd3f0
movaps %xmm0, %xmm1
cmpnleps %xmm2, %xmm1
unpcklps %xmm1, %xmm1            # xmm1 = xmm1[0,0,1,1]
movmskpd %xmm1, %eax
testb $0x1, %al
jne 0x2e484
movsd 0xaeef6(%rip), %xmm1    # 0xdd378
jmp 0x2e48b
xorps %xmm1, %xmm1
cvtss2sd %xmm0, %xmm1
movq 0x8(%rsp), %rcx
testb $0x2, %al
jne 0x2e499
movaps %xmm1, %xmm0
jmp 0x2e4a1
shufps $0x55, %xmm0, %xmm0     # xmm0 = xmm0[1,1,1,1]
cvtss2sd %xmm0, %xmm0
movsd %xmm0, 0x30(%rsp)
addq %rbx, %rbp
testb $0x1, %cl
movsd %xmm1, 0x38(%rsp)
je 0x2e4be
leaq 0x2c(%rbp), %rdi
callq 0x13660
testb $0x1, 0x4(%rsp)
jne 0x2e4d7
testb $0x1, (%rsp)
je 0x2e4e8
leaq 0x48(%rsp), %rdi
callq 0x13780
jmp 0x2e4e8
movl 0x20(%rbp), %eax
movl %eax, 0x60(%rsp)
leaq 0x60(%rsp), %rdi
callq 0x13260
xorl %ebx, %ebx
leaq (%rsp,%rbx), %rdi
addq $0x60, %rdi
callq 0x83dc0
addq $0x18, %rbx
cmpq $0x90, %rbx
jne 0x2e4ea
leaq 0x60(%rsp), %rbx
xorl %r14d, %r14d
xorps %xmm0, %xmm0
cvtsi2sd %r14d, %xmm0
mulsd 0x28(%rsp), %xmm0
divsd 0xaee5e(%rip), %xmm0    # 0xdd380
movsd %xmm0, 0x40(%rsp)
xorps %xmm2, %xmm2
cvtss2sd 0x8(%rbp), %xmm2
cvtps2pd (%rbp), %xmm1
movups %xmm1, (%rbx)
movsd %xmm2, 0x10(%rbx)
callq 0x13950
mulsd 0x38(%rsp), %xmm0
movq %r15, %rdi
movq %r12, %rsi
callq 0x851f2
movq %rbx, %rdi
movq %r15, %rsi
callq 0x841a4
movsd 0x40(%rsp), %xmm0
callq 0x13100
mulsd 0x30(%rsp), %xmm0
movq %r15, %rdi
movq %r13, %rsi
callq 0x851f2
movq %rbx, %rdi
movq %r15, %rsi
callq 0x841a4
incq %r14
addq $0x18, %rbx
cmpq $0x6, %r14
jne 0x2e50c
movl $0x1, %r14d
leaq 0x60(%rsp), %rbx
movq %rbp, %rdi
callq 0x13360
movq %rbx, %rdi
callq 0x13150
cmpq $0x6, %r14
movl $0x0, %eax
cmovneq %r14, %rax
leaq (%rax,%rax,2), %rax
leaq (%rsp,%rax,8), %rdi
addq $0x60, %rdi
callq 0x13150
addq $0x18, %rbx
incq %r14
cmpq $0x7, %r14
jne 0x2e5a0
movq 0x20(%rsp), %rax
addq 0x18(%rsp), %rax
movq 0x10(%rsp), %r14
cmpl %eax, 0x8(%r14)
jg 0x2e396
jmp 0x2e337
nop