Developer Documentation
LineNode.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 
47 //=============================================================================
48 //
49 // CLASS LineNode - IMPLEMENTATION
50 //
51 //=============================================================================
52 
53 //== INCLUDES =================================================================
54 #include <ACG/GL/acg_glew.hh>
55 #include "LineNode.hh"
56 #include <ACG/GL/IRenderer.hh>
57 
58 //== NAMESPACES ===============================================================
59 
60 namespace ACG {
61 namespace SceneGraph {
62 
63 //== IMPLEMENTATION ==========================================================
64 
66  BaseNode* _parent,
67  std::string _name ) :
68  MaterialNode(_parent, _name, MaterialNode::BaseColor | MaterialNode::LineWidth),
69  picking_line_width_(std::numeric_limits<float>::infinity()),
70  line_mode_(_mode),
71  draw_always_on_top (false),
72  prev_depth_(GL_LESS),
73  vbo_(0),
74  updateVBO_(true),
75  lineNodeName_("")
76 {
78 }
79 
80 //----------------------------------------------------------------------------
81 
83  if (vbo_)
84  glDeleteBuffers(1, &vbo_);
85 
86 }
87 
88 //----------------------------------------------------------------------------
89 
91 {
92  // Set the new line mode
93  line_mode_ = _mode;
94 
95  // Force an update of the vbo
96  updateVBO_ = true;
97 }
98 
99 //----------------------------------------------------------------------------
100 
102 {
103  clear_points();
104  clear_colors();
105 }
106 
107 //----------------------------------------------------------------------------
108 
110 {
111  points_.clear();
112 
113  // Force an update of the vbo
114  updateVBO_ = true;
115 }
116 
117 //----------------------------------------------------------------------------
118 
120 {
121  colors_.clear();
122  colors4f_.clear();
123 
124  // Force an update of the vbo
125  updateVBO_ = true;
126 }
127 
128 //----------------------------------------------------------------------------
129 
130 void LineNode::set_color(const Vec4f& _c)
131 {
132  clear_colors();
133  add_color(ACG::Vec3uc((char) (((int) _c[0]) * 255),
134  (char) (((int) _c[1]) * 255),
135  (char) (((int) _c[2]) * 255)));
137 }
138 
139 //----------------------------------------------------------------------------
140 
141 void LineNode::add_point(const Vec3d& _v)
142 {
143  points_.push_back(_v);
144 
145  // Force an update of the vbo
146  updateVBO_ = true;
147 }
148 
149 //----------------------------------------------------------------------------
150 
151 void LineNode::add_line(const Vec3d& _v0, const Vec3d& _v1)
152 {
153  add_point(_v0);
154  add_point(_v1);
155 
156  // Force an update of the vbo
157  updateVBO_ = true;
158 }
159 
160 //----------------------------------------------------------------------------
161 
163 {
164  colors_.push_back(_c);
165 
166  // Force an update of the vbo
167  updateVBO_ = true;
168 }
169 
170 //----------------------------------------------------------------------------
171 
173 {
174  colors4f_.push_back(_c);
175 
176  // Force an update of the vbo
177  updateVBO_ = true;
178 }
179 
180 //----------------------------------------------------------------------------
181 
182 void
184 boundingBox(Vec3d& _bbMin, Vec3d& _bbMax)
185 {
186  ConstPointIter p_it=points_.begin(), p_end=points_.end();
187  for (; p_it!=p_end; ++p_it)
188  {
189  _bbMax.maximize(*p_it);
190  _bbMin.minimize(*p_it);
191  }
192 }
193 
194 
195 //----------------------------------------------------------------------------
196 
197 
201 {
202  return DrawModes::WIREFRAME;
203 }
204 
205 
206 //----------------------------------------------------------------------------
207 
208 void
210 enter(GLState& _state , const DrawModes::DrawMode& _drawMode)
211 {
212  MaterialNode::enter(_state, _drawMode);
213 
214  if (alwaysOnTop()) {
215  //store current depth comparison function (needed for lasso selection)
216  prev_depth_ = _state.depthFunc();
217 
218  //set depth function and change GLState accordingly
219  _state.set_depthFunc(GL_ALWAYS);
220  }
221 }
222 
223 //----------------------------------------------------------------------------
224 
225 void
227 draw(GLState& _state , const DrawModes::DrawMode& _drawMode)
228 {
229  if(_state.compatibilityProfile())
230  drawCompat(_state, _drawMode);
231  else
232  {
233  /* //Node Based Drawing is not supported on Core profiles
234  if (_drawMode & DrawModes::WIREFRAME)
235  {
236  ACG::GLState::disable(GL_LIGHTING);
237 
238 
239  // if (line_mode_ == LineSegmentsMode)
240  // glBegin(GL_LINES);
241  // else
242  // glBegin(GL_LINE_STRIP);
243 
244 
245  if (line_mode_ == LineSegmentsMode)
246  {
247  // first check if (new standard) 4-channel colors are specified
248  if( (points_.size()/2 == colors4f_.size()) )
249  {
250  // enable blending of lines
251  GLboolean blendb;
252  glGetBooleanv( GL_BLEND, &blendb);
253  glEnable(GL_BLEND);
254  // blend ontop of prev. drawn mesh
255  GLboolean depthmaskb;
256  glGetBooleanv( GL_DEPTH_WRITEMASK, &depthmaskb);
257  glDepthMask(GL_FALSE);
258 
259  glBegin(GL_LINES);
260 
261  ConstPointIter p_it=points_.begin(), p_end=points_.end();
262  ConstColor4fIter c_it=colors4f_.begin();
263 
264  Color4f c(1.0f,1.0f,1.0f,1.0f);
265  if(c_it != colors4f_.end()) {
266  c = *c_it;
267  }
268 
269  int cnt = 0;
270  for (; p_it!=p_end; ++p_it)
271  {
272  if ((cnt > 0) && (cnt % 2 == 0) && (c_it+1) != colors4f_.end()) {
273  ++c_it;
274  c = *c_it;
275  }
276 
277  glColor(c);
278  glVertex(*p_it);
279 
280  ++cnt;
281  }
282 
283  glEnd();
284 
285  // disable blending of lines
286  if( blendb == GL_FALSE )
287  glDisable(GL_BLEND);
288 
289  // enable depth mask
290  if( depthmaskb == GL_TRUE )
291  glDepthMask(GL_TRUE);
292 
293  }
294  else if ((line_mode_ == LineSegmentsMode) && (points_.size()/2 == colors_.size()) )
295  {
296  glBegin(GL_LINES);
297  ConstPointIter p_it=points_.begin(), p_end=points_.end();
298  ConstColorIter c_it=colors_.begin();
299 
300  Color c((char)255, (char)255, (char)255);
301  if(c_it != colors_.end()) {
302  c = *c_it;
303  }
304 
305  int cnt = 0;
306  for (; p_it!=p_end; ++p_it)
307  {
308  if ((cnt > 0) && (cnt % 2 == 0) && (c_it+1) != colors_.end()) {
309  ++c_it;
310  c = *c_it;
311  }
312 
313  glColor(c);
314  glVertex(*p_it);
315 
316  ++cnt;
317  }
318  glEnd();
319  }
320  else
321  {
322  glBegin(GL_LINES);
323 
324  ConstPointIter p_it=points_.begin(), p_end=points_.end();
325 
326  for (; p_it!=p_end; ++p_it)
327  {
328  glVertex(*p_it);
329  }
330 
331  glEnd();
332  }
333  }
334  else
335  {
336  _state.set_color(_state.base_color());
337  glBegin(GL_LINE_STRIP);
338  ConstPointIter p_it=points_.begin(), p_end=points_.end();
339  for (; p_it!=p_end; ++p_it)
340  glVertex(*p_it);
341  glEnd();
342  }
343 
344  //glEnd();
345  }*/
346  }
347 }
348 
349 //----------------------------------------------------------------------------
350 
351 void
353 leave(GLState& _state , const DrawModes::DrawMode& _drawMode)
354 {
355  if (alwaysOnTop()) {
356  //restore depth function and change GLState accordingly
357  _state.set_depthFunc(prev_depth_);
358  }
359 
360  MaterialNode::leave(_state, _drawMode);
361 }
362 
363 //----------------------------------------------------------------------------
364 
365 void LineNode::pick(GLState& _state , PickTarget _target)
366 {
367  if(_state.compatibilityProfile())
368  pickCompat(_state, _target);
369  else
370  {
371  if (n_points() == 0)
372  return;
373 
374  // Bind the vertex array
375  ACG::GLState::bindBuffer(GL_ARRAY_BUFFER_ARB, 0);
376 
377  const size_t n_edges = n_points() - 1;
378 
379  switch (_target)
380  {
381  case PICK_EDGE:
382  {
383  _state.pick_set_maximum (n_edges);
384  pick_edges(_state, 0);
385  break;
386  }
387 
388  case PICK_ANYTHING:
389  {
390  _state.pick_set_maximum (n_edges);
391  pick_edges(_state, 0);
392  break;
393  }
394 
395  default:
396  break;
397  }
398  }
399 }
400 
401 //----------------------------------------------------------------------------
402 
403 void LineNode::pick_edges(GLState& _state, unsigned int _offset)
404 {
405  //TODO: implement edge picking for lines in CoreProfile
406 }
407 
408 //----------------------------------------------------------------------------
409 
411 {
412  if (!updateVBO_)
413  return;
414 
415  // create vbo if it does not exist
416  if (!vbo_)
417  glGenBuffers(1, &vbo_);
418 
419  vertexDecl_.clear();
420  vertexDecl_.addElement(GL_FLOAT, 3, VERTEX_USAGE_POSITION);
421 
422  //3 coordinates per vertex
423  std::vector<float> vboData(3*points_.size(),0.f);
424 
425  if (line_mode_ == LineSegmentsMode)
426  {
427  if( (points_.size()/2 == colors4f_.size()) )
428  {
429  // === One color entry per line segment (alpha channel available ) ===
430  vertexDecl_.addElement(GL_FLOAT, 4, VERTEX_USAGE_COLOR);
431  vboData.resize(vboData.size() + 4 * points_.size());
432  float* vboPtr = &vboData[0];
433 
434  ConstPointIter p_it=points_.begin(), p_end=points_.end();
435  ConstColor4fIter c_it=colors4f_.begin();
436 
437  Color4f c(1.0f,1.0f,1.0f,1.0f);
438  if(c_it != colors4f_.end()) {
439  c = *c_it;
440  }
441 
442  int cnt = 0;
443  for (; p_it!=p_end; ++p_it)
444  {
445  if ((cnt > 0) && (cnt % 2 == 0) && (c_it+1) != colors4f_.end()) {
446  ++c_it;
447  c = *c_it;
448  }
449  //add position information
450  *(vboPtr++) = (*p_it)[0];
451  *(vboPtr++) = (*p_it)[1];
452  *(vboPtr++) = (*p_it)[2];
453 
454  //add color information
455  *(vboPtr++) = c[0];
456  *(vboPtr++) = c[1];
457  *(vboPtr++) = c[2];
458  *(vboPtr++) = c[3];
459 
460  ++cnt;
461  }
462 
463  //====================
464  } else if ( points_.size()/2 == colors_.size() )
465  {
466  //=== One color entry per line segment (no alpha channel available and uchars as colors) ===
467  vertexDecl_.addElement(GL_FLOAT, 4, VERTEX_USAGE_COLOR);
468  //add 4 colors for each vertex
469  vboData.resize(vboData.size() + 4 * points_.size());
470  float* vboPtr = &vboData[0];
471 
472  ConstPointIter p_it=points_.begin(), p_end=points_.end();
473  ConstColorIter c_it=colors_.begin();
474 
475  Color c((char)255, (char)255, (char)255);
476  if(c_it != colors_.end()) {
477  c = *c_it;
478  }
479 
480  int cnt = 0;
481  for (; p_it!=p_end; ++p_it)
482  {
483  if ((cnt > 0) && (cnt % 2 == 0) && (c_it+1) != colors_.end()) {
484  ++c_it;
485  c = *c_it;
486  }
487 
488  //add position information
489  *(vboPtr++) = (*p_it)[0];
490  *(vboPtr++) = (*p_it)[1];
491  *(vboPtr++) = (*p_it)[2];
492 
493  //add color information
494  *(vboPtr++) = c[0]/255.f;
495  *(vboPtr++) = c[1]/255.f;
496  *(vboPtr++) = c[2]/255.f;
497  *(vboPtr++) = 1.f;
498 
499  ++cnt;
500  }
501 
502  //===========
503  } else
504  {
505  //=== No colors. Just draw the segments ===
506  ConstPointIter p_it=points_.begin(), p_end=points_.end();
507  float* vboPtr = &vboData[0];
508 
509  for (; p_it!=p_end; ++p_it)
510  {
511  *(vboPtr++) = (*p_it)[0];
512  *(vboPtr++) = (*p_it)[1];
513  *(vboPtr++) = (*p_it)[2];
514  }
515  //===========
516  }
517 
518 
519  }
520  else
521  {
522  // === No colors (Use material) and one continuous line ===
523  // Pointer to it for easier copy operation
524  float* pPoints = &vboData[0];
525 
526  // Copy from internal storage to vbo in memory
527  for (unsigned int i = 0 ; i < points_.size(); ++i) {
528  for ( unsigned int j = 0 ; j < 3 ; ++j) {
529  *(pPoints++) = points_[i][j];
530  }
531  }
532  }
533 
534  glBindBuffer(GL_ARRAY_BUFFER_ARB, vbo_);
535  glBufferData(GL_ARRAY_BUFFER_ARB, vboData.size()*sizeof(float) , &vboData[0] , GL_STATIC_DRAW_ARB);
536 
537  // Update done.
538  updateVBO_ = false;
539 
540 }
541 
542 void
544 getRenderObjects(IRenderer* _renderer, GLState& _state , const DrawModes::DrawMode& _drawMode , const ACG::SceneGraph::Material* _mat) {
545 
546  if (points_.empty())
547  return;
548 
549  // init base render object
550 
551  RenderObject ro;
552  ro.initFromState(&_state);
553  ro.setMaterial(_mat);
554 
555  lineNodeName_ = std::string("LineNode: ")+name();
556  ro.debugName = lineNodeName_;
557 
558  // draw after scene-meshes
559  if (draw_always_on_top)
560  {
561  ro.priority = 1;
562  ro.depthTest = false;
563  ro.depthWrite = false;
564  }
565  else
566  {
567  ro.depthTest = true;
568  ro.depthWrite = true;
569  }
570 
571  //set blending
572  if ((line_mode_ == LineSegmentsMode) && (points_.size()/2 == colors4f_.size()))
573  {
574  ro.blending = true;
575  ro.blendSrc = GL_SRC_ALPHA;
576  ro.blendDest = GL_ONE_MINUS_SRC_ALPHA;
577  }
578 
579  // simulate line width via quad extrusion in geometry shader
580  QString geomTemplate = ShaderProgGenerator::getShaderDir();
581  geomTemplate += "Wireframe/geom_line2quad.tpl";
582 
583  ro.shaderDesc.geometryTemplateFile = geomTemplate;
584 
585  ro.setUniform("screenSize", Vec2f((float)_state.viewport_width(), (float)_state.viewport_height()));
586  ro.setUniform("lineWidth", _state.line_width());
587 
588  createVBO();
589  ro.vertexBuffer = vbo_;
590  // vertexDecl is defined in createVBO
591  ro.vertexDecl = &vertexDecl_;
592 
593  //besides of the position, colors are saved so we can show them
594  if (vertexDecl_.getNumElements() > 1)
595  ro.shaderDesc.vertexColors = true;
596 
597 
598  if (line_mode_ == LineSegmentsMode)
599  ro.glDrawArrays(GL_LINES, 0, int( points_.size() ));
600  else
601  ro.glDrawArrays(GL_LINE_STRIP, 0, int(points_.size()) );
602 
603  _renderer->addRenderObject(&ro);
604 
605 }
606 
607 //=============================================================================
608 } // namespace SceneGraph
609 } // namespace ACG
610 //=============================================================================
vector_type & maximize(const vector_type &_rhs)
maximize values: same as *this = max(*this, _rhs), but faster
Definition: Vector11T.hh:563
DrawMode WIREFRAME
draw wireframe
Definition: DrawModes.cc:78
Namespace providing different geometric functions concerning angles.
void boundingBox(Vec3d &_bbMin, Vec3d &_bbMax)
update bounding box
Definition: LineNode.cc:184
void leave(GLState &_state, const DrawModes::DrawMode &_drawMode)
reset depth function to what it was before enter()
Definition: LineNode.cc:353
pick any of the prior targets (should be implemented for all nodes)
Definition: PickTarget.hh:84
void createVBO()
creates the vbo only if update was requested
Definition: LineNode.cc:410
void clear_points()
clear points/lines
Definition: LineNode.cc:109
void set_color(const Vec4f &_c)
set color (base, ambient, diffuse, specular) based on _c
const GLenum & depthFunc() const
get glDepthFunc() that is supposed to be active
Definition: GLState.cc:941
std::string name() const
Returns: name of node (needs not be unique)
DrawModes::DrawMode drawMode() const
Return the own draw modes of this node.
static void bindBuffer(GLenum _target, GLuint _buffer)
replaces glBindBuffer, supports locking
void getRenderObjects(IRenderer *_renderer, GLState &_state, const DrawModes::DrawMode &_drawMode, const ACG::SceneGraph::Material *_mat)
Add the objects to the given renderer.
Definition: LineNode.cc:544
void leave(GLState &_state, const DrawModes::DrawMode &_drawmode)
restores original GL-color and GL-material
void enter(GLState &_state, const DrawModes::DrawMode &_drawmode)
set current GL-color and GL-material
void initFromState(GLState *_glState)
Initializes a RenderObject instance.
Definition: RenderObject.cc:61
int viewport_width() const
get viewport width
Definition: GLState.hh:822
float line_width() const
get line width
Definition: GLState.hh:975
void draw(GLState &_state, const DrawModes::DrawMode &_drawMode)
draw lines and normals
Definition: LineNode.cc:227
unsigned int getNumElements() const
void set_depthFunc(const GLenum &_depth_func)
Call glDepthFunc() to actually change the depth comparison function, and store the new value in this ...
Definition: GLState.cc:948
Interface class between scenegraph and renderer.
Definition: RenderObject.hh:98
void add_point(const Vec3d &_v)
add point (for LineMode == PolygonMode)
Definition: LineNode.cc:141
void pick(GLState &_state, PickTarget _target)
Draw the line using the GL picking name stack.
Definition: LineNode.cc:365
void enter(GLState &_state, const DrawModes::DrawMode &_drawMode)
set depth function (needed for lasso selection so that the line can be draw in pseudo-2D) ...
Definition: LineNode.cc:210
LineMode
Line mode: draw line segments (every 2 points) or ONE polyline.
Definition: LineNode.hh:102
~LineNode()
destructor
Definition: LineNode.cc:82
VectorT< float, 2 > Vec2f
Definition: VectorT.hh:102
LineNode(LineMode _mode, BaseNode *_parent=0, std::string _name="<LineNode>")
default constructor
Definition: LineNode.cc:65
void add_line(const Vec3d &_v0, const Vec3d &_v1)
add line (for LineMode == LineSegmentsMode)
Definition: LineNode.cc:151
void addElement(const VertexElement *_pElement)
GLuint vertexBuffer
VBO, IBO ids, ignored if VAO is provided.
int viewport_height() const
get viewport height
Definition: GLState.hh:824
void setUniform(const char *_name, GLint _value)
set values for int uniforms
DrawModes::DrawMode availableDrawModes() const
return available draw modes
Definition: LineNode.cc:200
STL namespace.
picks edges (may not be implemented for all nodes)
Definition: PickTarget.hh:80
void clear_colors()
clear colors
Definition: LineNode.cc:119
virtual void addRenderObject(RenderObject *_renderObject)
Callback for the scenegraph nodes, which send new render objects via this function.
Definition: IRenderer.cc:104
static QString getShaderDir()
void clear()
clear points/lines and colors
Definition: LineNode.cc:101
ShaderGenDesc shaderDesc
Drawmode and other shader params.
size_t n_points() const
number of points
Definition: LineNode.hh:181
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
void set_color(const Vec4f &_c)
Override material node&#39;s set color function in order to locally add color.
Definition: LineNode.cc:130
GLenum blendDest
glBlendFunc: GL_SRC_ALPHA, GL_ZERO, GL_ONE, GL_ONE_MINUS_SRC_ALPHA ...
const VertexDeclaration * vertexDecl
Defines the vertex buffer layout, ignored if VAO is provided.
void add_color(const ACG::Vec3uc &_c)
add color (only for LineMode == LineSegmentsMode)
Definition: LineNode.cc:162
bool & alwaysOnTop()
get and set always on top
Definition: LineNode.hh:198
bool pick_set_maximum(size_t _idx)
Set the maximal number of primitives/components of your object.
Definition: GLState.cc:1051
void set_line_mode(LineMode _mode)
set line mode (see LineNode::LineMode)
Definition: LineNode.cc:90
int priority
Priority to allow sorting of objects.