Developer Documentation
PolyLineNodeT_impl.hh
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 
47 //=============================================================================
48 //
49 // CLASS PolyLineNodeT - IMPLEMENTATION
50 //
51 //=============================================================================
52 
53 #define ACG_POLYLINENODET_C
54 
55 //== INCLUDES =================================================================
56 
57 #include "PolyLineNodeT.hh"
58 #include <ACG/GL/gl.hh>
59 #include <ACG/GL/ShaderCache.hh>
60 #include <ACG/Utils/VSToolsT.hh>
61 #include <vector>
62 
63 //== NAMESPACES ===============================================================
64 
65 namespace ACG {
66 namespace SceneGraph {
67 
68 //== IMPLEMENTATION ==========================================================
69 
71 template <class PolyLine>
72 PolyLineNodeT<PolyLine>::PolyLineNodeT(PolyLine& _pl, BaseNode* _parent, std::string _name) :
73  BaseNode(_parent, _name),
74  polyline_(_pl),
75  updateVBO_(true),
76  sphere_(0)
77 
78 {
79 
80  // Initialize our local draw mode references
81  POINTS_SPHERES = DrawModes::DrawMode(ACG::SceneGraph::DrawModes::addDrawMode("Points (as Spheres)",
82  ACG::SceneGraph::DrawModes::DrawModeProperties(ACG::SceneGraph::DrawModes::PRIMITIVE_POLYGON,
85 
86  POINTS_SPHERES_SCREEN = DrawModes::DrawMode(ACG::SceneGraph::DrawModes::addDrawMode("Points (as Spheres, constant screen size)",
87  ACG::SceneGraph::DrawModes::DrawModeProperties(ACG::SceneGraph::DrawModes::PRIMITIVE_POLYGON,
90 
91  // Initial default draw mode
92  drawMode(DrawModes::WIREFRAME | DrawModes::POINTS );
93 }
94 
95 //----------------------------------------------------------------------------
96 
97 template <class PolyLine>
99 {
100  delete sphere_;
101 }
102 
103 //----------------------------------------------------------------------------
104 
105 template <class PolyLine>
106 void
108 boundingBox(Vec3d& _bbMin, Vec3d& _bbMax)
109 {
110  for (unsigned int i=0; i< polyline_.n_vertices(); ++i)
111  {
112  _bbMin.minimize(polyline_.point(i));
113  _bbMax.maximize(polyline_.point(i));
114  }
115 }
116 
117 
118 //----------------------------------------------------------------------------
119 
120 
121 template <class PolyLine>
125 {
126  return (DrawModes::WIREFRAME | DrawModes::POINTS | DrawModes::POINTS_COLORED | POINTS_SPHERES | POINTS_SPHERES_SCREEN | DrawModes::EDGES_COLORED);
127 }
128 
129 
130 //----------------------------------------------------------------------------
131 
132 
133 template <class PolyLine>
134 void
136 draw(GLState& _state, const DrawModes::DrawMode& _drawMode)
137 {
138  // Block if we do not have any vertices
139  if ( polyline_.n_vertices() == 0 )
140  return;
141 
142  // Update the vbo only if required.
143  if ( updateVBO_ )
144  updateVBO();
145 
146  ACG::GLState::disable(GL_LIGHTING);
147  ACG::GLState::disable(GL_TEXTURE_2D);
148 
149  // Bind the vertex array
150  vbo_.bind();
151 
152  ACG::Vec4f color = _state.ambient_color() + _state.diffuse_color();
153 
154  // draw points
155  if (_drawMode & DrawModes::POINTS || _drawMode & DrawModes::POINTS_COLORED)
156  {
157  vertexDecl_.activateFixedFunction();
158 
159  // draw selection
160  if( polyline_.vertex_selections_available() && !selectedVertexIndexBuffer_.empty())
161  {
162  // save old values
163  float point_size_old = _state.point_size();
164  _state.set_color( Vec4f(1,0,0,1) );
165  _state.set_point_size(point_size_old+4);
166 
167  glDrawElements(GL_POINTS, selectedVertexIndexBuffer_.size(), GL_UNSIGNED_INT, &(selectedVertexIndexBuffer_[0]));
168 
169  _state.set_point_size(point_size_old);
170  }
171 
172  _state.set_color( color );
173 
174 
175  if (_drawMode & DrawModes::POINTS_COLORED)
176  {
177  vertexDecl_.deactivateFixedFunction();
178  vertexDeclVCol_.activateFixedFunction();
179  }
180 
181  // Draw all vertices (don't care about selection)
182  glDrawArrays(GL_POINTS, 0, polyline_.n_vertices());
183 
184  if (_drawMode & DrawModes::POINTS_COLORED)
185  vertexDeclVCol_.deactivateFixedFunction();
186  else
187  vertexDecl_.deactivateFixedFunction();
188  }
189 
190  // draw line segments
191  if (_drawMode & DrawModes::WIREFRAME) {
192  vertexDecl_.activateFixedFunction();
193 
194  // draw selection
195  if (polyline_.edge_selections_available() && !selectedEdgeIndexBuffer_.empty()) {
196  // save old values
197  float line_width_old = _state.line_width();
198  _state.set_color(Vec4f(1, 0, 0, 1));
199  _state.set_line_width(2 * line_width_old);
200 
201  glDrawElements(GL_LINES, selectedEdgeIndexBuffer_.size(), GL_UNSIGNED_INT, &(selectedEdgeIndexBuffer_[0]));
202 
203  _state.set_line_width(line_width_old);
204  }
205 
206  _state.set_color( color );
207 
208  if ( polyline_.is_closed() )
209  glDrawArrays(GL_LINE_STRIP, 0, polyline_.n_vertices() + 1);
210  else
211  glDrawArrays(GL_LINE_STRIP, 0, polyline_.n_vertices());
212 
213  vertexDecl_.deactivateFixedFunction();
214  }
215 
216 
217  if (_drawMode & DrawModes::EDGES_COLORED) {
218  vertexDecl_.activateFixedFunction();
219 
220  // draw selection
221  if (polyline_.edge_selections_available() && !selectedEdgeIndexBuffer_.empty()) {
222  // save old values
223  float line_width_old = _state.line_width();
224  _state.set_color(Vec4f(1, 0, 0, 1));
225  _state.set_line_width(2 * line_width_old);
226 
227  glDrawElements(GL_LINES, selectedEdgeIndexBuffer_.size(), GL_UNSIGNED_INT, &(selectedEdgeIndexBuffer_[0]));
228 
229  _state.set_line_width(line_width_old);
230  }
231 
232  vertexDecl_.deactivateFixedFunction();
233 
234  _state.set_color(color);
235 
236 
237  vertexDeclECol_.activateFixedFunction();
238  if (polyline_.is_closed())
239  glDrawArrays(GL_LINE_STRIP, 0, polyline_.n_vertices() + 1);
240  else
241  glDrawArrays(GL_LINE_STRIP, 0, polyline_.n_vertices());
242 
243  vertexDeclECol_.deactivateFixedFunction();
244  }
245 
246 
247  // draw normals
248  if (polyline_.vertex_normals_available()) {
249  double avg_len = polyline_.n_edges() > 0 ? (polyline_.length() / polyline_.n_edges() * 0.75) : 0;
250  std::vector<Point> ps;
251  for (unsigned int i = 0; i < polyline_.n_vertices(); ++i) {
252  ps.push_back(polyline_.point(i));
253  ps.push_back(polyline_.point(i) + polyline_.vertex_normal(i) * avg_len);
254  if (polyline_.vertex_binormals_available())
255  ps.push_back(polyline_.point(i) + polyline_.vertex_binormal(i) * avg_len);
256  }
257 
258  // Disable the big buffer and switch to in memory buffer
259  vbo_.unbind();
261 
262  float line_width_old = _state.line_width();
263  _state.set_color( Vec4f(0.8f, 0.f, 0.f, 1.f) );
264  _state.set_line_width(1);
265 
266  int stride = polyline_.vertex_binormals_available() ? 3 : 2;
267  glBegin(GL_LINES);
268  for (unsigned int i = 0; i < polyline_.n_vertices(); ++i) {
269  glArrayElement(stride * i);
270  glArrayElement(stride * i + 1);
271  }
272  glEnd();
273 
274  if (polyline_.vertex_binormals_available()) {
275  _state.set_color( Vec4f(0.f, 0.f, 0.8f, 1.f) );
276  glBegin(GL_LINES);
277  for (unsigned int i = 0; i < polyline_.n_vertices(); ++i) {
278  glArrayElement(stride * i);
279  glArrayElement(stride * i + 2);
280  }
281  glEnd();
282  }
283 
284  _state.set_line_width(line_width_old);
285  }
286 
287  vbo_.unbind();
288 
289  //Disable the vertex array
290  ACG::GLState::disableClientState(GL_VERTEX_ARRAY);
291 
292  // draw vertices as spheres, using the radius given in the polyline
293  if (_drawMode & POINTS_SPHERES)
294  {
295  // create sphere if not yet done
296  if(!sphere_)
297  sphere_ = new GLSphere(10,10);
298 
299  if( polyline_.vertex_selections_available())
300  {
301  for(unsigned int i=0; i<polyline_.n_vertices(); ++i)
302  {
303  if(polyline_.vertex_selected(i))
304  _state.set_color( Vec4f(1,0,0,1) );
305  else
306  _state.set_color( color );
307 
308  sphere_->draw(_state, _state.point_size(), (Vec3f)polyline_.point(i));
309  }
310  }
311  else
312  {
313  _state.set_color( color );
314  for(unsigned int i=0; i<polyline_.n_vertices(); ++i)
315  sphere_->draw(_state, _state.point_size(), (Vec3f)polyline_.point(i));
316  }
317  }
318  // draw vertices as spheres with constant size on screen
319  if (_drawMode & POINTS_SPHERES_SCREEN)
320  {
321  // create sphere if not yet done
322  if(!sphere_)
323  sphere_ = new GLSphere(10,10);
324 
325  // precompute desired radius of projected sphere
326  double r = 0.5*_state.point_size() / double(_state.viewport_height()) * 2.0 * tan(0.5*_state.fovy());
327 
328  if( polyline_.vertex_selections_available())
329  {
330  for(unsigned int i=0; i<polyline_.n_vertices(); ++i)
331  {
332  if(polyline_.vertex_selected(i))
333  _state.set_color( Vec4f(1,0,0,1) );
334  else
335  _state.set_color( color );
336 
337  // compute radius in 3D
338  const Vec3d p = (Vec3d)polyline_.point(i) - _state.eye();
339  const double l = (p|_state.viewing_direction());
340  sphere_->draw(_state, r*l, (Vec3f)polyline_.point(i));
341  }
342  }
343  else
344  {
345  _state.set_color( color );
346  for(unsigned int i=0; i<polyline_.n_vertices(); ++i)
347  {
348  // compute radius in 3D
349  const Vec3d p = (Vec3d)polyline_.point(i) - _state.eye();
350  const double l = (p|_state.viewing_direction());
351  sphere_->draw(_state, r*l, (Vec3f)polyline_.point(i));
352  }
353 
354  }
355  }
356 }
357 
358 //----------------------------------------------------------------------------
359 
360 
361 template <class PolyLine>
362 void
364 pick(GLState& _state, PickTarget _target)
365 {
366  if ( polyline_.n_vertices() == 0 )
367  return;
368 
369  // Bind the vertex array
370  ACG::GLState::bindBuffer(GL_ARRAY_BUFFER_ARB, 0);
371  ACG::GLState::vertexPointer( &(polyline_.points())[0] );
372  ACG::GLState::enableClientState(GL_VERTEX_ARRAY);
373 
374  unsigned int n_end = polyline_.n_edges()+1;
375  if( !polyline_.is_closed()) --n_end;
376 
377  // (draw lines slightly in front of everything else)
378  //disabled right now because of rendering artifacts.
379  //This probably doesn't make sense anyways since the lines are drawn as cylinders and therefore have a width
380  // glDepthRange(0.0,0.99)
381 
382  switch (_target)
383  {
384  case PICK_VERTEX:
385  {
386  _state.pick_set_maximum (polyline_.n_vertices());
387  if (drawMode() & DrawModes::POINTS)
388  pick_vertices( _state);
389 
390  if (drawMode() & POINTS_SPHERES)
391  pick_spheres( _state);
392 
393  if (drawMode() & POINTS_SPHERES_SCREEN)
394  pick_spheres_screen( _state);
395 
396  break;
397  }
398 
399  case PICK_EDGE:
400  {
401  _state.pick_set_maximum (n_end);
402  pick_edges(_state, 0);
403  break;
404  }
405 
406  case PICK_ANYTHING:
407  {
408  _state.pick_set_maximum (polyline_.n_vertices() + n_end);
409 
410  if (drawMode() & DrawModes::POINTS)
411  pick_vertices( _state);
412 
413  if (drawMode() & POINTS_SPHERES)
414  pick_spheres( _state);
415 
416  if (drawMode() & POINTS_SPHERES_SCREEN)
417  pick_spheres_screen( _state);
418 
419  pick_edges( _state, polyline_.n_vertices());
420  break;
421  }
422 
423  default:
424  break;
425  }
426 
427  //see above
428  // glDepthRange(0.0,1.0)
429 
430  //Disable the vertex array
431  ACG::GLState::disableClientState(GL_VERTEX_ARRAY);
432 
433 }
434 
435 
436 //----------------------------------------------------------------------------
437 
438 
439 template <class PolyLine>
440 void
442 pick_vertices( GLState& _state )
443 {
444  if (!polyline_.n_vertices())
445  return;
446 
447  float point_size_old = _state.point_size();
448  glPointSize(18);
449 
450  glDepthRange(0.0, 0.999999);
451 
452  static ShaderGenDesc desc;
453  desc.vertexTemplateFile = "Picking/pick_vertices_vs.glsl";
454  desc.fragmentTemplateFile = "Picking/pick_vertices_fs.glsl";
455  GLSL::Program* pickShader = ACG::ShaderCache::getInstance()->getProgram(&desc, nullptr);
456 
457  if (pickShader && pickShader->isLinked())
458  {
459  // Update the vbo only if required.
460  if (updateVBO_)
461  updateVBO();
462 
463  // Bind the vertex array
464  vbo_.bind();
465 
466  int pickOffsetIndex = int(_state.pick_current_index());
467 
468  vertexDecl_.activateShaderPipeline(pickShader);
469 
470  pickShader->use();
471 
472  ACG::GLMatrixf transform = _state.projection() * _state.modelview();
473 
474  pickShader->setUniform("mWVP", transform);
475  pickShader->setUniform("pickVertexOffset", pickOffsetIndex);
476 
477  glDrawArrays(GL_POINTS, 0, polyline_.n_vertices());
478 
479  vertexDecl_.deactivateShaderPipeline(pickShader);
480  pickShader->disable();
481 
482 
483  vbo_.unbind();
484  }
485  else
486  {
487  for (unsigned int i = 0; i < polyline_.n_vertices(); ++i) {
488  _state.pick_set_name(i);
489  glBegin(GL_POINTS);
490  glArrayElement(i);
491  glEnd();
492  }
493  }
494 
495  glDepthRange(0.0, 1.0);
496 
497 
498 
499  glPointSize(point_size_old);
500 }
501 
502 
503 //----------------------------------------------------------------------------
504 
505 
506 template <class PolyLine>
507 void
509 pick_spheres( GLState& _state )
510 {
511  if(!sphere_)
512  sphere_ = new GLSphere(10,10);
513 
514  _state.pick_set_name(0);
515 
516  for(unsigned int i=0; i<polyline_.n_vertices(); ++i)
517  {
518  _state.pick_set_name (i);
519  sphere_->draw(_state, _state.point_size(), (Vec3f)polyline_.point(i));
520  }
521 }
522 
523 //----------------------------------------------------------------------------
524 
525 
526 template <class PolyLine>
527 void
529 pick_spheres_screen( GLState& _state )
530 {
531  if(!sphere_)
532  sphere_ = new GLSphere(10,10);
533 
534  _state.pick_set_name(0);
535 
536  // precompute desired radius of projected sphere
537  double r = 0.5*_state.point_size()/double(_state.viewport_height())*2.0*tan(0.5*_state.fovy());
538 
539  for(unsigned int i=0; i<polyline_.n_vertices(); ++i)
540  {
541  _state.pick_set_name (i);
542  // compute radius in 3D
543  const Vec3d p = (Vec3d)polyline_.point(i) - _state.eye();
544  double l = (p|_state.viewing_direction());
545  sphere_->draw(_state, r*l, (Vec3f)polyline_.point(i));
546 
547 // ToFix: _state does still not provide the near_plane in picking mode!!!
548 // std::cerr << "radius in picking: " << r*l << std::endl;
549  }
550 }
551 
552 
553 //----------------------------------------------------------------------------
554 
555 
556 template <class PolyLine>
557 void
559 pick_edges( GLState& _state, unsigned int _offset)
560 {
561  // Check if we have any edges to draw ( % 0 causes division by zero on windows)
562  if ( polyline_.n_edges() == 0 )
563  return;
564 
565  glDepthRange(0.0, 0.999999);
566 
567  static ShaderGenDesc desc;
568  if(ACG::openGLVersionTest(3,2))
569  {
570  desc.vertexTemplateFile = "Picking/vertex.glsl";
571  desc.fragmentTemplateFile = "Picking/pick_vertices_fs2.glsl";
572  }
573  else
574  {
575  desc.vertexTemplateFile = "Picking/pick_vertices_vs.glsl";
576  desc.fragmentTemplateFile = "Picking/pick_vertices_fs.glsl";
577  }
578  GLSL::Program* pickShader = ACG::ShaderCache::getInstance()->getProgram(&desc, nullptr);
579 
580  if (pickShader && pickShader->isLinked())
581  {
582  // Update the vbo only if required.
583  if (updateVBO_)
584  updateVBO();
585 
586  // Bind the vertex array
587  vbo_.bind();
588 
589  int pickOffsetIndex = int(_state.pick_current_index());
590 
591  vertexDecl_.activateShaderPipeline(pickShader);
592 
593  pickShader->use();
594 
595  ACG::GLMatrixf transform = _state.projection() * _state.modelview();
596 
597  pickShader->setUniform("mWVP", transform);
598  pickShader->setUniform("pickVertexOffset", pickOffsetIndex);
599 
600  int numIndices = polyline_.n_vertices() + (polyline_.is_closed() ? 1 : 0);
601  glDrawArrays(GL_LINE_STRIP, 0, numIndices);
602 
603  vertexDecl_.deactivateShaderPipeline(pickShader);
604  pickShader->disable();
605 
606  vbo_.unbind();
607  }
608  else
609  {
610  // save old values
611  float line_width_old = _state.line_width();
612  // _state.set_line_width(2*line_width_old);
613  _state.set_line_width(14);
614 
615  unsigned int n_end = polyline_.n_edges() + 1;
616  if (!polyline_.is_closed()) --n_end;
617 
618  for (unsigned int i = 0; i < n_end; ++i) {
619  _state.pick_set_name(i + _offset);
620  glBegin(GL_LINES);
621  glArrayElement(i % polyline_.n_vertices());
622  glArrayElement((i + 1) % polyline_.n_vertices());
623  glEnd();
624  }
625 
626  _state.set_line_width(line_width_old);
627  }
628 
629  glDepthRange(0.0, 1.0);
630 
631 }
632 
633 //----------------------------------------------------------------------------
634 
635 template <class PolyLine>
636 void
638 setupVertexDeclaration(VertexDeclaration* _dst, int _colorSource) const {
639  // Update the vertex declaration based on the input data:
640  _dst->clear();
641 
642 
643  // We always output vertex positions
644  _dst->addElement(GL_FLOAT, 3, ACG::VERTEX_USAGE_POSITION);
645 
646  // current byte offset
647  size_t curOffset = 12;
648 
649  // Use the normals if available
650  if (polyline_.vertex_normals_available())
651  {
652  _dst->addElement(GL_FLOAT, 3, ACG::VERTEX_USAGE_NORMAL, curOffset);
653  curOffset += 12;
654  }
655 
656  // colors
657  if (polyline_.vertex_colors_available())
658  {
659  if (_colorSource == 1)
660  _dst->addElement(GL_UNSIGNED_BYTE, 4, ACG::VERTEX_USAGE_COLOR, curOffset);
661  curOffset += 4;
662  }
663 
664  if (polyline_.edge_colors_available())
665  {
666  if (_colorSource == 2)
667  _dst->addElement(GL_UNSIGNED_BYTE, 4, ACG::VERTEX_USAGE_COLOR, curOffset);
668  curOffset += 4;
669  }
670 
671 
672  // Add custom vertex elements to declaration
673  for (size_t i = 0; i < customBuffers_.size(); ++i) {
674  ACG::VertexElement tmp = customBuffers_[i].first;
675  tmp.pointer_ = 0;
677  tmp.setByteOffset(curOffset);
678  _dst->addElement(&tmp);
679 
680  curOffset += VertexDeclaration::getElementSize(&tmp);
681  }
682 
683  _dst->setVertexStride(curOffset);
684 }
685 
686 //----------------------------------------------------------------------------
687 
688 template <class PolyLine>
689 size_t
691 fillVertexBuffer(void *_buf, size_t _bufSize, bool _addLineStripEndVertex) {
692 
693  // register custom properties defined in polyline
694 
695  for (unsigned int i = 0; i < polyline_.get_num_custom_properties(); ++i) {
696 
697  typename PolyLine::CustomPropertyHandle proph = polyline_.enumerate_custom_property_handles(i);
698 
699 
700 
701  const void* propDataBuf = polyline_.get_custom_property_buffer(proph);
702 
703  typename std::map< typename PolyLine::CustomPropertyHandle, int >::iterator mapEntry = polylinePropMap_.find(proph);
704 
705  // insert newly defined properties
706  if (mapEntry == polylinePropMap_.end()) {
707 
708  // setup element description
709  ACG::VertexElement desc;
710 
711  unsigned int propSize = 0;
712  if (polyline_.get_custom_property_shader_binding(proph, &propSize, &desc.shaderInputName_, &desc.type_)) {
713  // assume aligned memory without byte padding
714  desc.numElements_ = propSize / VertexDeclaration::getGLTypeSize(desc.type_);
715  desc.pointer_ = 0;
716 
717  polylinePropMap_[proph] = addCustomBuffer(desc, propDataBuf);
718  }
719  }
720  else // otherwise update pointer of property data buffer
721  setCustomBuffer(mapEntry->second, propDataBuf);
722  }
723 
724 
725  // Update vertex declarations
726  setupVertexDeclaration(&vertexDecl_, 0);
727  setupVertexDeclaration(&vertexDeclVCol_, 1);
728  setupVertexDeclaration(&vertexDeclECol_, 2);
729 
730 
731  // fill buffer
732 
733  const unsigned int stride = vertexDecl_.getVertexStride();
734 
735  char* data = static_cast<char*>(_buf);
736  size_t bytesWritten = 0;
737 
738  for (unsigned int i = 0 ; i < polyline_.n_vertices() && bytesWritten + stride <= _bufSize; ++i) {
739  writeVertex(i, data + i * stride);
740  bytesWritten += stride;
741  }
742 
743  if (_addLineStripEndVertex && bytesWritten + stride <= _bufSize) {
744  // First point is added to the end for a closed loop
745  writeVertex(0, data + polyline_.n_vertices() * stride);
746  bytesWritten += stride;
747  }
748 
749  return bytesWritten;
750 }
751 
752 //----------------------------------------------------------------------------
753 
754 template <class PolyLine>
755 void
758 
759  setupVertexDeclaration(&vertexDecl_, 0);
760 
761  const unsigned int stride = vertexDecl_.getVertexStride();
762 
763  // size in bytes of vbo, create additional vertex for closed loop indexing
764  size_t bufferSize = stride * (polyline_.n_vertices() + 1);
765 
766  // Create the required array
767  std::vector<char> vboData(bufferSize);
768 
769  if (bufferSize > 0) {
770  size_t bytesWritten = fillVertexBuffer(&vboData[0], bufferSize, true);
771 
772  if (bytesWritten != bufferSize)
773  std::cerr << "PolyLineNode: fill vertex buffer only wrote " << bytesWritten << " bytes instead of expected " << bufferSize << " bytes" << std::endl;
774 
775  // Move data to the buffer in gpu memory
776  vbo_.upload(bufferSize, &vboData[0], GL_STATIC_DRAW);
777  vbo_.unbind();
778  }
779 
780  // Index buffer for selected vertices
781  selectedVertexIndexBuffer_.clear();
782 
783  // Index buffer for selected vertices
784  selectedEdgeIndexBuffer_.clear();
785 
786  for (unsigned int i = 0 ; i < polyline_.n_vertices(); ++i) {
787 
788  // Create an ibo in system memory for vertex selection
789  if ( polyline_.vertex_selections_available() && polyline_.vertex_selected(i) )
790  selectedVertexIndexBuffer_.push_back(i);
791 
792  // Create an ibo in system memory for edge selection
793  if ( polyline_.edge_selections_available() && polyline_.edge_selected(i) ) {
794  selectedEdgeIndexBuffer_.push_back(i);
795  selectedEdgeIndexBuffer_.push_back( (i + 1) % polyline_.n_vertices() );
796  }
797 
798  }
799 
800  // Update done.
801  updateVBO_ = false;
802 }
803 
804 //----------------------------------------------------------------------------
805 
806 template <class PolyLine>
807 void
809 writeVertexColor(unsigned int _vertex, bool _colorSourceVertex, void* _dst) const
810 {
811  const VertexDeclaration* declToUse = _colorSourceVertex ? &vertexDeclVCol_ : &vertexDeclECol_;
812 
813  unsigned int byteOffset = declToUse->findElementByUsage(VERTEX_USAGE_COLOR)->getByteOffset();
814  unsigned char* ucdata = ((unsigned char*)_dst) + byteOffset;
815 
816  Point col;
817  if (_colorSourceVertex)
818  col = polyline_.vertex_color(_vertex); // per vertex
819  else
820  {
821  // edge colors
822  // use the 2nd vertex of each edge as the provoking vertex
823  int edgeID = (_vertex + polyline_.n_edges() - 1) % polyline_.n_edges();
824  col = polyline_.edge_color(edgeID);
825  }
826 
827  // rgb
828  for (int i = 0; i < 3; ++i)
829  {
830  // convert to normalized ubyte
831  int ival = int(col[i] * 255.0);
832  ival = std::min(std::max(ival, 0), 255);
833  ucdata[i] = ival;
834  }
835  ucdata[3] = 0xff; // alpha
836 }
837 
838 //----------------------------------------------------------------------------
839 
840 template <class PolyLine>
841 void
843 writeVertex(unsigned int _vertex, void* _dst) {
844 
845  // position and normal in float
846  float* fdata = (float*)_dst;
847 
848  // Copy from internal storage to VBO in CPU memory
849  for ( unsigned int j = 0 ; j < 3 ; ++j)
850  *(fdata++) = polyline_.point(_vertex)[j];
851 
852  // Also write normal into buffer if available
853  if ( polyline_.vertex_normals_available() )
854  for ( unsigned int j = 0 ; j < 3 ; ++j)
855  *(fdata++) = polyline_.vertex_normal(_vertex)[j];
856 
857  if (polyline_.vertex_colors_available())
858  writeVertexColor(_vertex, true, _dst);
859 
860  if (polyline_.edge_colors_available())
861  writeVertexColor(_vertex, false, _dst);
862 
863  int customElementOffset = vertexDeclVCol_.findElementIdByUsage(VERTEX_USAGE_SHADER_INPUT);
864 
865  if (customElementOffset >= 0)
866  {
867  // copy custom data byte-wise
868  for (unsigned int i = 0; i < customBuffers_.size(); ++i) {
869 
870  // element in custom input buffer
871  const ACG::VertexElement* veInput = &customBuffers_[i].first;
872  unsigned int elementInputStride = veInput->getByteOffset();
873  unsigned int elementSize = ACG::VertexDeclaration::getElementSize(veInput);
874 
875  if (!elementInputStride)
876  elementInputStride = elementSize;
877 
878  // element in vertex buffer
879  const ACG::VertexElement* ve = vertexDeclVCol_.getElement(i + static_cast<unsigned int>(customElementOffset));
880 
881  const char* src = (const char*)customBuffers_[i].second;
882 
883  memcpy((char*)_dst + ve->getByteOffset(), src + elementInputStride * _vertex, elementSize);
884  }
885  }
886 }
887 
888 //----------------------------------------------------------------------------
889 
890 template <class PolyLine>
891 void
894 
895  // Block if we do not have any vertices
896  if ( polyline_.n_vertices() == 0 )
897  return;
898 
899  // init base render object
901 
902  _state.enable(GL_COLOR_MATERIAL);
903  _state.enable(GL_LIGHTING);
904  ro.initFromState(&_state);
905 
906  ro.setMaterial(_mat);
907 
908  // draw after scene-meshes
909  ro.priority = 1;
910 
911  // Update the vbo only if required.
912  if ( updateVBO_ )
913  updateVBO();
914 
915  // Set to the right vbo
916  ro.vertexBuffer = vbo_.id();
917 
918  // Set style
919  ro.debugName = "PolyLine";
920  ro.blending = false;
921  ro.depthTest = true;
922 
923  // Default color
924  ACG::Vec4f defaultColor = _state.ambient_color() + _state.diffuse_color();
925  ACG::Vec4f selectionColor = ACG::Vec4f(1.0,0.0,0.0,1.0);
926 
927  // Viewport size
928  ACG::Vec2f screenSize(float(_state.viewport_width()), float(_state.viewport_height()));
929 
930  for (unsigned int i = 0; i < _drawMode.getNumLayers(); ++i) {
931  ACG::SceneGraph::Material localMaterial = *_mat;
932 
933  const ACG::SceneGraph::DrawModes::DrawModeProperties* props = _drawMode.getLayer(i);
934 
935  ro.setupShaderGenFromDrawmode(props);
936  ro.shaderDesc.shadeMode = SG_SHADE_UNLIT;
937  ro.vertexDecl = &vertexDecl_;
938 
939  //---------------------------------------------------
940  // No lighting!
941  // Therefore we need some emissive color
942  //---------------------------------------------------
943  localMaterial.baseColor(defaultColor);
944  ro.setMaterial(&localMaterial);
945 
946 
947  switch (props->primitive()) {
948 
949  case ACG::SceneGraph::DrawModes::PRIMITIVE_POINT:
950 
951  // Render all vertices which are selected via an index buffer
952  ro.debugName = "polyline.Points.selected";
953  localMaterial.baseColor(selectionColor);
954  ro.setMaterial(&localMaterial);
955 
956  // Point Size geometry shader
957  ro.setupPointRendering(_mat->pointSize(), screenSize);
958 
959  // selection without colors
960  ro.shaderDesc.vertexColors = false;
961 
962  if (!selectedVertexIndexBuffer_.empty())
963  {
964  ro.glDrawElements(GL_POINTS, selectedVertexIndexBuffer_.size(), GL_UNSIGNED_INT, &(selectedVertexIndexBuffer_[0]));
965  // apply user settings
966  applyRenderObjectSettings(props->primitive(), &ro);
967 
968  _renderer->addRenderObject(&ro);
969  }
970 
971  // Render all vertices (ignore selection here!)
972  ro.debugName = "polyline.Points";
973  localMaterial.baseColor(defaultColor);
974  ro.setMaterial(&localMaterial);
975  ro.glDrawArrays(GL_POINTS, 0, polyline_.n_vertices());
976 
977  if (props->colored() && polyline_.vertex_colors_available())
978  {
979  ro.vertexDecl = &vertexDeclVCol_;
980  ro.shaderDesc.vertexColors = true;
981  }
982 
983 
984  // Point Size geometry shader
985  ro.setupPointRendering(_mat->pointSize(), screenSize);
986 
987  // apply user settings
988  applyRenderObjectSettings(props->primitive(), &ro);
989 
990  _renderer->addRenderObject(&ro);
991 
992  break;
993 
994  case ACG::SceneGraph::DrawModes::PRIMITIVE_WIREFRAME:
995  case ACG::SceneGraph::DrawModes::PRIMITIVE_EDGE:
996 
997  // Render all edges which are selected via an index buffer
998  ro.debugName = "polyline.Wireframe.selected";
999  localMaterial.baseColor(selectionColor);
1000  ro.setMaterial(&localMaterial);
1001 
1002  // Line Width geometry shader
1003  ro.setupLineRendering(_state.line_width(), screenSize);
1004 
1005  // selection without colors
1006  ro.shaderDesc.vertexColors = false;
1007 
1008  if (!selectedEdgeIndexBuffer_.empty())
1009  {
1010  ro.glDrawElements(GL_LINES, selectedEdgeIndexBuffer_.size(), GL_UNSIGNED_INT, &(selectedEdgeIndexBuffer_[0]));
1011 
1012  // apply user settings
1013  applyRenderObjectSettings(props->primitive(), &ro);
1014 
1015  _renderer->addRenderObject(&ro);
1016  }
1017 
1018  ro.debugName = "polyline.Wireframe";
1019  localMaterial.baseColor(defaultColor);
1020  ro.setMaterial(&localMaterial);
1021  // The first point is mapped to an additional last point in buffer, so we can
1022  // just Render one point more to get a closed line
1023  if ( polyline_.is_closed() )
1024  ro.glDrawArrays(GL_LINE_STRIP, 0, polyline_.n_vertices() + 1);
1025  else
1026  ro.glDrawArrays(GL_LINE_STRIP, 0, polyline_.n_vertices());
1027 
1028  if (props->colored() && polyline_.edge_colors_available())
1029  {
1030  ro.vertexDecl = &vertexDeclECol_;
1031  ro.shaderDesc.vertexColors = true;
1032  }
1033 
1034  // Line Width geometry shader
1035  ro.setupLineRendering(_state.line_width(), screenSize);
1036 
1037  // apply user settings
1038  applyRenderObjectSettings(props->primitive(), &ro);
1039 
1040  _renderer->addRenderObject(&ro);
1041 
1042  break;
1043 
1044 
1045  case ACG::SceneGraph::DrawModes::PRIMITIVE_POLYGON:
1046  {
1047  // create sphere object for each vertex
1048  // potential optimization: create only one render object and use instancing
1049 
1050  // use world space radius or screen space point size?
1051  bool screenScale = _drawMode & POINTS_SPHERES_SCREEN;
1052 
1053  // clear shaders used by thick line / point drawing
1054  ro.shaderDesc.vertexTemplateFile.clear();
1055  ro.shaderDesc.geometryTemplateFile.clear();
1056  ro.shaderDesc.fragmentTemplateFile.clear();
1057 
1058  // create sphere if not yet done
1059  if (!sphere_)
1060  sphere_ = new GLSphere(10, 10);
1061 
1062  // precompute desired radius of projected sphere
1063  double r = 1.0;
1064  if (screenScale)
1065  r = 0.5*_state.point_size() / double(_state.viewport_height())*2.0*tan(0.5*_state.fovy());
1066 
1067  // get eye position and view direction in world space
1068  Vec3d eyePos = _state.eye();
1069  Vec3d viewDir = _state.viewing_direction();
1070 
1071  // render-objects for the selected points with selection color
1072  if (polyline_.vertex_selections_available())
1073  {
1074  ro.debugName = "polyline.Sphere.selected";
1075  localMaterial.baseColor(selectionColor);
1076  ro.setMaterial(&localMaterial);
1077 
1078  for (unsigned int i = 0; i < polyline_.n_vertices(); ++i)
1079  {
1080  if (polyline_.vertex_selected(i))
1081  {
1082  double radius = _state.point_size();
1083  if (screenScale)
1084  {
1085  // compute radius in 3D
1086  const Vec3d p = (Vec3d)polyline_.point(i) - eyePos;
1087  radius = (p | viewDir) * r;
1088  }
1089 
1090  sphere_->addToRenderer(_renderer, &ro, radius, (Vec3f)polyline_.point(i));
1091  }
1092  }
1093  }
1094 
1095  // unselected points with default color
1096  ro.debugName = "polyline.Sphere";
1097  localMaterial.baseColor(defaultColor);
1098  ro.setMaterial(&localMaterial);
1099 
1100  for (unsigned int i = 0; i < polyline_.n_vertices(); ++i)
1101  {
1102  if (!polyline_.vertex_selections_available() || !polyline_.vertex_selected(i))
1103  {
1104  double radius = _state.point_size();
1105  if (screenScale)
1106  {
1107  // compute radius in 3D
1108  const Vec3d p = (Vec3d)polyline_.point(i) - eyePos;
1109  radius = (p | viewDir) * r;
1110  }
1111 
1112  sphere_->addToRenderer(_renderer, &ro, radius, (Vec3f)polyline_.point(i));
1113  }
1114  }
1115  } break;
1116 
1117 
1118  default:
1119  break;
1120  }
1121 
1122  }
1123 
1124 }
1125 
1126 //----------------------------------------------------------------------------
1127 
1128 template <class PolyLine>
1129 int
1131 addCustomBuffer( const ACG::VertexElement& _desc, const void* _buffer) {
1132 
1133  if (_buffer) {
1134  customBuffers_.push_back( std::pair<ACG::VertexElement, const void*>(_desc, _buffer) );
1135  update();
1136 
1137  return int(customBuffers_.size()-1);
1138  }
1139  else
1140  {
1141  std::cerr << "PolyLineNodeT::addCustomBuffer - null pointer buffer" << std::endl;
1142  return -1;
1143  }
1144 }
1145 
1146 //----------------------------------------------------------------------------
1147 
1148 template <class PolyLine>
1149 void
1151 setCustomBuffer( int _id, const void* _buffer) {
1152 
1153  customBuffers_[_id].second = _buffer;
1154  update();
1155 }
1156 
1157 //=============================================================================
1158 } // namespace SceneGraph
1159 } // namespace ACG
1160 //=============================================================================
vector_type & maximize(const vector_type &_rhs)
maximize values: same as *this = max(*this, _rhs), but faster
Definition: Vector11T.hh:563
static ShaderCache * getInstance()
Return instance of the ShaderCache singleton.
Definition: ShaderCache.cc:84
Namespace providing different geometric functions concerning angles.
double fovy() const
get field of view in y direction
void setupShaderGenFromDrawmode(const SceneGraph::DrawModes::DrawModeProperties *_props)
Fills out ShaderGenDesc parameters based on Drawmode properties.
Class to define the vertex input layout.
GLSL::Program * getProgram(const ShaderGenDesc *_desc, const std::vector< unsigned int > &_mods)
Query a dynamically generated program from cache.
Definition: ShaderCache.cc:102
void push_back(BaseNode *_node)
Insert _node at the end of the list of children.
static void enable(GLenum _cap, bool _warnRemoved=true)
replaces glEnable, but supports locking
void pointSize(float _sz)
set point size (default: 1.0)
defined by user via VertexElement::shaderInputName_
const GLMatrixd & projection() const
get projection matrix
Definition: GLState.hh:786
VectorT< float, 4 > Vec4f
Definition: VectorT.hh:138
void set_color(const Vec4f &_col)
set color
Definition: GLState.cc:691
void initFromState(GLState *_glState)
Initializes a RenderObject instance.
Definition: RenderObject.cc:61
size_t pick_current_index() const
Returns the current color picking index (can be used for caching)
Definition: GLState.cc:1131
float point_size() const
get point size
Definition: GLState.hh:970
float line_width() const
get line width
Definition: GLState.hh:975
void disable()
Resets to standard rendering pipeline.
Definition: GLSLShader.cc:355
Interface class between scenegraph and renderer.
Definition: RenderObject.hh:98
size_t getNumLayers() const
returns the layer count
Definition: DrawModes.cc:531
GLSL program class.
Definition: GLSLShader.hh:211
float line_width() const
get line width
float point_size() const
get point size
int viewport_width() const
get viewport width
static void disableClientState(GLenum _cap)
replaces glDisableClientState, supports locking
Definition: GLState.cc:1584
void setupPointRendering(float _pointSize, const Vec2f &_screenSize)
Setup rendering of circle points.
const Vec4f & ambient_color() const
get ambient color
void baseColor(const Vec4f &_c)
set the base color (Sets the baseColor which is the same as the emission(const Vec4f& _c) ) ...
void setVertexStride(unsigned int _stride)
VERTEX_USAGE usage_
position, normal, shader input ..
void set_point_size(float _f)
set point size
Definition: GLState.cc:776
void addElement(const VertexElement *_pElement)
bool colored() const
Are colors used?
Definition: DrawModes.hh:222
void set_line_width(float _f)
set line width
Definition: GLState.cc:791
double fovy() const
get field of view in y direction
Definition: GLState.cc:868
Vec3d viewing_direction() const
get viewing ray
GLuint vertexBuffer
VBO, IBO ids, ignored if VAO is provided.
int viewport_height() const
get viewport height
int viewport_height() const
get viewport height
Definition: GLState.hh:824
const char * shaderInputName_
set shader input name, if usage_ = VERTEX_USAGE_USER_DEFINED otherwise this is set automatically...
void setByteOffset(unsigned int _offset)
const DrawMode & addDrawMode(const std::string &_name, bool _propertyBased)
Add a custom DrawMode.
Definition: DrawModes.cc:765
bool ACGDLLEXPORT openGLVersionTest(const int _major, const int _minor)
Definition: gl.hh:265
virtual void addRenderObject(RenderObject *_renderObject)
Callback for the scenegraph nodes, which send new render objects via this function.
Definition: IRenderer.cc:104
Vec3d viewing_direction() const
get viewing ray
Definition: GLState.hh:848
Description of one vertex element.
void setupLineRendering(float _lineWidth, const Vec2f &_screenSize)
Setup rendering of thick lines.
Vec3d eye() const
get eye point
Definition: GLState.cc:886
const GLMatrixd & modelview() const
get modelview matrix
Definition: GLState.hh:791
static void vertexPointer(GLint _size, GLenum _type, GLsizei _stride, const GLvoid *_pointer)
replaces glVertexPointer, supports locking
Definition: GLState.cc:1918
const Vec4f & diffuse_color() const
get diffuse color
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 DrawModeProperties * getLayer(unsigned int _i) const
returns the property set at layer i
Definition: DrawModes.cc:535
static size_t getElementSize(const VertexElement *_pElement)
static void bindBuffer(GLenum _target, GLuint _buffer)
replaces glBindBuffer, supports locking
Definition: GLState.cc:1820
const VertexElement * findElementByUsage(VERTEX_USAGE _usage) const
PolyLineNodeT(PolyLine &_pl, BaseNode *_parent=0, std::string _name="<PolyLineNode>")
Constructor.
Vec3d eye() const
get eye point
const void * pointer_
Offset in bytes to the first occurrence of this element in vertex buffer; Or address to vertex data i...
unsigned int getByteOffset() const
const Vec4f & diffuse_color() const
get diffuse color
Definition: GLState.hh:936
unsigned int numElements_
how many elements of type_
bool isLinked()
Returns if the program object has been succesfully linked.
Definition: GLSLShader.cc:370
static void disable(GLenum _cap, bool _warnRemoved=true)
replaces glDisable, but supports locking
Definition: GLState.cc:1527
static void enableClientState(GLenum _cap)
replaces glEnableClientState, supports locking
Definition: GLState.cc:1570
const VertexDeclaration * vertexDecl
Defines the vertex buffer layout, ignored if VAO is provided.
const Vec4f & ambient_color() const
get ambient color
Definition: GLState.hh:931
void setUniform(const char *_name, GLint _value)
Set int uniform to specified value.
Definition: GLSLShader.cc:385
DrawModeProperties stores a set of properties that defines, how to render an object.
Definition: DrawModes.hh:177
bool pick_set_maximum(size_t _idx)
Set the maximal number of primitives/components of your object.
Definition: GLState.cc:1051
void pick_set_name(size_t _idx)
sets the current name/color (like glLoadName(_idx))
Definition: GLState.cc:1061
int priority
Priority to allow sorting of objects.
void use()
Enables the program object for using.
Definition: GLSLShader.cc:345
unsigned int type_
GL_FLOAT, GL_UNSIGNED_BYTE, GL_INT, ...