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
65namespace ACG {
66namespace SceneGraph {
67
68//== IMPLEMENTATION ==========================================================
69
71template <class PolyLine>
72PolyLineNodeT<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
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
93}
94
95//----------------------------------------------------------------------------
96
97template <class PolyLine>
99{
100 delete sphere_;
101}
102
103//----------------------------------------------------------------------------
104
105template <class PolyLine>
106void
108boundingBox(Vec3d& _bbMin, Vec3d& _bbMax)
109{
110 for (unsigned int i=0; i< polyline_.n_vertices(); ++i)
112 _bbMin.minimize(polyline_.point(i));
113 _bbMax.maximize(polyline_.point(i));
115}
116
118//----------------------------------------------------------------------------
119
120
121template <class PolyLine>
124availableDrawModes() const
125{
126 return (DrawModes::WIREFRAME | DrawModes::POINTS | DrawModes::POINTS_COLORED | POINTS_SPHERES | POINTS_SPHERES_SCREEN | DrawModes::EDGES_COLORED);
127}
128
129
130//----------------------------------------------------------------------------
131
132
133template <class PolyLine>
134void
136draw(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
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
361template <class PolyLine>
362void
364pick(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
439template <class PolyLine>
440void
442pick_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
506template <class PolyLine>
507void
508PolyLineNodeT<PolyLine>::
509pick_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
526template <class PolyLine>
527void
528PolyLineNodeT<PolyLine>::
529pick_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
556template <class PolyLine>
557void
558PolyLineNodeT<PolyLine>::
559pick_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;
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
635template <class PolyLine>
636void
638setupVertexDeclaration(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
688template <class PolyLine>
689size_t
691fillVertexBuffer(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
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
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
754template <class PolyLine>
755void
757updateVBO() {
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
806template <class PolyLine>
807void
809writeVertexColor(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
840template <class PolyLine>
841void
843writeVertex(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
890template <class PolyLine>
891void
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 if (compatibilityProfile( ) ) {
903 _state.enable(GL_COLOR_MATERIAL);
904 _state.enable(GL_LIGHTING);
905 }
906 ro.initFromState(&_state);
907
908 ro.setMaterial(_mat);
909
910 // draw after scene-meshes
911 ro.priority = 1;
912
913 // Update the vbo only if required.
914 if ( updateVBO_ )
915 updateVBO();
916
917 // Set to the right vbo
918 ro.vertexBuffer = vbo_.id();
919
920 // Set style
921 ro.debugName = "PolyLine";
922 ro.blending = false;
923 ro.depthTest = true;
924
925 // Default color
926 ACG::Vec4f defaultColor = _state.ambient_color() + _state.diffuse_color();
927 ACG::Vec4f selectionColor = ACG::Vec4f(1.0,0.0,0.0,1.0);
928
929 // Viewport size
930 ACG::Vec2f screenSize(float(_state.viewport_width()), float(_state.viewport_height()));
931
932 for (unsigned int i = 0; i < _drawMode.getNumLayers(); ++i) {
933 ACG::SceneGraph::Material localMaterial = *_mat;
934
936
938 ro.shaderDesc.shadeMode = SG_SHADE_UNLIT;
939 ro.vertexDecl = &vertexDecl_;
940
941 //---------------------------------------------------
942 // No lighting!
943 // Therefore we need some emissive color
944 //---------------------------------------------------
945 localMaterial.baseColor(defaultColor);
946 ro.setMaterial(&localMaterial);
947
948
949 switch (props->primitive()) {
950
951 case ACG::SceneGraph::DrawModes::PRIMITIVE_POINT:
952
953 // Render all vertices which are selected via an index buffer
954 ro.debugName = "polyline.Points.selected";
955 localMaterial.baseColor(selectionColor);
956 ro.setMaterial(&localMaterial);
957
958 // Point Size geometry shader
959 ro.setupPointRendering(_mat->pointSize(), screenSize);
960
961 // selection without colors
962 ro.shaderDesc.vertexColors = false;
963
964 if (!selectedVertexIndexBuffer_.empty())
965 {
966 ro.glDrawElements(GL_POINTS, selectedVertexIndexBuffer_.size(), GL_UNSIGNED_INT, &(selectedVertexIndexBuffer_[0]));
967 // apply user settings
968 applyRenderObjectSettings(props->primitive(), &ro);
969
970 _renderer->addRenderObject(&ro);
971 }
972
973 // Render all vertices (ignore selection here!)
974 ro.debugName = "polyline.Points";
975 localMaterial.baseColor(defaultColor);
976 ro.setMaterial(&localMaterial);
977 ro.glDrawArrays(GL_POINTS, 0, polyline_.n_vertices());
978
979 if (props->colored() && polyline_.vertex_colors_available())
980 {
981 ro.vertexDecl = &vertexDeclVCol_;
982 ro.shaderDesc.vertexColors = true;
983 }
984
985
986 // Point Size geometry shader
987 ro.setupPointRendering(_mat->pointSize(), screenSize);
988
989 // apply user settings
990 applyRenderObjectSettings(props->primitive(), &ro);
991
992 _renderer->addRenderObject(&ro);
993
994 break;
995
996 case ACG::SceneGraph::DrawModes::PRIMITIVE_WIREFRAME:
997 case ACG::SceneGraph::DrawModes::PRIMITIVE_EDGE:
998
999 // Render all edges which are selected via an index buffer
1000 ro.debugName = "polyline.Wireframe.selected";
1001 localMaterial.baseColor(selectionColor);
1002 ro.setMaterial(&localMaterial);
1003
1004 // Line Width geometry shader
1005 ro.setupLineRendering(_state.line_width(), screenSize);
1006
1007 // selection without colors
1008 ro.shaderDesc.vertexColors = false;
1009
1010 if (!selectedEdgeIndexBuffer_.empty())
1011 {
1012 ro.glDrawElements(GL_LINES, selectedEdgeIndexBuffer_.size(), GL_UNSIGNED_INT, &(selectedEdgeIndexBuffer_[0]));
1013
1014 // apply user settings
1015 applyRenderObjectSettings(props->primitive(), &ro);
1016
1017 _renderer->addRenderObject(&ro);
1018 }
1019
1020 ro.debugName = "polyline.Wireframe";
1021 localMaterial.baseColor(defaultColor);
1022 ro.setMaterial(&localMaterial);
1023 // The first point is mapped to an additional last point in buffer, so we can
1024 // just Render one point more to get a closed line
1025 if ( polyline_.is_closed() )
1026 ro.glDrawArrays(GL_LINE_STRIP, 0, polyline_.n_vertices() + 1);
1027 else
1028 ro.glDrawArrays(GL_LINE_STRIP, 0, polyline_.n_vertices());
1029
1030 if (props->colored() && polyline_.edge_colors_available())
1031 {
1032 ro.vertexDecl = &vertexDeclECol_;
1033 ro.shaderDesc.vertexColors = true;
1034 }
1035
1036 // Line Width geometry shader
1037 ro.setupLineRendering(_state.line_width(), screenSize);
1038
1039 // apply user settings
1040 applyRenderObjectSettings(props->primitive(), &ro);
1041
1042 _renderer->addRenderObject(&ro);
1043
1044 break;
1045
1046
1047 case ACG::SceneGraph::DrawModes::PRIMITIVE_POLYGON:
1048 {
1049 // create sphere object for each vertex
1050 // potential optimization: create only one render object and use instancing
1051
1052 // use world space radius or screen space point size?
1053 bool screenScale = _drawMode & POINTS_SPHERES_SCREEN;
1054
1055 // clear shaders used by thick line / point drawing
1056 ro.shaderDesc.vertexTemplateFile.clear();
1057 ro.shaderDesc.geometryTemplateFile.clear();
1058 ro.shaderDesc.fragmentTemplateFile.clear();
1059
1060 // create sphere if not yet done
1061 if (!sphere_)
1062 sphere_ = new GLSphere(10, 10);
1063
1064 // precompute desired radius of projected sphere
1065 double r = 1.0;
1066 if (screenScale)
1067 r = 0.5*_state.point_size() / double(_state.viewport_height())*2.0*tan(0.5*_state.fovy());
1068
1069 // get eye position and view direction in world space
1070 Vec3d eyePos = _state.eye();
1071 Vec3d viewDir = _state.viewing_direction();
1072
1073 // render-objects for the selected points with selection color
1074 if (polyline_.vertex_selections_available())
1075 {
1076 ro.debugName = "polyline.Sphere.selected";
1077 localMaterial.baseColor(selectionColor);
1078 ro.setMaterial(&localMaterial);
1079
1080 for (unsigned int i = 0; i < polyline_.n_vertices(); ++i)
1081 {
1082 if (polyline_.vertex_selected(i))
1083 {
1084 double radius = _state.point_size();
1085 if (screenScale)
1086 {
1087 // compute radius in 3D
1088 const Vec3d p = (Vec3d)polyline_.point(i) - eyePos;
1089 radius = (p | viewDir) * r;
1090 }
1091
1092 sphere_->addToRenderer(_renderer, &ro, radius, (Vec3f)polyline_.point(i));
1093 }
1094 }
1095 }
1096
1097 // unselected points with default color
1098 ro.debugName = "polyline.Sphere";
1099 localMaterial.baseColor(defaultColor);
1100 ro.setMaterial(&localMaterial);
1101
1102 for (unsigned int i = 0; i < polyline_.n_vertices(); ++i)
1103 {
1104 if (!polyline_.vertex_selections_available() || !polyline_.vertex_selected(i))
1105 {
1106 double radius = _state.point_size();
1107 if (screenScale)
1108 {
1109 // compute radius in 3D
1110 const Vec3d p = (Vec3d)polyline_.point(i) - eyePos;
1111 radius = (p | viewDir) * r;
1112 }
1113
1114 sphere_->addToRenderer(_renderer, &ro, radius, (Vec3f)polyline_.point(i));
1115 }
1116 }
1117 } break;
1118
1119
1120 default:
1121 break;
1122 }
1123
1124 }
1125
1126}
1127
1128//----------------------------------------------------------------------------
1129
1130template <class PolyLine>
1131int
1133addCustomBuffer( const ACG::VertexElement& _desc, const void* _buffer) {
1134
1135 if (_buffer) {
1136 customBuffers_.push_back( std::pair<ACG::VertexElement, const void*>(_desc, _buffer) );
1137 update();
1138
1139 return int(customBuffers_.size()-1);
1140 }
1141 else
1142 {
1143 std::cerr << "PolyLineNodeT::addCustomBuffer - null pointer buffer" << std::endl;
1144 return -1;
1145 }
1146}
1147
1148//----------------------------------------------------------------------------
1149
1150template <class PolyLine>
1151void
1153setCustomBuffer( int _id, const void* _buffer) {
1154
1155 customBuffers_[_id].second = _buffer;
1156 update();
1157}
1158
1159//=============================================================================
1160} // namespace SceneGraph
1161} // namespace ACG
1162//=============================================================================
static void disableClientState(GLenum _cap)
replaces glDisableClientState, supports locking
Definition: GLState.cc:1584
Vec3d eye() const
get eye point
Definition: GLState.cc:886
static void vertexPointer(GLint _size, GLenum _type, GLsizei _stride, const GLvoid *_pointer)
replaces glVertexPointer, supports locking
Definition: GLState.cc:1961
static void enable(GLenum _cap, bool _warnRemoved=true)
replaces glEnable, but supports locking
Definition: GLState.cc:1507
const GLMatrixd & modelview() const
get modelview matrix
Definition: GLState.hh:816
static void enableClientState(GLenum _cap)
replaces glEnableClientState, supports locking
Definition: GLState.cc:1570
int viewport_width() const
get viewport width
Definition: GLState.hh:847
void pick_set_name(size_t _idx)
sets the current name/color (like glLoadName(_idx))
Definition: GLState.cc:1061
Vec3d viewing_direction() const
get viewing ray
Definition: GLState.hh:873
bool pick_set_maximum(size_t _idx)
Set the maximal number of primitives/components of your object.
Definition: GLState.cc:1051
const GLMatrixd & projection() const
get projection matrix
Definition: GLState.hh:811
void set_color(const Vec4f &_col)
set color
Definition: GLState.cc:691
static void disable(GLenum _cap, bool _warnRemoved=true)
replaces glDisable, but supports locking
Definition: GLState.cc:1527
void set_line_width(float _f)
set line width
Definition: GLState.cc:791
const Vec4f & ambient_color() const
get ambient color
Definition: GLState.hh:956
void set_point_size(float _f)
set point size
Definition: GLState.cc:776
double fovy() const
get field of view in y direction
Definition: GLState.cc:868
size_t pick_current_index() const
Returns the current color picking index (can be used for caching)
Definition: GLState.cc:1131
int viewport_height() const
get viewport height
Definition: GLState.hh:849
float line_width() const
get line width
Definition: GLState.hh:1000
const Vec4f & diffuse_color() const
get diffuse color
Definition: GLState.hh:961
static void bindBuffer(GLenum _target, GLuint _buffer)
replaces glBindBuffer, supports locking
Definition: GLState.cc:1820
float point_size() const
get point size
Definition: GLState.hh:995
virtual void addRenderObject(RenderObject *_renderObject)
Callback for the scenegraph nodes, which send new render objects via this function.
Definition: IRenderer.cc:104
DrawModes::DrawMode drawMode() const
Return the own draw modes of this node.
Definition: BaseNode.hh:430
DrawModeProperties stores a set of properties that defines, how to render an object.
Definition: DrawModes.hh:177
bool colored() const
Are colors used?
Definition: DrawModes.hh:222
const DrawModeProperties * getLayer(unsigned int _i) const
returns the property set at layer i
Definition: DrawModes.cc:525
size_t getNumLayers() const
returns the layer count
Definition: DrawModes.cc:521
void baseColor(const Vec4f &_c)
set the base color (Sets the baseColor which is the same as the emission(const Vec4f& _c) )
void pointSize(float _sz)
set point size (default: 1.0)
void getRenderObjects(ACG::IRenderer *_renderer, ACG::GLState &_state, const ACG::SceneGraph::DrawModes::DrawMode &_drawMode, const ACG::SceneGraph::Material *_mat) override
Add the objects to the given renderer.
DrawModes::DrawMode POINTS_SPHERES
This defines a local point spheres draw mode for all polyLine nodes.
void updateVBO()
Trigger an update of the vbo.
void writeVertexColor(unsigned int _vertex, bool _colorSourceVertex, void *_dst) const
Write color for rendering to a buffer.
void boundingBox(Vec3d &_bbMin, Vec3d &_bbMax) override
update bounding box
void setCustomBuffer(int _id, const void *_buffer)
void setupVertexDeclaration(VertexDeclaration *_dst, int _colorSource) const
Create the vertex declaration.
int addCustomBuffer(const ACG::VertexElement &_desc, const void *_buffer)
void draw(GLState &, const DrawModes::DrawMode &_drawMode) override
draw lines and normals
PolyLineNodeT(PolyLine &_pl, BaseNode *_parent=0, std::string _name="<PolyLineNode>")
Constructor.
size_t fillVertexBuffer(void *_buf, size_t _bufSize, bool _addLineStripEndVertex)
Fill a buffer with vertex data.
void writeVertex(unsigned int _vertex, void *_dst)
Write vertex data for rendering to a buffer.
DrawModes::DrawMode availableDrawModes() const override
return available draw modes
DrawModes::DrawMode POINTS_SPHERES_SCREEN
This defines a local point spheres draw mode for all polyLine nodes with constant screen size.
void pick(GLState &_state, PickTarget _target) override
picking
static ShaderCache * getInstance()
Return instance of the ShaderCache singleton.
Definition: ShaderCache.cc:84
GLSL::Program * getProgram(const ShaderGenDesc *_desc, const std::vector< unsigned int > &_mods)
Query a dynamically generated program from cache.
Definition: ShaderCache.cc:102
Class to define the vertex input layout.
void addElement(const VertexElement *_pElement)
static size_t getGLTypeSize(unsigned int _type)
void setVertexStride(unsigned int _stride)
static size_t getElementSize(const VertexElement *_pElement)
const VertexElement * findElementByUsage(VERTEX_USAGE _usage) const
GLSL program class.
Definition: GLSLShader.hh:211
bool isLinked()
Returns if the program object has been succesfully linked.
Definition: GLSLShader.cc:370
void disable()
Resets to standard rendering pipeline.
Definition: GLSLShader.cc:355
void use()
Enables the program object for using.
Definition: GLSLShader.cc:345
void setUniform(const char *_name, GLint _value)
Set int uniform to specified value.
Definition: GLSLShader.cc:385
vector_type & maximize(const vector_type &_rhs)
maximize values: same as *this = max(*this, _rhs), but faster
Definition: Vector11T.hh:588
vector_type & minimize(const vector_type &_rhs)
minimize values: same as *this = min(*this, _rhs), but faster
Definition: Vector11T.hh:560
DrawMode POINTS_COLORED
draw colored, but not lighted points (requires point colors)
Definition: DrawModes.cc:74
DrawMode WIREFRAME
draw wireframe
Definition: DrawModes.cc:78
DrawMode POINTS
draw unlighted points using the default base color
Definition: DrawModes.cc:73
DrawMode EDGES_COLORED
draw edges with colors (without shading)
Definition: DrawModes.cc:77
const DrawMode & addDrawMode(const std::string &_name, bool _propertyBased)
Add a custom DrawMode.
Definition: DrawModes.cc:755
PickTarget
What target to use for picking.
Definition: PickTarget.hh:74
@ PICK_EDGE
picks edges (may not be implemented for all nodes)
Definition: PickTarget.hh:80
@ PICK_ANYTHING
pick any of the prior targets (should be implemented for all nodes)
Definition: PickTarget.hh:84
@ PICK_VERTEX
picks verices (may not be implemented for all nodes)
Definition: PickTarget.hh:82
Namespace providing different geometric functions concerning angles.
VectorT< float, 4 > Vec4f
Definition: VectorT.hh:138
bool ACGDLLEXPORT openGLVersionTest(const int _major, const int _minor)
Definition: gl.hh:275
@ VERTEX_USAGE_NORMAL
"inNormal"
@ VERTEX_USAGE_COLOR
"inColor"
@ VERTEX_USAGE_POSITION
"inPosition"
@ VERTEX_USAGE_SHADER_INPUT
defined by user via VertexElement::shaderInputName_
void compatibilityProfile(bool _enableCoreProfile)
Store opengl core profile setting.
Definition: gl.cc:166
VectorT< double, 3 > Vec3d
Definition: VectorT.hh:121
Interface class between scenegraph and renderer.
Definition: RenderObject.hh:99
ShaderGenDesc shaderDesc
Drawmode and other shader params.
void setupLineRendering(float _lineWidth, const Vec2f &_screenSize)
Setup rendering of thick lines.
const VertexDeclaration * vertexDecl
Defines the vertex buffer layout, ignored if VAO is provided.
void setupShaderGenFromDrawmode(const SceneGraph::DrawModes::DrawModeProperties *_props)
Fills out ShaderGenDesc parameters based on Drawmode properties.
int priority
Priority to allow sorting of objects.
GLuint vertexBuffer
VBO, IBO ids, ignored if VAO is provided.
void initFromState(GLState *_glState)
Initializes a RenderObject instance.
Definition: RenderObject.cc:61
void setupPointRendering(float _pointSize, const Vec2f &_screenSize)
Setup rendering of circle points.
Description of one vertex element.
void setByteOffset(unsigned int _offset)
unsigned int numElements_
how many elements of type_
const void * pointer_
Offset in bytes to the first occurrence of this element in vertex buffer; Or address to vertex data i...
VERTEX_USAGE usage_
position, normal, shader input ..
unsigned int getByteOffset() const
unsigned int type_
GL_FLOAT, GL_UNSIGNED_BYTE, GL_INT, ...
const char * shaderInputName_
set shader input name, if usage_ = VERTEX_USAGE_USER_DEFINED otherwise this is set automatically,...