Developer Documentation
SplatCloudNode.cc
1 /*===========================================================================*\
2 * *
3 * OpenFlipper *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openflipper.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenFlipper. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39 * *
40 \*===========================================================================*/
41 
42 
43 
44 //================================================================
45 //
46 // CLASS SplatCloudNode - IMPLEMENTATION
47 //
48 //================================================================
49 
50 
51 //== INCLUDES ====================================================
52 
53 #include <ACG/GL/acg_glew.hh>
54 #include <ACG/GL/IRenderer.hh>
55 
56 #include "SplatCloudNode.hh"
57 
58 
59 //== DEFINES =====================================================
60 
61 
62 //#define REPORT_VBO_UPDATES
63 
64 
65 //== NAMESPACES ==================================================
66 
67 
68 namespace ACG {
69 namespace SceneGraph {
70 
71 //== STATIC MEMBER VARIABLES =====================================
72 
73 
74 const SplatCloudNode::Position SplatCloudNode::DEFAULT_POSITION (0,0,0);
75 const SplatCloudNode::Index SplatCloudNode::DEFAULT_INDEX ( -1);
76 const SplatCloudNode::Viewlist SplatCloudNode::DEFAULT_VIEWLIST ( 0.0);
77 const SplatCloudNode::Selection SplatCloudNode::DEFAULT_SELECTION(false);
78 
79 
80 //== IMPLEMENTATION ==============================================
81 
82 
83 SplatCloudNode::SplatCloudNode( const SplatCloud &_splatCloud, BaseNode *_parent, std::string _name ) :
84  BaseNode ( _parent, _name ),
85  splatCloud_ ( _splatCloud ),
86  positionsModified_ ( false ),
87  colorsModified_ ( false ),
88  normalsModified_ ( false ),
89  pointsizesModified_ ( false ),
90  selectionsModified_ ( false ),
91  pickColorsModified_ ( false ),
92  defaultColor_ ( Color (0,0,0) ),
93  defaultNormal_ ( Normal (0,0,0) ),
94  defaultPointsize_ ( Pointsize( 0.0) ),
95  splatsDrawMode_ ( DrawModes::addDrawMode( "Splats" ) ),
96  dotsDrawMode_ ( DrawModes::addDrawMode( "Dots" ) ),
97  pointsDrawMode_ ( DrawModes::addDrawMode( "Points" ) ),
98  pickingBaseIndex_ ( 0 ),
99  pickDrawMode_ ( DrawModes::NONE ), // TODO: hack, see enterPick()
100  vboGlId_ ( 0 ),
101  vboNumSplats_ ( 0 ),
102  vboData_ ( 0 ),
103  vboStride_ ( 0 ),
104  vboPositionsOffset_ ( -1 ),
105  vboColorsOffset_ ( -1 ),
106  vboNormalsOffset_ ( -1 ),
107  vboPointsizesOffset_( -1 ),
108  vboSelectionsOffset_( -1 ),
109  vboPickColorsOffset_( -1 ),
110  pointsizeScale_ ( 1.0f ),
111  backfaceCulling_ ( false ),
112  geometryShaderQuads_( false )
113 {
114  // create a new VBO (will be invalid and rebuilt the next time drawn (or picked))
115  createVBO();
116 }
117 
118 
119 //----------------------------------------------------------------
120 
121 
123 {
124  destroyVBO();
125 }
126 
127 
128 //----------------------------------------------------------------
129 
130 
132 {
133  ACG::Vec3f bbMin( FLT_MAX, FLT_MAX, FLT_MAX );
134  ACG::Vec3f bbMax(-FLT_MAX,-FLT_MAX,-FLT_MAX );
135 
136  if( splatCloud_.hasPositions() )
137  {
138  unsigned int i, num = splatCloud_.numSplats();
139  for( i=0; i<num; ++i )
140  {
141  const Position &p = splatCloud_.positions( i );
142 
143  ACG::Vec3f acgp( p[0], p[1], p[2] );
144 
145  bbMin.minimize( acgp );
146  bbMax.maximize( acgp );
147  }
148  }
149 
150  _bbMin.minimize( ACG::Vec3d( bbMin ) );
151  _bbMax.maximize( ACG::Vec3d( bbMax ) );
152 }
153 
154 
155 //----------------------------------------------------------------
156 
157 
158 void SplatCloudNode::draw( GLState &_state, const DrawModes::DrawMode &_drawMode )
159 {
160 
161  static const int RENDERMODE_DOTS = 1;
162  static const int RENDERMODE_SPLATS = 2;
163 
164  // check if drawmode is valid
165  int rendermode;
166  if( _drawMode.containsAtomicDrawMode( splatsDrawMode_ ) )
167  rendermode = RENDERMODE_SPLATS;
168  else if( _drawMode.containsAtomicDrawMode( dotsDrawMode_ ) )
169  rendermode = RENDERMODE_DOTS;
170  else if( _drawMode.containsAtomicDrawMode( pointsDrawMode_ ) ) {
171  static const int RENDERMODE_POINTS = 0;
172  rendermode = RENDERMODE_POINTS;
173  } else
174  return;
175 
176  // set desired depth function
178 
179  // if VBO is invalid or was (partially) modified, then rebuild
180  if( (vboData_ == 0) || vboModified() )
181  rebuildVBO( _state );
182 
183  // if VBO is valid...
184  if( vboData_ != 0 )
185  {
186  // activate VBO
187  ACG::GLState::bindBufferARB( GL_ARRAY_BUFFER_ARB, vboGlId_ );
188 
189  // enable arrays:
190  // --------------
191 
192  // positions
193  if( vboPositionsOffset_ != -1 )
194  {
195  ACG::GLState::enableClientState( GL_VERTEX_ARRAY );
196  ACG::GLState::vertexPointer( 3, GL_FLOAT, static_cast<GLsizei>(vboStride_), (unsigned char *) 0 + vboPositionsOffset_ );
197  }
198  else
199  {
200  ACG::GLState::disableClientState( GL_VERTEX_ARRAY );
201  }
202 
203  // colors
204  if( vboColorsOffset_ != -1 )
205  {
206  ACG::GLState::enableClientState( GL_SECONDARY_COLOR_ARRAY );
207  glSecondaryColorPointer( 3, GL_UNSIGNED_BYTE, static_cast<GLsizei>(vboStride_), (unsigned char *) 0 + vboColorsOffset_ ); // TODO: use ACG::GLState::secondaryColorPointer() when implemented
208  }
209  else
210  {
211  ACG::GLState::disableClientState( GL_SECONDARY_COLOR_ARRAY );
212  glSecondaryColor3ub( defaultColor_[0], defaultColor_[1], defaultColor_[2] );
213  }
214 
215  // normals
216  if( vboNormalsOffset_ != -1 )
217  {
218  ACG::GLState::enableClientState( GL_NORMAL_ARRAY );
219  ACG::GLState::normalPointer( GL_FLOAT, static_cast<GLsizei>(vboStride_), (unsigned char *) 0 + vboNormalsOffset_ );
220  }
221  else
222  {
223  ACG::GLState::disableClientState( GL_NORMAL_ARRAY );
224  glNormal3f( defaultNormal_[0], defaultNormal_[1], defaultNormal_[2] );
225  }
226 
227  // pointsizes
228  if( vboPointsizesOffset_ != -1 )
229  {
230  glClientActiveTexture( GL_TEXTURE0 ); // TODO: use ACG::GLState::clientActiveTexture() when implemented
231  ACG::GLState::enableClientState( GL_TEXTURE_COORD_ARRAY );
232  ACG::GLState::texcoordPointer( 1, GL_FLOAT, static_cast<GLsizei>(vboStride_), (unsigned char *) 0 + vboPointsizesOffset_ );
233  }
234  else
235  {
236  glClientActiveTexture( GL_TEXTURE0 ); // TODO: use ACG::GLState::clientActiveTexture() when implemented
237  ACG::GLState::disableClientState( GL_TEXTURE_COORD_ARRAY );
238  glMultiTexCoord1f( GL_TEXTURE0, defaultPointsize_ );
239  }
240 
241  // selections
242  if( vboSelectionsOffset_ != -1 )
243  {
244  glClientActiveTexture( GL_TEXTURE1 ); // TODO: use ACG::GLState::clientActiveTexture() when implemented
245  ACG::GLState::enableClientState( GL_TEXTURE_COORD_ARRAY );
246  ACG::GLState::texcoordPointer( 1, GL_FLOAT, static_cast<GLsizei>(vboStride_), (unsigned char *) 0 + vboSelectionsOffset_ );
247  }
248  else
249  {
250  glClientActiveTexture( GL_TEXTURE1 ); // TODO: use ACG::GLState::clientActiveTexture() when implemented
251  ACG::GLState::disableClientState( GL_TEXTURE_COORD_ARRAY );
252  glMultiTexCoord1f( GL_TEXTURE1, 0.0f );
253  }
254 
255  // pick colors
256  if( vboPickColorsOffset_ != -1 )
257  {
258  ACG::GLState::enableClientState( GL_COLOR_ARRAY );
259  ACG::GLState::colorPointer( 4, GL_UNSIGNED_BYTE, static_cast<GLsizei>(vboStride_), (unsigned char *) 0 + vboPickColorsOffset_ );
260  }
261  else
262  {
263  ACG::GLState::disableClientState( GL_COLOR_ARRAY );
264  glColor4ub( 255, 255, 255, 255 );
265  }
266 
267  // render:
268  // -------
269 
270  // enable "pointsize by program" depending on current rendermode
271  if( rendermode == RENDERMODE_SPLATS || rendermode == RENDERMODE_DOTS )
272  ACG::GLState::enable( GL_VERTEX_PROGRAM_POINT_SIZE );
273  else
274  ACG::GLState::disable( GL_VERTEX_PROGRAM_POINT_SIZE );
275 
276  // draw as GLpoints
277  glDrawArrays( GL_POINTS, 0, vboNumSplats_ );
278 
279  // disable arrays:
280  // ---------------
281 
282  // positions
283  ACG::GLState::disableClientState( GL_VERTEX_ARRAY );
284 
285  // colors
286  ACG::GLState::disableClientState( GL_SECONDARY_COLOR_ARRAY );
287 
288  // normals
289  ACG::GLState::disableClientState( GL_NORMAL_ARRAY );
290 
291  // pointsizes
292  glClientActiveTexture( GL_TEXTURE0 ); // TODO: use ACG::GLState::clientActiveTexture() when implemented
293  ACG::GLState::disableClientState( GL_TEXTURE_COORD_ARRAY );
294 
295  // selections
296  glClientActiveTexture( GL_TEXTURE1 ); // TODO: use ACG::GLState::clientActiveTexture() when implemented
297  ACG::GLState::disableClientState( GL_TEXTURE_COORD_ARRAY );
298 
299  // pick colors
300  ACG::GLState::disableClientState( GL_COLOR_ARRAY );
301 
302  // reset states:
303  // -------------
304 
305  // disable "pointsize by program"
306  ACG::GLState::disable( GL_VERTEX_PROGRAM_POINT_SIZE );
307 
308  // make defaults current again
309  glClientActiveTexture( GL_TEXTURE0 ); // TODO: use ACG::GLState::clientActiveTexture() when implemented
310  glColor4f ( 1.0f, 1.0f, 1.0f, 1.0f );
311  glSecondaryColor3f( 1.0f, 1.0f, 1.0f );
312 
313  // deactivate VBO
314  ACG::GLState::bindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
315  }
316 }
317 
318 //----------------------------------------------------------------
319 
320 void SplatCloudNode::getRenderObjects( IRenderer* _renderer, GLState& _state, const DrawModes::DrawMode& _drawMode, const Material* _mat )
321 {
322  static const int RENDERMODE_POINTS = 0;
323  static const int RENDERMODE_DOTS = 1;
324  static const int RENDERMODE_SPLATS = 2;
325 
326  // check if drawmode is valid
327  int rendermode;
328  if (_drawMode.containsAtomicDrawMode(splatsDrawMode_))
329  rendermode = RENDERMODE_SPLATS;
330  else if (_drawMode.containsAtomicDrawMode(dotsDrawMode_))
331  rendermode = RENDERMODE_DOTS;
332  else if (_drawMode.containsAtomicDrawMode(pointsDrawMode_)) {
333  rendermode = RENDERMODE_POINTS;
334  }
335  else
336  return;
337 
338  ACG::RenderObject obj;
339 
340  obj.initFromState(&_state);
341  obj.setMaterial(_mat);
342 
343  obj.depthTest = true;
344 
345  // backface culling is done manually in shader
346  obj.culling = false;
347 
348  // if VBO is invalid or was (partially) modified, then rebuild
349  if ((vboData_ == 0) || vboModified())
350  rebuildVBO(_state);
351 
352  // if VBO is valid...
353  if (vboData_ != 0)
354  {
355  // activate VBO
356  obj.vertexBuffer = vboGlId_;
357 
358 
359  // enable arrays:
360  // --------------
361  vboDecl_.clear();
362 
363  // positions
364  if (vboPositionsOffset_ != -1)
365  vboDecl_.addElement(GL_FLOAT, 3, ACG::VERTEX_USAGE_POSITION, size_t(vboPositionsOffset_));
366 
367  // colors
368  if (vboColorsOffset_ != -1)
369  vboDecl_.addElement(GL_UNSIGNED_BYTE, 3, ACG::VERTEX_USAGE_COLOR, size_t(vboColorsOffset_));
370  else
371  {
372  obj.emissive = ACG::Vec3f(defaultColor_[0], defaultColor_[1], defaultColor_[2]);
373  obj.emissive /= 255.0f;
374  }
375 
376  // normals
377  if (vboNormalsOffset_ != -1)
378  vboDecl_.addElement(GL_FLOAT, 3, ACG::VERTEX_USAGE_NORMAL, size_t(vboNormalsOffset_));
379  else
380  {
381  // todo
382 // defaultNormal_;
383  }
384 
385  // pointsizes
386  if (vboPointsizesOffset_ != -1)
387  vboDecl_.addElement(GL_FLOAT, 1, ACG::VERTEX_USAGE_TEXCOORD, size_t(vboPointsizesOffset_));
388  else
389  {
390  // todo
391 // glMultiTexCoord1f(GL_TEXTURE0, defaultPointsize_);
392  }
393 
394  // selections
395  if (vboSelectionsOffset_ != -1)
396  vboDecl_.addElement(GL_FLOAT, 1, ACG::VERTEX_USAGE_SHADER_INPUT, size_t(vboSelectionsOffset_), "inSplatSelection");
397  else
398  {
399  // todo
400 // glMultiTexCoord1f(GL_TEXTURE1, 0.0f);
401  }
402 
403  // pick colors
404  if (vboPickColorsOffset_ != -1)
405  vboDecl_.addElement(GL_UNSIGNED_BYTE, 4, ACG::VERTEX_USAGE_SHADER_INPUT, size_t(vboPickColorsOffset_), "inSplatPickColor");
406  else
407  {
408  // todo
409 // glColor4ub(255, 255, 255, 255);
410  }
411 
412  vboDecl_.setVertexStride(vboStride_);
413 
414  obj.vertexDecl = &vboDecl_;
415 
416  // render:
417  // -------
418 
419  // setup shader
420  obj.shaderDesc.shadeMode = SG_SHADE_UNLIT;
421 
422 
423 
424  obj.programPointSize = false;
425 
426  // test gl_PointSize performance
427  if (rendermode == RENDERMODE_DOTS)
428  {
429 
430  }
431 
432 
433  switch (rendermode)
434  {
435  case RENDERMODE_SPLATS:
436  {
437  if (geometryShaderQuads_)
438  {
439  obj.shaderDesc.vertexTemplateFile = "SplatCloud_ShaderGen/splats_quad_vs.glsl";
440  obj.shaderDesc.geometryTemplateFile = "SplatCloud_ShaderGen/splats_quad_gs.glsl";
441  obj.shaderDesc.fragmentTemplateFile = "SplatCloud_ShaderGen/splats_quad_fs.glsl";
442  obj.programPointSize = false;
443  }
444  else
445  {
446  obj.shaderDesc.vertexTemplateFile = "SplatCloud_ShaderGen/splats_psize_vs.glsl";
447  obj.shaderDesc.fragmentTemplateFile = "SplatCloud_ShaderGen/splats_psize_fs.glsl";
448  obj.programPointSize = true;
449  }
450  } break;
451 
452  case RENDERMODE_DOTS:
453  {
454  if (geometryShaderQuads_)
455  {
456  obj.shaderDesc.vertexTemplateFile = "SplatCloud_ShaderGen/dots_quad_vs.glsl";
457  obj.shaderDesc.geometryTemplateFile = "SplatCloud_ShaderGen/splats_quad_gs.glsl";
458  obj.shaderDesc.fragmentTemplateFile = "SplatCloud_ShaderGen/splats_quad_fs.glsl";
459  obj.programPointSize = false;
460  }
461  else
462  {
463  obj.shaderDesc.vertexTemplateFile = "SplatCloud_ShaderGen/dots_psize_vs.glsl";
464  obj.programPointSize = true;
465  }
466  } break;
467 
468  case RENDERMODE_POINTS:
469  {
470  obj.shaderDesc.vertexTemplateFile = "SplatCloud_ShaderGen/points_vs.glsl";
471  obj.programPointSize = false;
472  } break;
473 
474  default: break;
475  }
476 
477  // setup uniforms
478  /*
479  uniform float pointsizeScale = 1.0;
480  uniform bool backfaceCulling = false;
481  uniform float modelviewScale;
482  uniform float viewportScaleFov_y;
483 
484  uniform mat4 g_mPInv;
485 
486  uniform vec4 invViewportScale;
487  uniform vec4 invViewportTransp;
488  uniform float viewportScale_z;
489  uniform float viewportTransp_z;
490  */
491 
492  // get viewport
493  int left, bottom, width, height;
494  _state.get_viewport(left, bottom, width, height);
495 
496  float x = (float)left;
497  float y = (float)bottom;
498  float w = (float)width;
499  float h = (float)height;
500 
501  // get depthrange
502  // TODO: use glstate.get_depth_range when implemented
503  GLfloat depthRange[2];
504  glGetFloatv(GL_DEPTH_RANGE, depthRange);
505  float z = (float)depthRange[0];
506  float d = (float)depthRange[1] - z;
507 
508  // check if we are safe
509  if (w <= 0.0f || h <= 0.0f || d <= 0.0f)
510  return;
511 
512  // calculate window-coordinates to normalized-device-coordinates scale
513  ACG::Vec4f invVPs;
514  invVPs[0] = 2.0f / w;
515  invVPs[1] = 2.0f / h;
516  invVPs[2] = 2.0f / d;
517  invVPs[3] = 0.0f;
518 
519  // calculate window-coordinates to normalized-device-coordinates transpose
520  ACG::Vec4f invVPt;
521  invVPt[0] = -(x * invVPs[0] + 1.0f);
522  invVPt[1] = -(y * invVPs[1] + 1.0f);
523  invVPt[2] = -(z * invVPs[2] + 1.0f);
524  invVPt[3] = 1.0f;
525 
526  // calculate normalized-device-coordinates to window-coordinates scale and transpose
527  GLfloat VPs_z = 0.5f * d;
528  GLfloat VPt_z = z + VPs_z;
529 
530  // calculate scaling factor of modelview matrix
531  static const double RCP_3 = 1.0 / 3.0;
532  const ACG::GLMatrixd &mv = _state.modelview();
533  double detMV = mv(0, 0) * (mv(1, 1)*mv(2, 2) - mv(1, 2)*mv(2, 1))
534  + mv(0, 1) * (mv(1, 2)*mv(2, 0) - mv(1, 0)*mv(2, 2))
535  + mv(0, 2) * (mv(1, 0)*mv(2, 1) - mv(1, 1)*mv(2, 0));
536  GLfloat MVs = (GLfloat)pow(fabs(detMV), RCP_3);
537 
538  // calculate scale for pointsizes in eye-coordinates according to fovy and transformation to window-coordinates
539  GLfloat VPsFov_y = _state.projection()(1, 1) * (0.5f * h);
540 
541  ACG::GLMatrixf projInv = _state.inverse_projection();
542 
543  obj.setUniform("invViewportScale", invVPs);
544  obj.setUniform("invViewportTransp", invVPt);
545  obj.setUniform("viewportScale_z", VPs_z);
546  obj.setUniform("viewportTransp_z", VPt_z);
547  obj.setUniform("modelviewScale", MVs);
548  obj.setUniform("viewportScaleFov_y", VPsFov_y);
549  obj.setUniform("invProjection", projInv);
550  obj.setUniform("pointsizeScale", pointsizeScale_);
551  obj.setUniform("backfaceCulling", backfaceCulling_);
552  obj.setUniform("defaultPointsize", defaultPointsize_);
553  obj.setUniform("defaultNormal", defaultNormal_);
554 
555  if (vboColorsOffset_ != -1)
556  obj.shaderDesc.vertexColors = true;
557 
558  // draw as GLpoints
559  obj.glDrawArrays(GL_POINTS, 0, vboNumSplats_);
560 
561  _renderer->addRenderObject(&obj);
562  }
563 }
564 
565 //----------------------------------------------------------------
566 
567 
568 void SplatCloudNode::pick( GLState &_state, PickTarget _target )
569 {
570  // if pick target is valid...
571  if( _target == PICK_ANYTHING || _target == PICK_VERTEX )
572  {
573  // set number of pick colors used (each splats gets a unique pick color)
574  if( !_state.pick_set_maximum( splatCloud_.numSplats() ) ) // number of splats could have changed, so use new number of splats (*not* the one in VBO memory!)
575  {
576  std::cerr << "SplatCloudNode::pick() : Color range too small, picking failed." << std::endl;
577  return;
578  }
579 
580  // if in color picking mode...
581  if( _state.color_picking() )
582  {
583  // if picking base index has changed, rebuild pick colors block in VBO so new pick colors will be used
584  if( pickingBaseIndex_ != _state.pick_current_index() )
585  {
586  pickColorsModified_ = true;
587  }
588 
589  // TODO: hack, see enterPick()
590  draw( _state, pickDrawMode_ );
591  }
592  }
593 }
594 
595 
596 //----------------------------------------------------------------
597 
598 
599 void SplatCloudNode::createVBO()
600 {
601  // create new VBO (if *not* already existing)
602  if( vboGlId_ == 0 )
603  {
604  glGenBuffers( 1, &vboGlId_ );
605  vboNumSplats_ = 0;
606  vboData_ = 0;
607 
608  modifiedAll(); // (re-)build all data block in VBO memory the first time
609  }
610 }
611 
612 
613 //----------------------------------------------------------------
614 
615 
616 void SplatCloudNode::destroyVBO()
617 {
618  // delete VBO (if existing)
619  if( vboGlId_ != 0 )
620  {
621  glDeleteBuffers( 1, &vboGlId_ );
622  vboGlId_ = 0;
623  vboNumSplats_ = 0;
624  vboData_ = 0;
625  }
626 }
627 
628 
629 //----------------------------------------------------------------
630 
631 
632 void SplatCloudNode::rebuildVBO( GLState &_state )
633 {
634  // if something went wrong in the initialization, make VBO invalid and abort
635  if( vboGlId_ == 0 )
636  {
637  vboData_ = 0;
638  return;
639  }
640 
641  // activate VBO
642  ACG::GLState::bindBufferARB( GL_ARRAY_BUFFER_ARB, vboGlId_ );
643 
644  // calculate size of data and offsets
645  unsigned int numSplats = splatCloud_.numSplats();
646  unsigned int stride = 0;
647 
648  int positionsOffset = -1;
649  int colorsOffset = -1;
650  int normalsOffset = -1;
651  int pointsizesOffset = -1;
652  int selectionsOffset = -1;
653  int pickColorsOffset = -1;
654 
655  if( splatCloud_.hasPositions() ) { positionsOffset = stride; stride += 12; }
656  if( splatCloud_.hasColors() ) { colorsOffset = stride; stride += 3; }
657  if( splatCloud_.hasNormals() ) { normalsOffset = stride; stride += 12; }
658  if( splatCloud_.hasPointsizes() ) { pointsizesOffset = stride; stride += 4; }
659  if( splatCloud_.hasSelections() ) { selectionsOffset = stride; stride += 4; }
660  /* has pick colors is true */ { pickColorsOffset = stride; stride += 4; }
661 
662  // tell GL that we are seldomly updating the VBO but are often drawing it
663  glBufferData( GL_ARRAY_BUFFER_ARB, static_cast<GLsizei>(stride * numSplats), 0, GL_STATIC_DRAW_ARB );
664 
665  // get pointer to VBO memory
666  unsigned char *data = (unsigned char *) glMapBuffer( GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB );
667 
668  // check if something went wrong during VBO mapping
669  if( data == 0 )
670  {
671  std::cout << "SplatCloudNode::rebuildVBO() : glMapBuffer() failed." << std::endl;
672  vboData_ = 0;
673  }
674  else
675  {
676  // if VBO memory block was moved or the internal block structure has to be changed, rebuild entire VBO
677  if( (vboData_ != data) || vboStructureModified() )
678  {
679  vboNumSplats_ = numSplats;
680  vboData_ = data;
681  vboStride_ = stride;
682 
683  vboPositionsOffset_ = positionsOffset;
684  vboColorsOffset_ = colorsOffset;
685  vboNormalsOffset_ = normalsOffset;
686  vboPointsizesOffset_ = pointsizesOffset;
687  vboSelectionsOffset_ = selectionsOffset;
688  vboPickColorsOffset_ = pickColorsOffset;
689 
690  // mark all data blocks to rebuild them lateron
691  modifiedAll();
692  }
693 
694  // if in color picking mode...
695  if( _state.color_picking() )
696  {
697  // store picking base index
698  pickingBaseIndex_ = static_cast<unsigned int>(_state.pick_current_index());
699  }
700 
701  // rebuild data blocks if needed
702  if( positionsModified_ ) rebuildVBOPositions();
703  if( colorsModified_ ) rebuildVBOColors();
704  if( normalsModified_ ) rebuildVBONormals();
705  if( pointsizesModified_ ) rebuildVBOPointsizes();
706  if( selectionsModified_ ) rebuildVBOSelections();
707  if( pickColorsModified_ ) rebuildVBOPickColors( _state );
708 
709 # ifdef REPORT_VBO_UPDATES
710  std::cout << std::endl;
711 # endif
712 
713  // every block in VBO memory has been updated
714  positionsModified_ = false;
715  colorsModified_ = false;
716  normalsModified_ = false;
717  pointsizesModified_ = false;
718  selectionsModified_ = false;
719  pickColorsModified_ = false;
720 
721  // release pointer to VBO memory. if something went wrong, make VBO invalid and abort
722  if( !glUnmapBuffer( GL_ARRAY_BUFFER_ARB ) )
723  {
724  std::cout << "SplatCloudNode::rebuildVBO() : glUnmapBuffer() failed." << std::endl;
725  vboData_ = 0;
726  }
727  }
728 
729  // deactivate VBO
730  ACG::GLState::bindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
731 }
732 
733 
734 //----------------------------------------------------------------
735 
736 
737 static void addFloatToBuffer( float _value, unsigned char *&_buffer )
738 {
739  // get pointer
740  unsigned char *v = (unsigned char *) &_value;
741 
742  // copy over 4 bytes
743  *_buffer++ = *v++;
744  *_buffer++ = *v++;
745  *_buffer++ = *v++;
746  *_buffer++ = *v;
747 }
748 
749 
750 //----------------------------------------------------------------
751 
752 
753 static void addIntToBuffer( int _value, unsigned char *&_buffer )
754 {
755  // get pointer
756  unsigned char *v = (unsigned char *) &_value;
757 
758  // copy over 4 bytes
759  *_buffer++ = *v++;
760  *_buffer++ = *v++;
761  *_buffer++ = *v++;
762  *_buffer++ = *v;
763 }
764 
765 
766 //----------------------------------------------------------------
767 
768 
769 static void addUCharToBuffer( unsigned char _value, unsigned char *&_buffer )
770 {
771  // get pointer
772  unsigned char *v = (unsigned char *) &_value;
773 
774  // copy over 1 byte
775  *_buffer++ = *v;
776 }
777 
778 
779 //----------------------------------------------------------------
780 
781 
782 void SplatCloudNode::rebuildVBOPositions()
783 {
784  if( (vboPositionsOffset_ == -1) || !splatCloud_.hasPositions() )
785  return;
786 
787 # ifdef REPORT_VBO_UPDATES
788  std::cout << "SplatCloudNode::rebuildVBOPositions()" << std::endl;
789 # endif
790 
791  // get pointer to buffer
792  unsigned char *buffer = vboData_ + vboPositionsOffset_;
793 
794  // for all positions...
795  unsigned int i, num = splatCloud_.numSplats();
796  for( i=0; i<num; ++i )
797  {
798  // add position
799  const Position &p = getPosition( i );
800  buffer = vboData_ + vboPositionsOffset_ + i * vboStride_;
801  addFloatToBuffer( p[0], buffer );
802  addFloatToBuffer( p[1], buffer );
803  addFloatToBuffer( p[2], buffer );
804  }
805 }
806 
807 
808 //----------------------------------------------------------------
809 
810 
811 void SplatCloudNode::rebuildVBOColors()
812 {
813  if( (vboColorsOffset_ == -1) || !splatCloud_.hasColors() )
814  return;
815 
816 # ifdef REPORT_VBO_UPDATES
817  std::cout << "SplatCloudNode::rebuildVBOColors()" << std::endl;
818 # endif
819 
820  // get pointer to buffer
821  unsigned char *buffer = vboData_ + vboColorsOffset_;
822 
823  // for all colors...
824  unsigned int i, num = splatCloud_.numSplats();
825  for( i=0; i<num; ++i )
826  {
827  // add color
828  const Color &c = getColor( i );
829  buffer = vboData_ + vboColorsOffset_ + i * vboStride_;
830 
831  addUCharToBuffer( c[0], buffer );
832  addUCharToBuffer( c[1], buffer );
833  addUCharToBuffer( c[2], buffer );
834  }
835 }
836 
837 
838 //----------------------------------------------------------------
839 
840 
841 void SplatCloudNode::rebuildVBONormals()
842 {
843  if( (vboNormalsOffset_ == -1) || !splatCloud_.hasNormals() )
844  return;
845 
846 # ifdef REPORT_VBO_UPDATES
847  std::cout << "SplatCloudNode::rebuildVBONormals()" << std::endl;
848 # endif
849 
850  // get pointer to buffer
851  unsigned char *buffer = vboData_ + vboNormalsOffset_;
852 
853  // for all normals...
854  unsigned int i, num = splatCloud_.numSplats();
855  for( i=0; i<num; ++i )
856  {
857  // add normal
858  const Normal &n = getNormal( i );
859  buffer = vboData_ + vboNormalsOffset_ + i * vboStride_;
860 
861  addFloatToBuffer( n[0], buffer );
862  addFloatToBuffer( n[1], buffer );
863  addFloatToBuffer( n[2], buffer );
864  }
865 }
866 
867 
868 //----------------------------------------------------------------
869 
870 
871 void SplatCloudNode::rebuildVBOPointsizes()
872 {
873  if( (vboPointsizesOffset_ == -1) || !splatCloud_.hasPointsizes() )
874  return;
875 
876 # ifdef REPORT_VBO_UPDATES
877  std::cout << "SplatCloudNode::rebuildVBOPointsizes()" << std::endl;
878 # endif
879 
880  // get pointer to buffer
881  unsigned char *buffer = vboData_ + vboPointsizesOffset_;
882 
883  // for all pointsizes...
884  unsigned int i, num = splatCloud_.numSplats();
885  for( i=0; i<num; ++i )
886  {
887  // add pointsize
888  const Pointsize &ps = getPointsize( i );
889  buffer = vboData_ + vboPointsizesOffset_ + i * vboStride_;
890 
891  addFloatToBuffer(ps, buffer);
892  }
893 }
894 
895 
896 //----------------------------------------------------------------
897 
898 
899 void SplatCloudNode::rebuildVBOSelections()
900 {
901  if( (vboSelectionsOffset_ == -1) || !splatCloud_.hasSelections() )
902  return;
903 
904 # ifdef REPORT_VBO_UPDATES
905  std::cout << "SplatCloudNode::rebuildVBOSelections()" << std::endl;
906 # endif
907 
908  // get pointer to buffer
909  unsigned char *buffer = vboData_ + vboSelectionsOffset_;
910 
911  // for all selections...
912  unsigned int i, num = splatCloud_.numSplats();
913  for( i=0; i<num; ++i )
914  {
915  const bool &s = getSelection( i );
916  buffer = vboData_ + vboSelectionsOffset_ + i * vboStride_;
917 
918  addFloatToBuffer((s ? 1.0f : 0.0f), buffer);
919  }
920 }
921 
922 
923 //----------------------------------------------------------------
924 
925 
926 void SplatCloudNode::rebuildVBOPickColors( GLState &_state )
927 {
928  if( (vboPickColorsOffset_ == -1) || !splatCloud_.hasPositions() )
929  return;
930 
931 # ifdef REPORT_VBO_UPDATES
932  std::cout << "SplatCloudNode::rebuildVBOPickColors()" << std::endl;
933 # endif
934 
935  // get pointer to buffer
936  unsigned char *buffer = vboData_ + vboPickColorsOffset_;
937 
938  // for all pick colors...
939  unsigned int i, num = splatCloud_.numSplats();
940  for( i=0; i<num; ++i )
941  {
942  // add pick color
943  const Vec4uc &pc = _state.pick_get_name_color( i );
944  buffer = vboData_ + vboPickColorsOffset_ + i * vboStride_;
945 
946  addUCharToBuffer( pc[0], buffer );
947  addUCharToBuffer( pc[1], buffer );
948  addUCharToBuffer( pc[2], buffer );
949  addUCharToBuffer( pc[3], buffer );
950  }
951 }
952 
953 
954 //================================================================
955 
956 
957 } // namespace SceneGraph
958 } // namespace ACG
bool vboModified() const
return true iff any of the data values in the VBO has to be changed
vector_type & maximize(const vector_type &_rhs)
maximize values: same as *this = max(*this, _rhs), but faster
Definition: Vector11T.hh:563
Namespace providing different geometric functions concerning angles.
bool hasNormals() const
Return the availability of the predefined property.
Definition: SplatCloud.hh:609
bool color_picking() const
Is color picking active?
Definition: GLState.cc:1141
static void normalPointer(GLenum _type, GLsizei _stride, const GLvoid *_pointer)
replaces glNormalPointer, supports locking
Vec4uc pick_get_name_color(size_t _idx)
Definition: GLState.cc:1068
pick any of the prior targets (should be implemented for all nodes)
Definition: PickTarget.hh:84
static void colorPointer(GLint _size, GLenum _type, GLsizei _stride, const GLvoid *_pointer)
replaces glColorPointer, supports locking
bool vboStructureModified() const
returns true iff the internal block structure of the VBO has to be changed
void draw(GLState &_state, const DrawModes::DrawMode &_drawMode)
draw the SplatCloud
VectorT< float, 3 > Vec3f
Definition: VectorT.hh:119
const GLenum & depthFunc() const
get glDepthFunc() that is supposed to be active
Definition: GLState.cc:941
static void enable(GLenum _cap, bool _warnRemoved=true)
replaces glEnable, but supports locking
void pick(GLState &_state, PickTarget _target)
picking
void boundingBox(ACG::Vec3d &_bbMin, ACG::Vec3d &_bbMax)
update bounding box
defined by user via VertexElement::shaderInputName_
const GLMatrixd & projection() const
get projection matrix
Definition: GLState.hh:786
bool hasColors() const
Return the availability of the predefined property.
Definition: SplatCloud.hh:608
void initFromState(GLState *_glState)
Initializes a RenderObject instance.
Definition: RenderObject.cc:61
static void bindBufferARB(GLenum _target, GLuint _buffer)
same function as bindBuffer
int vboPositionsOffset_
offsets relative to vboData_ or -1 if not present in VBO
size_t pick_current_index() const
Returns the current color picking index (can be used for caching)
Definition: GLState.cc:1131
static void disable(GLenum _cap, bool _warnRemoved=true)
replaces glDisable, but supports locking
bool hasPositions() const
Return the availability of the predefined property.
Definition: SplatCloud.hh:607
Interface class between scenegraph and renderer.
Definition: RenderObject.hh:98
Position & positions(int _idx)
Get a reference of the predefined property&#39;s value.
Definition: SplatCloud.hh:631
bool positionsModified_
marks if parts of the data has been modified
static void vertexPointer(GLint _size, GLenum _type, GLsizei _stride, const GLvoid *_pointer)
replaces glVertexPointer, supports locking
static void disableClientState(GLenum _cap)
replaces glDisableClientState, supports locking
void setVertexStride(unsigned int _stride)
void addElement(const VertexElement *_pElement)
Color defaultColor_
the default values will be used when the specific array is not present
unsigned int numSplats() const
Get the number of splats.
Definition: SplatCloud.hh:179
SplatCloudNode(const SplatCloud &_splatCloud, BaseNode *_parent=0, std::string _name="<SplatCloudNode>")
constructor
GLuint vertexBuffer
VBO, IBO ids, ignored if VAO is provided.
void get_viewport(int &_left, int &_bottom, int &_width, int &_height) const
get viewport
Definition: GLState.hh:816
void setUniform(const char *_name, GLint _value)
set values for int uniforms
static void enableClientState(GLenum _cap)
replaces glEnableClientState, supports locking
virtual void addRenderObject(RenderObject *_renderObject)
Callback for the scenegraph nodes, which send new render objects via this function.
Definition: IRenderer.cc:104
void getRenderObjects(IRenderer *_renderer, GLState &_state, const DrawModes::DrawMode &_drawMode, const Material *_mat)
create render objects
const GLMatrixd & modelview() const
get modelview matrix
Definition: GLState.hh:791
bool hasSelections() const
Return the availability of the predefined property.
Definition: SplatCloud.hh:613
ShaderGenDesc shaderDesc
Drawmode and other shader params.
PickTarget
What target to use for picking.
Definition: PickTarget.hh:73
vector_type & minimize(const vector_type &_rhs)
minimize values: same as *this = min(*this, _rhs), but faster
Definition: Vector11T.hh:535
const GLenum & depthFunc() const
get glDepthFunc() that is supposed to be active
static void texcoordPointer(GLint _size, GLenum _type, GLsizei _stride, const GLvoid *_pointer)
replaces glTexcoordPointer, supports locking
const SplatCloud & splatCloud_
reference to class containing all the data
bool hasPointsizes() const
Return the availability of the predefined property.
Definition: SplatCloud.hh:610
const GLMatrixd & inverse_projection() const
get inverse projection matrix
Definition: GLState.hh:806
bool containsAtomicDrawMode(const DrawMode &_atomicDrawMode) const
Check whether an Atomic DrawMode is active in this draw Mode.
Definition: DrawModes.cc:520
const VertexDeclaration * vertexDecl
Defines the vertex buffer layout, ignored if VAO is provided.
const Position & getPosition(int _idx) const
if the data array exists, the entry with the given index is returned, otherwise the default value is ...
picks verices (may not be implemented for all nodes)
Definition: PickTarget.hh:82
bool pick_set_maximum(size_t _idx)
Set the maximal number of primitives/components of your object.
Definition: GLState.cc:1051