Developer Documentation

DrawMeshT_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 #define ACG_DRAW_MESH_TCC
45
46 //=============================================================================
47
48 #include "DrawMesh.hh"
49
50 #include <ACG/GL/gl.hh>
51 #include <ACG/Geometry/GPUCacheOptimizer.hh>
52 #include <ACG/GL/VertexDeclaration.hh>
53 #include <ACG/GL/ShaderCache.hh>
54 #include <cassert>
55 #include <cmath>
56 #include <vector>
57 #include <map>
58 #include <cstring>
59 #include <fstream>
60
61 #ifdef USE_OPENMP
62 #include <omp.h>
63 #endif
64
65 //=============================================================================
66
67 // print a memory usage report each draw call
68 //#define DEBUG_MEM_USAGE
69
70
71 namespace ACG
72 {
73
74 template <class Mesh>
75 DrawMeshT<Mesh>::DrawMeshT(Mesh& _mesh)
76 : mesh_(_mesh),
77 rebuild_(REBUILD_NONE),
78 prevNumFaces_(0), prevNumVerts_(0),
79 colorMode_(1),
80 curVBOColorMode_(1),
81 flatMode_(0), bVBOinFlatMode_(0),
82 textureMode_(1), bVBOinHalfedgeTexMode_(1),
83 halfedgeNormalMode_(0), bVBOinHalfedgeNormalMode_(0),
84 invVertexMap_(0),
85 offsetPos_(0), offsetNormal_(20), offsetTexc_(12), offsetColor_(32),
86 textureIndexPropertyName_("Not Set"),
87 perFaceTextureCoordinatePropertyName_("h:texcoords2D"),
88 updateFullVBO_(true),
89 updatePerEdgeBuffers_(1),
90 updatePerHalfedgeBuffers_(1)
91 {
92
93 //today (4.5.2018) the picking shader which uses a textureBuffer, also uses gl_PrimitiveID
94 // since it is only supported since glslversion 150 we can just check for openGLVersion 3.2
95 pickVertexMethod_ = openGLVersionTest(3,2) ? 1 : 0;
96 pickVertexShader_ = 0;
97
98 pickFaceShader_ = 0;
99 pickEdgeShader_ = 0;
100
101 createVertexDeclaration();
102 }
103
104 template<class Mesh>
105 template<class T>
106 const void* DrawMeshT<Mesh>::testMeshPropertyTypeT( const OpenMesh::BaseProperty* _prop, unsigned int* _outSize ) const
107 {
108 if (_outSize)
109 *_outSize = 0;
110 const void* dataPtr = 0;
111
112 // rtti - detect type of property from openmesh via dynamic_cast
113 typedef OpenMesh::PropertyT< T > Prop1;
114 typedef OpenMesh::PropertyT< OpenMesh::VectorT<T, 1> > PropVec1;
115 typedef OpenMesh::PropertyT< OpenMesh::VectorT<T, 2> > PropVec2;
116 typedef OpenMesh::PropertyT< OpenMesh::VectorT<T, 3> > PropVec3;
117 typedef OpenMesh::PropertyT< OpenMesh::VectorT<T, 4> > PropVec4;
118
119 const Prop1* p1 = dynamic_cast<const Prop1*>(_prop);
120 const PropVec1* pv1 = dynamic_cast<const PropVec1*>(_prop);
121 const PropVec2* pv2 = dynamic_cast<const PropVec2*>(_prop);
122 const PropVec3* pv3 = dynamic_cast<const PropVec3*>(_prop);
123 const PropVec4* pv4 = dynamic_cast<const PropVec4*>(_prop);
124
125 if (p1 || pv1)
126 {
127 if (_outSize)
128 *_outSize = 1;
129 if (p1)
130 dataPtr = p1->data();
131 else
132 dataPtr = pv1->data();
133 }
134 else if (pv2)
135 {
136 if (_outSize)
137 *_outSize = 2;
138 dataPtr = pv2->data();
139 }
140 else if (pv3)
141 {
142 if (_outSize)
143 *_outSize = 3;
144 dataPtr = pv3->data();
145 }
146 else if (pv4)
147 {
148 if (_outSize)
149 *_outSize = 4;
150 dataPtr = pv4->data();
151 }
152
153 return dataPtr;
154 }
155
156
157 template<class Mesh>
158 const void* DrawMeshT<Mesh>::getMeshPropertyType( OpenMesh::BaseProperty* _prop, GLuint* _outType, unsigned int* _outSize ) const
159 {
160 const void* dataPtr = 0;
161
162 // try float
163 dataPtr = testMeshPropertyTypeT<float>(_prop, _outSize);
164 if (dataPtr)
165 {
166 if (_outType) *_outType = GL_FLOAT;
167 return dataPtr;
168 }
169
170 // try byte
171 dataPtr = testMeshPropertyTypeT<char>(_prop, _outSize);
172 if (dataPtr)
173 {
174 if (_outType) *_outType = GL_BYTE;
175 return dataPtr;
176 }
177
178 // try ubyte
179 dataPtr = testMeshPropertyTypeT<unsigned char>(_prop, _outSize);
180 if (dataPtr)
181 {
182 if (_outType) *_outType = GL_UNSIGNED_BYTE;
183 return dataPtr;
184 }
185
186 // try double
187 dataPtr = testMeshPropertyTypeT<double>(_prop, _outSize);
188
189 if (dataPtr)
190 {
191 if (_outType) *_outType = GL_DOUBLE;
192 return dataPtr;
193 }
194
195 // try int
196 dataPtr = testMeshPropertyTypeT<int>(_prop, _outSize);
197
198 if (dataPtr)
199 {
200 if (_outType) *_outType = GL_INT;
201 return dataPtr;
202 }
203
204 // try uint
205 dataPtr = testMeshPropertyTypeT<unsigned int>(_prop, _outSize);
206
207 if (dataPtr)
208 {
209 if (_outType) *_outType = GL_UNSIGNED_INT;
210 return dataPtr;
211 }
212
213 // try short
214 dataPtr = testMeshPropertyTypeT<short>(_prop, _outSize);
215
216 if (dataPtr)
217 {
218 if (_outType) *_outType = GL_SHORT;
219 return dataPtr;
220 }
221
222 // try ushort
223 dataPtr = testMeshPropertyTypeT<unsigned short>(_prop, _outSize);
224
225 if (dataPtr)
226 {
227 if (_outType) *_outType = GL_UNSIGNED_SHORT;
228 return dataPtr;
229 }
230
231
232 // unknown data type
233 if (_outSize)
234 *_outSize = 0;
235
236 if (_outType)
237 *_outType = 0;
238
239 return 0;
240 }
241
242
243
244 template<class Mesh>
245 class DrawMeshFaceInput : public MeshCompilerFaceInput
246 {
247
248 public:
249
250 explicit DrawMeshFaceInput(Mesh& _mesh) :
251 mesh_(_mesh)
252 {
253 };
254
255 // map[attrID] -> use per halfedge/vertex attribute (true/false)
256 std::vector<int> attributeStoredPerHalfedge_;
257
258
259 int getNumFaces() const { return mesh_.n_faces(); }
260
261 // compute number of indices later automatically
262 int getNumIndices() const { return 0; };
263
267 int getFaceSize(const int _faceID) const
268 {
269 return mesh_.valence( mesh_.face_handle(_faceID) );
270 }
271
279 int getSingleFaceAttr(const int _faceID, const int _faceCorner, const int _attrID) const
280 {
281 const typename Mesh::FaceHandle fh = mesh_.face_handle(_faceID);
282
283 typename Mesh::ConstFaceHalfedgeIter fh_it = mesh_.cfh_iter(fh);
284
285 // ========================================================================================
286 // Optimization for triangular meshes (use previous halfedge to skip part of the iteration)
287 // ========================================================================================
288 if ( mesh_.is_trimesh()) {
289 if ( attributeStoredPerHalfedge_[_attrID] != 0 ) {
290 switch (_faceCorner) {
291 case 0 : return fh_it->idx();
292 break;
293 case 1 : return (mesh_.next_halfedge_handle(*fh_it)).idx();
294 break;
295 case 2 : return (mesh_.prev_halfedge_handle(*fh_it)).idx();
296 break;
297 default : std::cerr << " Index error!" << _faceCorner << std::endl; return -1;
298 break;
299 }
300 } else {
301 switch (_faceCorner) {
302 case 0 : return mesh_.to_vertex_handle(*fh_it).idx();
303 break;
304 case 1 : return (mesh_.to_vertex_handle(mesh_.next_halfedge_handle(*fh_it))).idx();
305 break;
306 case 2 : return (mesh_.to_vertex_handle(mesh_.prev_halfedge_handle(*fh_it))).idx();
307 break;
308 default : std::cerr << " Index error!" << _faceCorner << std::endl; return -1;
309 break;
310 }
311 }
312 }
313
314 // ========================================================================================
315 // Poly Meshes
316 // ========================================================================================
317 if ( attributeStoredPerHalfedge_[_attrID] != 0 ) {
318
319 for (int i = 0; fh_it.is_valid() && i <= _faceCorner; ++fh_it, ++i )
320 if (i == _faceCorner)
321 return fh_it->idx();
322
323 } else {
324
325 for (int i = 0; fh_it.is_valid() && i <= _faceCorner; ++fh_it, ++i )
326 if (i == _faceCorner)
327 return mesh_.to_vertex_handle(*fh_it).idx();
328
329 }
330
331 // Not found -> return -1 as error
332 return -1;
333 }
334
341 bool getFaceAttr(const int _faceID, const int _attrID, int* _out) const
342 {
343 const typename Mesh::FaceHandle fh = mesh_.face_handle(_faceID);
344
345 const bool usePerHalfedge = (attributeStoredPerHalfedge_[_attrID] != 0);
346
347 // read all vertex indices of this face
348 typename Mesh::ConstFaceHalfedgeIter hh_it = mesh_.cfh_iter(fh);
349 for (int i = 0; hh_it.is_valid(); ++hh_it, ++i )
350 {
351 _out[i] = usePerHalfedge ? hh_it->idx() : mesh_.to_vertex_handle(*hh_it).idx();
352 }
353
354 return true;
355 }
356
362 int* getFaceAttr(const int _faceID, const int _attrID) const
363 {
364 // cannot be implemented with OpenMesh data structure
365 return 0;
366 }
367
368
369
370 int getVertexAdjCount(const int _vertexID) const
371 {
372 const typename Mesh::VertexHandle vh = mesh_.vertex_handle(_vertexID);
373
374 int counter = 0;
375
376 // read all vertex indices of this face
377 typename Mesh::ConstVertexFaceIter adj_it = mesh_.cvf_iter(vh);
378 for (;adj_it.is_valid(); ++adj_it)
379 ++counter;
380
381 return counter;
382 }
383
384 int getVertexAdjFace(const int _vertexID, const int _k) const
385 {
386 const typename Mesh::VertexHandle vh = mesh_.vertex_handle(_vertexID);
387
388 // read all vertex indices of this face
389 typename Mesh::ConstVertexFaceIter adj_it = mesh_.cvf_iter(vh);
390 for (int i = 0; adj_it.is_valid() && i < _k; ++adj_it, ++i);
391
392 return adj_it->idx();
393 }
394
395 private:
396 Mesh& mesh_;
397 };
398
399
400
401 template <class Mesh>
402 void
403 DrawMeshT<Mesh>::rebuild()
404 {
405 if (rebuild_ == REBUILD_NONE) return;
406
407 if (!mesh_.n_vertices())
408 {
409 numVerts_ = 0;
410 numTris_ = 0;
411 return;
412 }
413
414
415
416 // --------------------------------------------
417 // debug - request properties
418 /*
419 if (additionalElements_.empty() && (mesh_._get_hprop("inTangent") || mesh_._get_vprop("inTangent")))
420 {
421 // VertexProperty tmp;
422 // tmp.name_ = "inTangent";
423 // tmp.source_ = 0;
424 //
425 // additionalElements_.push_back(tmp);
426
427 // scanVertexShaderForInput( "c:/dbg/nm_VS.tpl" );
428 scanVertexShaderForInput( "/home/tenter/dbg/nm_VS.tpl" );
429 }
430 */
431 // --------------------------------------------
432
433 // todo: check if vertex layout has been changed and eventually force a full rebuild
434
435
436 // update layout declaration
437 createVertexDeclaration();
438
439 // support for point clouds:
440 if (mesh_.n_vertices() && mesh_.n_faces() == 0)
441 {
442 if (mesh_.n_vertices() > numVerts_)
443 {
444 delete [] invVertexMap_;
445 invVertexMap_ = 0;
446 }
447 numVerts_ = mesh_.n_vertices();
448 vertices_.resize(numVerts_ * vertexDecl_->getVertexStride());
449
450 // read all vertices
451 for (size_t i = 0; i < numVerts_; ++i)
452 readVertex(i,
453 mesh_.vertex_handle(static_cast<unsigned int>(i)),
454 (typename Mesh::HalfedgeHandle)(-1),
455 (typename Mesh::FaceHandle)(-1));
456
457 createVBO();
458 rebuild_ = REBUILD_NONE;
459 return;
460 }
461
462 invalidateFullVBO();
463
464
465 unsigned int maxFaceVertCount = 0;
466 unsigned int numIndices = 0;
467 unsigned int newTriCount = countTris(&maxFaceVertCount, &numIndices);
468
469 int bTriangleRebuild = 0; // what should be rebuild?
470 int bVertexRebuild = 0;
471
472 if (newTriCount > numTris_)
473 {
474 // index buffer too small
475 deleteIbo();
476
477 numTris_ = newTriCount;
478
479 bTriangleRebuild = 1;
480 }
481
482 if (prevNumFaces_ != mesh_.n_faces())
483 {
484 bTriangleRebuild = 1;
485 prevNumFaces_ = mesh_.n_faces();
486 }
487
488 if (prevNumVerts_ != mesh_.n_vertices())
489 {
490 if (prevNumVerts_ < mesh_.n_vertices())
491 {
492 // resize inverse vertex map
493 delete [] invVertexMap_;
494 invVertexMap_ = new unsigned int[mesh_.n_vertices()];
495 }
496
497 bVertexRebuild = 1;
498 bTriangleRebuild = 1; // this may have caused changes in the topology!
499 prevNumVerts_ = mesh_.n_vertices();
500 }
501
502 // support faster update by only updating vertices (do a complete update if the textures have to be rebuild)
503 if (!bTriangleRebuild && !bVertexRebuild && (rebuild_ & REBUILD_GEOMETRY) && !(rebuild_ & REBUILD_TEXTURES))
504 {
505 // only update vertices, i.e. update values of vertices
506
507 #ifndef WIN32
508 #ifdef USE_OPENMP
509 #pragma omp parallel for
510 #endif
511 #endif
512 for (size_t i = 0; i < numVerts_; ++i)
513 {
514 // just pick one face, srews up face colors here so color updates need a full rebuild
515 const typename Mesh::HalfedgeHandle hh = mapToHalfedgeHandle(i);
516 typename Mesh::VertexHandle vh(-1);
517 typename Mesh::FaceHandle fh(-1);
518
519 if (hh.is_valid())
520 {
521 vh = mesh_.to_vertex_handle(hh);
522 fh = mesh_.face_handle(hh);
523 }
524 else
525 {
526 int f_id, c_id;
527 int posID = meshComp_->mapToOriginalVertexID(i, f_id, c_id);
528 vh = mesh_.vertex_handle(posID);
529 }
530
531 readVertex(i, vh, hh, fh);
532 }
533
534 createVBO();
535
536 rebuild_ = REBUILD_NONE;
537 return;
538 }
539
540
541 // full rebuild:
542 delete meshComp_;
543 meshComp_ = new MeshCompiler(*vertexDecl_);
544
545
546 // search for convenient attribute indices
547 int attrIDNorm = -1, attrIDPos = -1, attrIDTexC = -1;
548
549 for (int i = 0; i < (int)meshComp_->getVertexDeclaration()->getNumElements(); ++i)
550 {
551 const VertexElement* e = meshComp_->getVertexDeclaration()->getElement(i);
552
553 switch (e->usage_)
554 {
555 case VERTEX_USAGE_POSITION: attrIDPos = i; break;
556 case VERTEX_USAGE_NORMAL: attrIDNorm = i; break;
557 case VERTEX_USAGE_TEXCOORD: attrIDTexC = i; break;
558 default: break;
559 }
560 }
561
562
563 // pass face data to mesh compiler
564 DrawMeshFaceInput<Mesh>* faceInput = new DrawMeshFaceInput<Mesh>(mesh_);
565 faceInput->attributeStoredPerHalfedge_.resize(meshComp_->getVertexDeclaration()->getNumElements(), 0);
566 faceInput->attributeStoredPerHalfedge_[attrIDPos] = 0;
567 faceInput->attributeStoredPerHalfedge_[attrIDNorm] = ( (halfedgeNormalMode_ && mesh_.has_halfedge_normals()) ? 1 : 0 );
568 faceInput->attributeStoredPerHalfedge_[attrIDTexC] = ( mesh_.has_halfedge_texcoords2D() ? 1 : 0);
569
570 // index source for custom attributes
571 for (size_t i = 0; i < additionalElements_.size(); ++i)
572 {
573 const VertexProperty* prop = &additionalElements_[i];
574
575 if (prop->declElementID_ >= 0)
576 faceInput->attributeStoredPerHalfedge_[prop->declElementID_] = (prop->source_ == PROPERTY_SOURCE_HALFEDGE) ? 1 : 0;
577 }
578
579 meshComp_->setFaceInput(faceInput);
580
581 // set textures
582 for (unsigned int i = 0; i < mesh_.n_faces(); ++i)
583 meshComp_->setFaceGroup(i, getTextureIDofFace(i));
584
585 // pass vertex data to mesh compiler
586
587
588 // points
589 meshComp_->setVertices(mesh_.n_vertices(), mesh_.points(), 24, false, GL_DOUBLE, 3);
590
591 // normals
592 if (halfedgeNormalMode_ && mesh_.has_halfedge_normals())
593 meshComp_->setNormals(mesh_.n_halfedges(), mesh_.property(mesh_.halfedge_normals_pph()).data(), 24, false, GL_DOUBLE, 3);
594 else if (mesh_.has_vertex_normals())
595 meshComp_->setNormals(mesh_.n_vertices(), mesh_.vertex_normals(), 24, false, GL_DOUBLE, 3);
596
597 if (mesh_.has_halfedge_texcoords2D())
598 meshComp_->setTexCoords(mesh_.n_halfedges(), mesh_.htexcoords2D(), 8, false, GL_FLOAT, 2);
599
600 // add more requested custom attribtues to mesh compiler here..
601
602 for (size_t i = 0; i < additionalElements_.size(); ++i)
603 {
604 VertexProperty* propDesc = &additionalElements_[i];
605
606 if (propDesc->declElementID_ >= 0)
607 {
608 const VertexElement* el = vertexDecl_->getElement((unsigned int)propDesc->declElementID_);
609
610 if (el->usage_ == VERTEX_USAGE_SHADER_INPUT)
611 {
612 // get openmesh property handle
613 OpenMesh::BaseProperty* baseProp = 0;
614
615 switch (propDesc->source_)
616 {
617 case PROPERTY_SOURCE_VERTEX: baseProp = mesh_._get_vprop(propDesc->name_); break;
618 case PROPERTY_SOURCE_FACE: baseProp = mesh_._get_fprop(propDesc->name_); break;
619 case PROPERTY_SOURCE_HALFEDGE: baseProp = mesh_._get_hprop(propDesc->name_); break;
620 default: baseProp = mesh_._get_vprop(propDesc->name_); break;
621 }
622
623 if (baseProp)
624 {
625 size_t numAttribs = baseProp->n_elements();
626 const void* attribData = propDesc->propDataPtr_;
627
628 meshComp_->setAttribVec( propDesc->declElementID_, numAttribs, attribData );
629 }
630
631
632 }
633 }
634
635
636 }
637
638
639 // compile draw buffers
640 meshComp_->build(true, true, true, true);
641
642
643 // create inverse vertex map
644 for (int i = 0; i < (int)mesh_.n_faces(); ++i)
645 {
646 typename Mesh::FaceHandle fh = mesh_.face_handle(i);
647
648 int corner = 0;
649
650 for (typename Mesh::FaceHalfedgeIter hh_it = mesh_.fh_iter(fh); hh_it.is_valid(); ++hh_it )
651 {
652 int vertexId = mesh_.to_vertex_handle(*hh_it).idx();
653 invVertexMap_[vertexId] = meshComp_->mapToDrawVertexID(i, corner++);
654 }
655 }
656
657
658 // get vertex buffer
659 numTris_ = meshComp_->getNumTriangles();
660 numVerts_ = meshComp_->getNumVertices();
661
662 vertices_.resize(numVerts_ * vertexDecl_->getVertexStride());
663 meshComp_->getVertexBuffer(&vertices_[0]);
664
665 // copy colors
666 for (int i = 0; i < (int)numVerts_; ++i)
667 {
668 typename Mesh::HalfedgeHandle hh = mapToHalfedgeHandle(i);
669
670 unsigned int col = 0;
671
672 if (hh.is_valid())
673 col = getVertexColor(mesh_.to_vertex_handle(hh));
674 else
675 {
676 // isolated vertex
677 int f_id, c_id;
678 int posID = meshComp_->mapToOriginalVertexID(i, f_id, c_id);
679 col = getVertexColor( mesh_.vertex_handle(posID) );
680 }
681
682 writeColor(i, col);
683 }
684
685 // vbo stores per vertex colors
686 curVBOColorMode_ = 1;
687
688 // copy face colors to provoking id
689 if (colorMode_ == 2)
690 {
691 const int provokingId = meshComp_->getProvokingVertex();
692 assert(provokingId >= 0 && provokingId < 3);
693
694 for (int i = 0; i < (int)numTris_; ++i)
695 {
696 int idx = meshComp_->getIndex(i*3+provokingId);
697
698 int faceId = meshComp_->mapToOriginalFaceID(i);
699 unsigned int fcolor = getFaceColor(mesh_.face_handle(faceId));
700
701 writeColor(idx, fcolor);
702 }
703
704 #ifdef _DEBUG
705 // debug check
706
707 for (int i = 0; i < (int)numTris_; ++i)
708 {
709 int idx = meshComp_->getIndex(i*3+provokingId);
710
711 int faceId = meshComp_->mapToOriginalFaceID(i);
712 unsigned int fcolor = getFaceColor(mesh_.face_handle(faceId));
713
714 unsigned int storedColor = *(unsigned int*)(&vertices_[idx * vertexDecl_->getVertexStride() + offsetColor_]);
715
716 if (storedColor != fcolor)
717 {
718 std::cout << "warning: possibly found provoking vertex shared by more than one face, writing report to ../../meshcomp_provoking.txt" << std::endl;
719
720 // could also be caused by multi-threading, where one thread calls rebuild()
721 // and the other thread updates face colors between previous for-loop and debug-check
722
723 // check for errors
724 meshComp_->dbgVerify("../../meshcomp_provoking.txt");
725
726 break; // verify and dump report only once
727 }
728 }
729 #endif // _DEBUG
730
731 curVBOColorMode_ = colorMode_;
732 }
733
734
735
736
738 // copy to GPU
739
740 createVBO();
741 createIBO();
742
743 bVBOinHalfedgeNormalMode_ = halfedgeNormalMode_;
744
745 rebuild_ = REBUILD_NONE;
746 }
747
748
749 template <class Mesh>
750 void
751 DrawMeshT<Mesh>::readVertex(size_t _vertex,
752 const typename Mesh::VertexHandle& _vh,
753 const typename Mesh::HalfedgeHandle& _hh,
754 const typename Mesh::FaceHandle& _fh)
755 {
756 static const typename Mesh::HalfedgeHandle invalidHEH(-1);
757 static const typename Mesh::FaceHandle invalidFH(-1);
758
759
760 ACG::Vec3d n(0.0, 0.0, 1.0);
761 ACG::Vec2f texc(0.0f, 0.0f);
762 unsigned int col(0);
763
764 // read normal
765 if (halfedgeNormalMode_ == 0 && mesh_.has_vertex_normals())
766 n = mesh_.normal(_vh);
767 else if (halfedgeNormalMode_ && mesh_.has_halfedge_normals() && _hh != invalidHEH)
768 n = mesh_.normal(_hh);
769
770 // read texcoord
771 if (mesh_.has_halfedge_texcoords2D())
772 {
773 if (_hh != invalidHEH && textureMode_ == 1)
774 texc = mesh_.texcoord2D(_hh);
775 else if (mesh_.has_vertex_texcoords2D())
776 texc = mesh_.texcoord2D(_vh);
777 }
778 else if (mesh_.has_vertex_texcoords2D())
779 texc = mesh_.texcoord2D(_vh);
780
781 // read per face or per vertex color
782 unsigned int byteCol[2];
783 for (int col = 0; col < 2; ++col)
784 {
785 Vec4uc vecCol(255, 255, 255, 255);
786
787 if (col == 0 && mesh_.has_vertex_colors())
788 vecCol = OpenMesh::color_cast<Vec4uc, typename Mesh::Color>(mesh_.color(_vh));
789 if (_fh != invalidFH)
790 {
791 if (col == 1 && mesh_.has_face_colors() && _fh.idx() >= 0)
792 vecCol = OpenMesh::color_cast<Vec4uc,typename Mesh::Color>(mesh_.color(_fh));
793 }
794
795 // OpenGL color format: A8B8G8R8
796 byteCol[col] = (unsigned char)(vecCol[0]);
797 byteCol[col] |= ((unsigned char)(vecCol[1])) << 8;
798 byteCol[col] |= ((unsigned char)(vecCol[2])) << 16;
799 byteCol[col] |= ((unsigned char)(vecCol[3])) << 24;
800 //byteCol[col] |= 0xFF << 24; // if no alpha channel
801 }
802
803 if (colorMode_ != 2)
804 col = byteCol[0]; // vertex colors
805 else
806 col = byteCol[1]; // face colors
807
808
809 // store vertex attributes in vbo
810 writePosition(_vertex, mesh_.point(_vh));
811 writeNormal(_vertex, n);
812 writeTexcoord(_vertex, texc);
813 writeColor(_vertex, col);
814
815
816 // read/write custom attributes
817
818 for (size_t i = 0; i < additionalElements_.size(); ++i)
819 {
820 std::cout << "not implemented!" << std::endl;
821
822
823 }
824
825
826 }
827
828 template <class Mesh>
829 unsigned int
830 DrawMeshT<Mesh>::getVertexColor(const typename Mesh::VertexHandle& _vh)
831 {
832 static const typename Mesh::VertexHandle invalidVH(-1);
833
834 unsigned int byteCol;
835
836 Vec4uc vecCol(255, 255, 255, 255);
837
838 if ( _vh != invalidVH && mesh_.has_vertex_colors() )
839 vecCol = OpenMesh::color_cast<Vec4uc, typename Mesh::Color>(mesh_.color(_vh));
840
841 // OpenGL color format: A8B8G8R8
842 byteCol = (unsigned char)(vecCol[0]);
843 byteCol |= ((unsigned char)(vecCol[1])) << 8;
844 byteCol |= ((unsigned char)(vecCol[2])) << 16;
845 byteCol |= ((unsigned char)(vecCol[3])) << 24;
846
847 return byteCol;
848 }
849
850 template <class Mesh>
851 unsigned int
852 DrawMeshT<Mesh>::getFaceColor(const typename Mesh::FaceHandle& _fh)
853 {
854 static const typename Mesh::FaceHandle invalidFH(-1);
855
856 unsigned int byteCol;
857 Vec4uc vecCol(255, 255, 255, 255);
858
859 if ( _fh != invalidFH && mesh_.has_face_colors() && _fh.idx() >= 0 )
860 vecCol = OpenMesh::color_cast<Vec4uc,typename Mesh::Color>(mesh_.color(_fh));
861
862 // OpenGL color format: A8B8G8R8
863 byteCol = (unsigned char)(vecCol[0]);
864 byteCol |= ((unsigned char)(vecCol[1])) << 8;
865 byteCol |= ((unsigned char)(vecCol[2])) << 16;
866 byteCol |= ((unsigned char)(vecCol[3])) << 24;
867
868 return byteCol;
869 }
870
871
872 template <class Mesh>
873 int
874 DrawMeshT<Mesh>::getTextureIDofFace(unsigned int _face)
875 {
876 OpenMesh::FPropHandleT< int > textureIndexProperty;
877 if (mesh_.get_property_handle(textureIndexProperty, textureIndexPropertyName_))
878 return mesh_.property(textureIndexProperty, mesh_.face_handle(_face));
879
880 if (mesh_.has_face_texture_index())
881 return mesh_.texture_index(mesh_.face_handle(_face));
882
883 return 0;
884 }
885
886 template <class Mesh>
887 int
888 DrawMeshT<Mesh>::getTextureIDofTri(unsigned int _tri)
889 {
890 return getTextureIDofFace(meshComp_->mapToOriginalFaceID(_tri));
891 }
892
893
894 template <class Mesh>
895 void
896 DrawMeshT<Mesh>::createVBO()
897 {
898 bindVbo();
899
900 // toggle between normal source and texcoord source
901 // (per vertex, per halfedge, per face)
902
903 if (flatMode_ && meshComp_)
904 {
905 for (unsigned int i = 0; i < numTris_; ++i)
906 {
907 int faceId = meshComp_->mapToOriginalFaceID(i);
908
909 // get face normal
910 ACG::Vec3d n = mesh_.normal(mesh_.face_handle(faceId));
911
912 // store face normal in last tri vertex
913 // for (unsigned int k = 0; k < 3; ++k)
914 {
915 int idx = meshComp_->getIndex(i*3 + meshComp_->getProvokingVertex());
916 // vertices_[idx].n[k] = n[k];
917 writeNormal(idx, n);
918 }
919
920 }
921 bVBOinFlatMode_ = 1;
922 }
923 else
924 {
925 for (unsigned int i = 0; i < numVerts_; ++i)
926 {
927 typename Mesh::HalfedgeHandle hh = mapToHalfedgeHandle(i);
928
929 // get halfedge normal
930
931 if (hh.is_valid())
932 {
933 ACG::Vec3d n;
934 if (halfedgeNormalMode_ == 1 && mesh_.has_halfedge_normals())
935 n = mesh_.normal( hh );
936 else
937 n = mesh_.normal( mesh_.to_vertex_handle(hh) );
938
939 // for (int k = 0; k < 3; ++k)
940 // vertices_[i].n[k] = n[k];
941 writeNormal(i, n);
942 }
943 else
944 {
945 // isolated vertex
946 int posID = i;
947
948
949 if (meshComp_) {
950 int f_id, c_id;
951 posID = meshComp_->mapToOriginalVertexID(i, f_id, c_id);
952 }
953
954 // for (int k = 0; k < 3; ++k)
955 // vertices_[i].tex[k] = mesh_.normal( mesh_.vertex_handle(posID) )[k];
956 writeNormal(i, mesh_.normal( mesh_.vertex_handle(posID) ));
957 }
958 }
959
960 bVBOinFlatMode_ = 0;
961 }
962
963 if (textureMode_ == 0)
964 {
965 // per vertex texcoords
966 if (mesh_.has_vertex_texcoords2D())
967 {
968 for (unsigned int i = 0; i < numVerts_; ++i)
969 {
970 typename Mesh::HalfedgeHandle hh = mapToHalfedgeHandle(i);
971
972 if (hh.is_valid())
973 {
974 // copy texcoord
975 // for (int k = 0; k < 2; ++k)
976 // vertices_[i].tex[k] = mesh_.texcoord2D( mesh_.to_vertex_handle(hh) )[k];
977
978 writeTexcoord(i, mesh_.texcoord2D( mesh_.to_vertex_handle(hh) ) );
979 }
980 else
981 {
982 // isolated vertex
983 int posID = i;
984
985 if (meshComp_) {
986 int f_id, c_id;
987 posID = meshComp_->mapToOriginalVertexID(i, f_id, c_id);
988 }
989
990 // for (int k = 0; k < 2; ++k)
991 // vertices_[i].tex[k] = mesh_.texcoord2D( mesh_.vertex_handle(posID) )[k];
992
993 writeTexcoord(i, mesh_.texcoord2D( mesh_.vertex_handle(posID) ) );
994
995 }
996 }
997 }
998
999 bVBOinHalfedgeTexMode_ = 0;
1000 }
1001 else
1002 {
1003 if (mesh_.has_vertex_texcoords2D() || mesh_.has_halfedge_texcoords2D())
1004 {
1005 // per halfedge texcoords
1006 for (unsigned int i = 0; i < numVerts_; ++i)
1007 {
1008 typename Mesh::HalfedgeHandle hh = mapToHalfedgeHandle(i);
1009
1010 if (hh.is_valid())
1011 {
1012 // copy texcoord
1013 if (mesh_.has_halfedge_texcoords2D())
1014 {
1015 // for (int k = 0; k < 2; ++k)
1016 // vertices_[i].tex[k] = mesh_.texcoord2D( hh )[k];
1017
1018 writeTexcoord(i, mesh_.texcoord2D( hh ) );
1019 }
1020
1021 }
1022 else if (mesh_.has_vertex_texcoords2D())
1023 {
1024 // isolated vertex
1025 int posID = i;
1026
1027
1028 if (meshComp_) {
1029 int f_id, c_id;
1030 posID = meshComp_->mapToOriginalVertexID(i, f_id, c_id);
1031 }
1032
1033 // for (int k = 0; k < 2; ++k)
1034 // vertices_[i].tex[k] = mesh_.texcoord2D( mesh_.vertex_handle(posID) )[k];
1035
1036 writeTexcoord(i, mesh_.texcoord2D( mesh_.vertex_handle(posID) ) );
1037
1038 }
1039 }
1040 }
1041
1042 bVBOinHalfedgeTexMode_ = 1;
1043 }
1044
1045 if (colorMode_ && colorMode_ != curVBOColorMode_)
1046 {
1047 if (colorMode_ == 1)
1048 {
1049 // use vertex colors
1050
1051 for (int i = 0; i < (int)numVerts_; ++i)
1052 {
1053 typename Mesh::HalfedgeHandle hh = mapToHalfedgeHandle(i);
1054
1055 unsigned int col;
1056
1057 if (hh.is_valid())
1058 col = getVertexColor(mesh_.to_vertex_handle(hh));
1059 else
1060 {
1061 // isolated vertex
1062 int f_id, c_id;
1063 int posID = meshComp_->mapToOriginalVertexID(i, f_id, c_id);
1064 col = getVertexColor( mesh_.vertex_handle(posID) );
1065 }
1066
1067 writeColor(i, col);
1068 }
1069 }
1070 else if (colorMode_ == 2)
1071 {
1072 // use face colors
1073
1074 const int provokingId = meshComp_->getProvokingVertex();
1075 assert(provokingId >= 0 && provokingId < 3);
1076
1077 for (int i = 0; i < (int)numTris_; ++i)
1078 {
1079 int idx = meshComp_->getIndex(i*3+provokingId);
1080
1081 int faceId = meshComp_->mapToOriginalFaceID(i);
1082 unsigned int fcolor = getFaceColor(mesh_.face_handle(faceId));
1083
1084 // vertices_[idx].col = fcolor;
1085 writeColor(idx, fcolor);
1086 }
1087 }
1088
1089 // vbo colors updated
1090 curVBOColorMode_ = colorMode_;
1091 }
1092
1093 fillVertexBuffer();
1094
1095 ACG::GLState::bindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
1096
1097 // non indexed vbo needs updating now
1098 invalidateFullVBO();
1099 }
1100
1101 template <class Mesh>
1102 void
1103 DrawMeshT<Mesh>::createIBO()
1104 {
1105 // data read from indices_
1106
1107 bindIbo();
1108
1109 indexType_ = GL_UNSIGNED_INT;
1110 // if (numVerts_ <= 0xFFFF)
1111 // {
1112 // // use 2 byte indices
1113 // unsigned short* pwIndices = (unsigned short*)indicesTmp_;
1114 // indexType_ = GL_UNSIGNED_SHORT;
1115 //
1116 // for (unsigned int i = 0; i < numTris_ * 3; ++i)
1117 // pwIndices[i] = (unsigned short)indices_[i];
1118 //
1119 // glBufferData(GL_ELEMENT_ARRAY_BUFFER_ARB, numTris_ * 3 * sizeof(unsigned short), pwIndices, GL_STATIC_DRAW_ARB);
1120 // }
1121 // else
1122 createIndexBuffer();
1123
1124
1125 // line index buffer:
1126 if (mesh_.n_edges())
1127 {
1128 std::vector<unsigned int> lineBuffer(mesh_.n_edges() * 2);
1129
1130 for (unsigned int i = 0; i < mesh_.n_edges(); ++i)
1131 {
1132 OpenMesh::HalfedgeHandle hh = mesh_.halfedge_handle(mesh_.edge_handle(i), 0);
1133
1134 if (indexType_ == GL_UNSIGNED_SHORT)
1135 {
1136 // put two words in a dword
1137 unsigned int combinedIdx = invVertexMap_[mesh_.from_vertex_handle(hh).idx()] | (invVertexMap_[mesh_.to_vertex_handle(hh).idx()] << 16);
1138 lineBuffer[i] = combinedIdx;
1139 }
1140 else
1141 {
1142 lineBuffer[2 * i] = invVertexMap_[mesh_.from_vertex_handle(hh).idx()];
1143 lineBuffer[2 * i + 1] = invVertexMap_[mesh_.to_vertex_handle(hh).idx()];
1144 }
1145 }
1146
1147 bindLineIbo();
1148
1149 fillLineBuffer(mesh_.n_edges(), &lineBuffer[0]);
1150 }
1151
1152 ACG::GLState::bindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
1153 }
1154
1155 template <class Mesh>
1156 DrawMeshT<Mesh>::~DrawMeshT(void)
1157 {
1158 delete [] invVertexMap_;
1159 }
1160
1161
1162
1163 template <class Mesh>
1164 unsigned int DrawMeshT<Mesh>::getMemoryUsage(bool _printReport)
1165 {
1166 unsigned int res = 0;
1167 unsigned int sysBufSize = 0;
1168
1169 sysBufSize += meshComp_->getMemoryUsage();
1170
1171 // vertex buffer
1172 if (!vertices_.empty())
1173 sysBufSize += vertexDecl_->getVertexStride() * numVerts_;
1174
1175
1176
1177 res += sysBufSize;
1178
1179 // mappings
1180 unsigned int mapsSize = 0;
1181
1182 if (invVertexMap_)
1183 res += mesh_.n_vertices() * 4;
1184
1185 res += mapsSize;
1186
1187
1188 // picking buffers
1189 unsigned int pickBufSize = 0;
1190
1191 pickBufSize += pickVertBuf_.capacity() * sizeof(ACG::Vec3f);
1192 pickBufSize += pickVertColBuf_.capacity() * sizeof(ACG::Vec4uc);
1193
1194 pickBufSize += pickEdgeBuf_.capacity() * sizeof(ACG::Vec4uc);
1195
1196 pickBufSize += pickFaceVertexBuf_.capacity() * sizeof(ACG::Vec3f);
1197 pickBufSize += pickFaceColBuf_.capacity() * sizeof(ACG::Vec4uc);
1198
1199
1200 pickBufSize += pickAnyFaceColBuf_.capacity() * sizeof(ACG::Vec4uc);
1201 pickBufSize += pickAnyEdgeColBuf_.capacity() * sizeof(ACG::Vec4uc);
1202 pickBufSize += pickAnyVertexColBuf_.capacity() * sizeof(ACG::Vec4uc);
1203
1204 res += pickBufSize;
1205
1206
1207 // edge and halfedge vertex buffers (glDraw from sysmem)
1208 unsigned int edgeBufSize = 0;
1209
1210 edgeBufSize += perEdgeVertexBuf_.capacity() * sizeof(ACG::Vec3f);
1211 edgeBufSize += perEdgeColorBuf_.capacity() * sizeof(ACG::Vec4uc);
1212
1213 edgeBufSize += perHalfedgeVertexBuf_.capacity() * sizeof(ACG::Vec3f);
1214 edgeBufSize += perHalfedgeColorBuf_.capacity() * sizeof(ACG::Vec4uc);
1215
1216
1217 res += edgeBufSize;
1218
1219
1220 unsigned int gpuBufSize = 0;
1221
1222 if (ibo_)
1223 gpuBufSize += numTris_ * 3 * (indexType_ == GL_UNSIGNED_INT ? 4 : 2);
1224
1225 if (vbo_)
1226 gpuBufSize += numVerts_ * vertexDecl_->getVertexStride();
1227
1228 if (_printReport)
1229 {
1230 std::cout << "\nDrawMesh memory usage in MB:\n";
1231 std::cout << "Vertex+IndexBuffer (SYSMEM only): " << float(sysBufSize) / (1024 * 1024);
1232 std::cout << "\nMappings: " << float(mapsSize) / (1024 * 1024);
1233 std::cout << "\nPicking Buffers: " << float(pickBufSize) / (1024 * 1024);
1234 std::cout << "\nEdge Buffers: " << float(edgeBufSize) / (1024 * 1024);
1235 std::cout << "\nTotal SYSMEM: " << float(res) / (1024 * 1024);
1236 std::cout << "\nTotal GPU: " << float(gpuBufSize) / (1024 * 1024) << std::endl;
1237 }
1238
1239 return res;
1240 }
1241
1242
1243 template <class Mesh>
1244 void DrawMeshT<Mesh>::updateGPUBuffers()
1245 {
1246 // rebuild if necessary
1247 if ((!numTris_ && mesh_.n_faces())|| ! numVerts_ || (!meshComp_ && mesh_.n_faces()))
1248 {
1249 rebuild_ = REBUILD_FULL;
1250 }
1251
1252 if (bVBOinHalfedgeNormalMode_ != halfedgeNormalMode_) rebuild_ = REBUILD_FULL;
1253
1254 // if no rebuild necessary, check for smooth / flat shading switch
1255 // to update normals
1256 if (rebuild_ == REBUILD_NONE)
1257 {
1258 if (bVBOinFlatMode_ != flatMode_ || bVBOinHalfedgeTexMode_ != textureMode_ || (colorMode_ && curVBOColorMode_ != colorMode_))
1259 createVBO();
1260 }
1261 else
1262 {
1263 rebuild();
1264 }
1265 }
1266
1267
1268 template <class Mesh>
1269 GLuint DrawMeshT<Mesh>::getVBO()
1270 {
1271 updateGPUBuffers();
1272 return vbo_;
1273 }
1274
1275 template <class Mesh>
1276 GLuint DrawMeshT<Mesh>::getIBO()
1277 {
1278 updateGPUBuffers();
1279 return ibo_;
1280 }
1281
1282 template <class Mesh>
1283 unsigned int DrawMeshT<Mesh>::mapVertexToVBOIndex(unsigned int _v)
1284 {
1285 if (_v < mesh_.n_vertices())
1286 {
1287 if (invVertexMap_)
1288 return invVertexMap_[_v];
1289 else //if mesh is a point cloud
1290 return _v;
1291 }
1292
1293 return (unsigned int)-1;
1294 }
1295
1296 template <class Mesh>
1297 void DrawMeshT<Mesh>::bindBuffers()
1298 {
1299 updateGPUBuffers();
1300
1301 ACG::GLState::bindBuffer(GL_ARRAY_BUFFER_ARB, vbo_);
1302
1303 // prepare color mode
1304 if (colorMode_)
1305 {
1306 ACG::GLState::colorPointer(4, GL_UNSIGNED_BYTE, vertexDecl_->getVertexStride(), (char*)offsetColor_);
1307 ACG::GLState::enableClientState(GL_COLOR_ARRAY);
1308 }
1309
1310 // vertex decl
1311 ACG::GLState::vertexPointer(3, GL_FLOAT, vertexDecl_->getVertexStride(), (char*)offsetPos_);
1312 ACG::GLState::enableClientState(GL_VERTEX_ARRAY);
1313
1314 glClientActiveTexture(GL_TEXTURE0);
1315 ACG::GLState::texcoordPointer(2, GL_FLOAT, vertexDecl_->getVertexStride(), (char*)offsetTexc_);
1316 ACG::GLState::enableClientState(GL_TEXTURE_COORD_ARRAY);
1317
1318 ACG::GLState::normalPointer(GL_FLOAT, vertexDecl_->getVertexStride(), (char*)offsetNormal_);
1319 ACG::GLState::enableClientState(GL_NORMAL_ARRAY);
1320
1321 // ACG::GLState::normalPointerEXT(3, GL_FLOAT, sizeof(Vertex), (char*)(20)); // ACG::GLState::normalPointerEXT crashes sth. in OpenGL
1322
1323 ACG::GLState::bindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, ibo_);
1324 }
1325
1326 template <class Mesh>
1327 void DrawMeshT<Mesh>::bindBuffersToRenderObject(RenderObject* _obj)
1328 {
1329 updateGPUBuffers();
1330
1331 _obj->vertexBuffer = vbo_;
1332 _obj->indexBuffer = ibo_;
1333
1334 _obj->indexType = indexType_;
1335
1336 // assign correct vertex declaration
1337 _obj->vertexDecl = vertexDecl_;
1338 }
1339
1340 template <class Mesh>
1341 void DrawMeshT<Mesh>::unbindBuffers()
1342 {
1343 ACG::GLState::disableClientState(GL_VERTEX_ARRAY);
1344 ACG::GLState::disableClientState(GL_TEXTURE_COORD_ARRAY);
1345 ACG::GLState::disableClientState(GL_NORMAL_ARRAY);
1346
1347 if (colorMode_)
1348 ACG::GLState::disableClientState(GL_COLOR_ARRAY);
1349
1350 ACG::GLState::bindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
1351 ACG::GLState::bindBuffer(GL_ARRAY_BUFFER_ARB, 0);
1352 }
1353
1354 template <class Mesh>
1355 void DrawMeshT<Mesh>::draw(std::map< int, GLuint>* _textureMap, bool _nonindexed)
1356 {
1357 if (!_nonindexed)
1358 bindBuffers();
1359 else
1360 {
1361 updateFullVBO();
1362 vboFull_.bind();
1363 vertexDecl_->activateFixedFunction();
1364 }
1365
1366 #ifdef DEBUG_MEM_USAGE
1367 getMemoryUsage(true);
1368 #endif
1369
1370 if (numTris_)
1371 {
1372 if (_textureMap)
1373 {
1374 // textured mode
1375
1376 for (int i = 0; i < meshComp_->getNumSubsets(); ++i)
1377 {
1378 const MeshCompiler::Subset* sub = meshComp_->getSubset(i);
1379
1380 if ( _textureMap->find(sub->id) == _textureMap->end() ) {
1381 std::cerr << "Illegal texture index ... trying to access " << sub->id << std::endl;
1382 ACG::GLState::bindTexture(GL_TEXTURE_2D, 0);
1383 }
1384 else
1385 ACG::GLState::bindTexture(GL_TEXTURE_2D, (*_textureMap)[sub->id]);
1386
1387 if (!_nonindexed)
1388 glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(sub->numTris * 3), indexType_,
1389 (GLvoid*)( (size_t)sub->startIndex * (indexType_ == GL_UNSIGNED_INT ? 4 : 2))); // offset in bytes
1390 else
1391 glDrawArrays(GL_TRIANGLES, sub->startIndex, static_cast<GLsizei>(sub->numTris * 3));
1392 }
1393 }
1394 else
1395 {
1396 if (!_nonindexed)
1397 glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(numTris_ * 3), indexType_, 0);
1398 else
1399 glDrawArrays(GL_TRIANGLES, 0, static_cast<GLsizei>(numTris_ * 3));
1400 }
1401 }
1402
1403 unbindBuffers();
1404 }
1405
1406
1407 template <class Mesh>
1408 void ACG::DrawMeshT<Mesh>::addTriRenderObjects(IRenderer* _renderer, const RenderObject* _baseObj, std::map< int, GLuint>* _textureMap, bool _nonindexed)
1409 {
1410 if (numTris_)
1411 {
1412 RenderObject ro = *_baseObj;
1413 if (!_nonindexed)
1414 bindBuffersToRenderObject(&ro);
1415 else
1416 {
1417 updateFullVBO();
1418
1419 ro.vertexBuffer = vboFull_.id();
1420 ro.vertexDecl = vertexDecl_;
1421 }
1422
1423 if (_baseObj->shaderDesc.textured())
1424 {
1425 // textured mode
1426
1427 for (int i = 0; i < meshComp_->getNumSubsets(); ++i)
1428 {
1429 const MeshCompiler::Subset* sub = meshComp_->getSubset(i);
1430
1431 if ( _textureMap )
1432 {
1433 if ( _textureMap->find(sub->id) == _textureMap->end() ) {
1434 std::cerr << "Illegal texture index ... trying to access " << sub->id << std::endl;
1435 }
1436 else
1437 {
1438 RenderObject::Texture tex;
1439 tex.type = GL_TEXTURE_2D;
1440 tex.id = (*_textureMap)[sub->id];
1441 ro.addTexture(tex,0);
1442 }
1443 }
1444 else // no texture map specified, use whatever texture is currently bound to the first texture stage
1445 {
1446 GLState::activeTexture(GL_TEXTURE0);
1447 GLint textureID = 0;
1448 glGetIntegerv(GL_TEXTURE_BINDING_2D, &textureID);
1449
1450 RenderObject::Texture tex;
1451 tex.type = GL_TEXTURE_2D;
1452 tex.id = textureID;
1453 ro.addTexture(tex,0);
1454 }
1455
1456
1457
1458 if (!_nonindexed)
1459 ro.glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(sub->numTris * 3), indexType_,
1460 (GLvoid*)((size_t)sub->startIndex * (indexType_ == GL_UNSIGNED_INT ? 4 : 2))); // offset in bytes
1461 else
1462 ro.glDrawArrays(GL_TRIANGLES, sub->startIndex, static_cast<GLsizei>(sub->numTris * 3) );
1463
1464 _renderer->addRenderObject(&ro);
1465 }
1466 }
1467 else
1468 {
1469 if (!_nonindexed)
1470 ro.glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(numTris_ * 3), indexType_, 0);
1471 else
1472 ro.glDrawArrays(GL_TRIANGLES,0, static_cast<GLsizei>(numTris_ * 3));
1473 _renderer->addRenderObject(&ro);
1474 }
1475 }
1476 }
1477
1478
1479 template <class Mesh>
1480 void DrawMeshT<Mesh>::drawLines()
1481 {
1482 bindBuffers();
1483
1484 if (mesh_.n_edges())
1485 {
1486 ACG::GLState::bindBuffer(GL_ELEMENT_ARRAY_BUFFER, lineIBO_);
1487
1488 glDrawElements(GL_LINES, static_cast<GLsizei>(mesh_.n_edges() * 2), indexType_, 0);
1489 }
1490
1491 unbindBuffers();
1492 }
1493
1494
1495 template <class Mesh>
1496 void DrawMeshT<Mesh>::addLineRenderObjects(IRenderer* _renderer, const RenderObject* _baseObj)
1497 {
1498 RenderObject ro = *_baseObj;
1499 bindBuffersToRenderObject(&ro);
1500
1501 if (mesh_.n_edges())
1502 {
1503 ro.indexBuffer = lineIBO_;
1504 ro.glDrawElements(GL_LINES, static_cast<GLsizei>(mesh_.n_edges() * 2), indexType_, 0);
1505
1506 _renderer->addRenderObject(&ro);
1507 }
1508 }
1509
1510 template <class Mesh>
1511 void DrawMeshT<Mesh>::drawVertices()
1512 {
1513
1514 bindBuffers();
1515
1516 if (numVerts_)
1517 glDrawArrays(GL_POINTS, 0, static_cast<GLsizei>(numVerts_));
1518
1519 unbindBuffers();
1520 }
1521
1522 template <class Mesh>
1523 void DrawMeshT<Mesh>::addPointRenderObjects(IRenderer* _renderer, const RenderObject* _baseObj)
1524 {
1525 RenderObject ro = *_baseObj;
1526 bindBuffersToRenderObject(&ro);
1527
1528 if (numVerts_)
1529 {
1530 ro.glDrawArrays(GL_POINTS, 0, static_cast<GLsizei>(numVerts_));
1531
1532 _renderer->addRenderObject(&ro);
1533 }
1534 }
1535
1537
1538 template <class Mesh>
1539 unsigned int DrawMeshT<Mesh>::countTris(unsigned int* pMaxVertsOut, unsigned int* _pOutNumIndices)
1540 {
1541 unsigned int triCounter = 0;
1542
1543 if (pMaxVertsOut) *pMaxVertsOut = 0;
1544 if (_pOutNumIndices) *_pOutNumIndices = 0;
1545
1546 for (unsigned int i = 0; i < mesh_.n_faces(); ++i)
1547 {
1548 typename Mesh::FaceHandle fh = mesh_.face_handle(i);
1549
1550 // count vertices
1551 unsigned int nPolyVerts = 0;
1552
1553 for (typename Mesh::FaceHalfedgeIter hh_it = mesh_.fh_iter(fh); hh_it.is_valid(); ++hh_it ) ++nPolyVerts;
1554
1555 triCounter += (nPolyVerts - 2);
1556
1557 if (pMaxVertsOut)
1558 {
1559 if (*pMaxVertsOut < nPolyVerts)
1560 *pMaxVertsOut = nPolyVerts;
1561 }
1562
1563 if (_pOutNumIndices) *_pOutNumIndices += nPolyVerts;
1564 }
1565
1566 return triCounter;
1567 }
1568
1569
1570
1571 template <class Mesh>
1572 ACG::Vec3f* DrawMeshT<Mesh>::perEdgeVertexBuffer()
1573 {
1574 // Force update of the buffers if required
1575 if (updatePerEdgeBuffers_)
1576 updatePerEdgeBuffers();
1577 return perEdgeVertexBuf_.empty() ? 0 : &(perEdgeVertexBuf_[0]);
1578 }
1579
1580 template <class Mesh>
1581 ACG::Vec4f* DrawMeshT<Mesh>::perEdgeColorBuffer()
1582 {
1583 // Force update of the buffers if required
1584 if (updatePerEdgeBuffers_)
1585 updatePerEdgeBuffers();
1586 return perEdgeColorBuf_.empty() ? 0 : &(perEdgeColorBuf_[0]);
1587 }
1588
1589
1590 template <class Mesh>
1591 void DrawMeshT<Mesh>::updatePickingVertices(ACG::GLState& _state,
1592 uint _offset)
1593 {
1594 unsigned int idx = 0;
1595
1596 // Adjust size of the color buffer to the number of vertices in the mesh
1597 pickVertColBuf_.resize( mesh_.n_vertices() );
1598 pickVertBuf_.resize( mesh_.n_vertices() );
1599
1600 // Get the right picking colors from the gl state and add them per vertex to the color buffer
1601 typename Mesh::ConstVertexIter v_it(mesh_.vertices_begin()), v_end(mesh_.vertices_end());
1602 for (; v_it!=v_end; ++v_it, ++idx)
1603 {
1604 pickVertColBuf_[idx] = _state.pick_get_name_color(idx + _offset);
1605 pickVertBuf_[idx] = mesh_.point(mesh_.vertex_handle(idx));
1606 }
1607 }
1608
1609
1610 template <class Mesh>
1611 void DrawMeshT<Mesh>::updatePickingVertices_opt(ACG::GLState& _state)
1612 {
1613 // Make sure, the face buffers are up to date before generating the picking data!
1614 if (!numVerts_ && mesh_.n_vertices())
1615 {
1616 rebuild_ = REBUILD_FULL;
1617 rebuild();
1618 }
1619
1620 if (numVerts_)
1621 {
1622 // upload vbo id->openmesh id lookup-table to texture buffer
1623
1624 if (pickVertexMethod_ == 0)
1625 {
1626 std::vector<int> forwardMap(numVerts_, 0);
1627
1628 for (int i = 0; i < (int)numVerts_; ++i)
1629 {
1630 int vboIdx = mapVertexToVBOIndex(i);
1631 if (vboIdx >= 0)
1632 forwardMap[vboIdx] = i;
1633 }
1634 pickVertexMapTBO_.setBufferData(sizeof(int) * numVerts_, &forwardMap[0], GL_R32I, GL_STATIC_DRAW);
1635
1636 }
1637 else
1638 {
1639 // Another method: draw with index buffer, which contains the mapping from openmesh vertex id to drawmesh vbo vertex.
1640 // problem with this: gl_VertexID is affected by index buffer and thus represents the drawmesh vbo ids
1641 // -> use gl_PrimitiveID instead, which represents the openmesh vertex id
1642 if (invVertexMap_)
1643 {
1644 bindPickVertexIbo();
1645 fillInvVertexMap(mesh_.n_vertices(), invVertexMap_);
1646 ACG::GLState::bindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
1647 }
1648
1649 }
1650 }
1651 }
1652
1653
1654 template <class Mesh>
1655 bool ACG::DrawMeshT<Mesh>::supportsPickingVertices_opt()
1656 {
1657 // load and compile picking shader if necessary
1658 // use shaderGenDesc to generate shaders for better shader compatibility
1659 static ShaderGenDesc desc;
1660 // load from cache
1661 if (pickVertexMethod_ == 0)
1662 {
1663 desc.fragmentTemplateFile = "Picking/pick_vertices_fs.glsl";
1664 desc.vertexTemplateFile = "Picking/pick_vertices_vs.glsl";
1665 }
1666 else
1667 {
1668 desc.fragmentTemplateFile = "Picking/pick_vertices_fs2.glsl";
1669 desc.vertexTemplateFile = "Picking/vertex.glsl";
1670 }
1671 pickVertexShader_ = ShaderCache::getInstance()->getProgram(&desc,nullptr);
1672
1673 // check link status
1674 return pickVertexShader_ && pickVertexShader_->isLinked();
1675 }
1676
1677
1678 template <class Mesh>
1679 void ACG::DrawMeshT<Mesh>::drawPickingVertices_opt( const GLMatrixf& _mvp, size_t _pickOffset )
1680 {
1681 // optimized version which computes picking ids in the shader
1682
1683 /*
1684 pickVertexMethod_
1685 0: - create a textureBuffer containing the mapping from vbo id to openmesh vertex id
1686 - draw point list of the main vbo and read texture map in the vertex shader
1687 - computation in vertex shader via gl_VertexID
1688 -> required mem: 4 bytes per vertex in draw vbo
1689 -> # vertex transforms: vertex count in draw vbo
1690
1691 1: - create index buffer containing the mapping from openmesh vertex id to vbo id
1692 (not required for point-clouds)
1693 - draw point list with index buffer
1694 - computation in fragment shader via gl_PrimitiveID
1695 -> required mem: nothing for point-clouds, otherwise 4 bytes per vertex in openmesh
1696 -> # vertex transforms: vertex count in openmesh
1697
1698 method 1 is probably more efficient overall
1699 */
1700
1701 // test support by loading and compiling picking shader
1702 if (!supportsPickingVertices_opt())
1703 return;
1704
1705 ACG::GLState::bindBufferARB(GL_ARRAY_BUFFER_ARB, getVBO());
1706
1707 if (pickVertexMethod_ == 1 && invVertexMap_)
1708 bindPickVertexIbo();
1709
1710 // setup picking shader
1711 pickVertexShader_->use();
1712 getVertexDeclaration()->activateShaderPipeline(pickVertexShader_);
1713
1714 pickVertexShader_->setUniform("pickVertexOffset", static_cast<GLint>(_pickOffset) );
1715
1716 if (pickVertexMethod_ == 0)
1717 {
1718 pickVertexShader_->setUniform("vboToInputMap", 0);
1719 pickVertexMap_opt()->bind(GL_TEXTURE0);
1720 }
1721
1722 pickVertexShader_->setUniform("mWVP", _mvp);
1723
1724 // draw call
1725 if (pickVertexMethod_ == 0)
1726 glDrawArrays(GL_POINTS, 0, static_cast<GLsizei>(getNumVerts()));
1727 else
1728 {
1729 if (pickVertexIBO_opt() && invVertexMap_)
1730 glDrawElements(GL_POINTS, static_cast<GLsizei>(mesh_.n_vertices()), GL_UNSIGNED_INT, 0);
1731 else
1732 glDrawArrays(GL_POINTS, 0, static_cast<GLsizei>(mesh_.n_vertices()));
1733 }
1734
1735 // restore gl state
1736 getVertexDeclaration()->deactivateShaderPipeline(pickVertexShader_);
1737 pickVertexShader_->disable();
1738
1739 // unbind draw buffers
1740 ACG::GLState::bindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
1741
1742 if (pickVertexMethod_ == 1)
1743 ACG::GLState::bindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
1744 }
1745
1746
1747
1748 template <class Mesh>
1749 void DrawMeshT<Mesh>::updatePerEdgeBuffers()
1750 {
1751 // Only update buffers if they are invalid
1752 if (!updatePerEdgeBuffers_)
1753 return;
1754
1755 perEdgeVertexBuf_.resize(mesh_.n_edges() * 2);
1756
1757 if ( mesh_.has_edge_colors() ) {
1758 perEdgeColorBuf_.resize(mesh_.n_edges() * 2);
1759 } else
1760 perEdgeColorBuf_.clear();
1761
1762 unsigned int idx = 0;
1763
1764 typename Mesh::ConstEdgeIter e_it(mesh_.edges_sbegin()), e_end(mesh_.edges_end());
1765 for (; e_it!=e_end; ++e_it) {
1766
1767 perEdgeVertexBuf_[idx] = mesh_.point(mesh_.to_vertex_handle(mesh_.halfedge_handle(*e_it, 0)));
1768 perEdgeVertexBuf_[idx+1] = mesh_.point(mesh_.to_vertex_handle(mesh_.halfedge_handle(*e_it, 1)));
1769
1770 if ( mesh_.has_edge_colors() ) {
1771 const Vec4f color = OpenMesh::color_cast<Vec4f>( mesh_.color(*e_it) ) ;
1772 perEdgeColorBuf_[ idx ] = color;
1773 perEdgeColorBuf_[ idx + 1 ] = color;
1774 }
1775
1776 idx += 2;
1777 }
1778
1779
1780 updatePerEdgeBuffers_ = 0;
1781
1782 updateEdgeHalfedgeVertexDeclarations();
1783 }
1784
1785 template <class Mesh>
1786 template<typename Mesh::Normal (DrawMeshT<Mesh>::*NormalLookup)(typename Mesh::FaceHandle)>
1787 void DrawMeshT<Mesh>::updatePerHalfedgeBuffers()
1788 {
1789 // Only update buffers if they are invalid
1790 if (!updatePerHalfedgeBuffers_)
1791 return;
1792
1793 perHalfedgeVertexBuf_.resize(mesh_.n_halfedges() * 2);
1794
1795 if ( mesh_.has_halfedge_colors() ) {
1796 perHalfedgeColorBuf_.resize(mesh_.n_halfedges() * 2);
1797 } else
1798 perHalfedgeColorBuf_.clear();
1799
1800 unsigned int idx = 0;
1801
1802 for (typename Mesh::ConstHalfedgeIter he_it(mesh_.halfedges_sbegin()), he_end(mesh_.halfedges_end());
1803 he_it != he_end; ++he_it) {
1804
1805 typename Mesh::HalfedgeHandle next_heh = mesh_.next_halfedge_handle(*he_it);
1806 typename Mesh::HalfedgeHandle previous_heh = mesh_.prev_halfedge_handle(*he_it);
1807
1808 if (mesh_.is_valid_handle(next_heh) && mesh_.is_valid_handle(previous_heh))
1809 {
1810 perHalfedgeVertexBuf_[idx] = halfedge_point<NormalLookup>(*he_it);
1811 perHalfedgeVertexBuf_[idx+1] = halfedge_point<NormalLookup>(previous_heh);
1812 }
1813 else
1814 {
1815 // Cannot compute shifted vertex positions. Use original vertex positions instead.
1816 perHalfedgeVertexBuf_[idx ] = mesh_.point(mesh_.to_vertex_handle(*he_it));
1817 perHalfedgeVertexBuf_[idx+1] = mesh_.point(mesh_.from_vertex_handle(*he_it));
1818 }
1819
1820 if ( mesh_.has_halfedge_colors() ) {
1821 const Vec4f color = OpenMesh::color_cast<Vec4f>( mesh_.color(*he_it) ) ;
1822 perHalfedgeColorBuf_[ idx ] = color;
1823 perHalfedgeColorBuf_[ idx + 1 ] = color;
1824 }
1825 idx += 2;
1826 }
1827
1828 if(perHalfedgeVertexBuf_.size() > 0)
1829 {
1830 //create buffers if necessary and bind them
1831 bindHEVbo();
1832 //fill buffer with data
1833 fillHEVBO(perHalfedgeVertexBuf_.size(), sizeof(perHalfedgeVertexBuf_[0]), perHalfedgeVertexBuf_.data());
1834 // rebind the previous buffers
1835 unbindHEVbo();
1836 }
1837
1838 updatePerHalfedgeBuffers_ = 0;
1839
1840 updateEdgeHalfedgeVertexDeclarations();
1841 }
1842
1843 template<class Mesh>
1844 template<typename Mesh::Normal (DrawMeshT<Mesh>::*NormalLookup)(typename Mesh::FaceHandle)>
1845 typename Mesh::Point DrawMeshT<Mesh>::halfedge_point(const typename Mesh::HalfedgeHandle _heh) {
1846
1847 typename Mesh::Point p = mesh_.point(mesh_.to_vertex_handle (_heh));
1848 typename Mesh::Point pp = mesh_.point(mesh_.from_vertex_handle(_heh));
1849 typename Mesh::Point pn = mesh_.point(mesh_.to_vertex_handle(mesh_.next_halfedge_handle(_heh)));
1850
1851 // typename Mesh::Point n = (p-pp)%(pn-p);
1852 typename Mesh::Point fn;
1853 if( !mesh_.is_boundary(_heh))
1854 //fn = mesh_.normal(mesh_.face_handle(_heh));
1855 fn = (this->*NormalLookup)(mesh_.face_handle(_heh));
1856 else
1857 //fn = mesh_.normal(mesh_.face_handle(mesh_.opposite_halfedge_handle(_heh)));
1858 fn = (this->*NormalLookup)(mesh_.face_handle(mesh_.opposite_halfedge_handle(_heh)));
1859
1860 typename Mesh::Point upd = ((fn%(pn-p)).normalize() + (fn%(p-pp)).normalize()).normalize();
1861
1862 upd *= ((pn-p).norm()+(p-pp).norm())*0.08;
1863
1864 return (p+upd);
1865
1866 // double alpha = 0.1;
1867 // // correct weighting for concave triangles (or at concave boundaries)
1868 // if( (fn | n) < 0.0) alpha *=-1.0;
1869
1870 // return (p*(1.0-2.0*alpha) + pp*alpha + pn*alpha);
1871 }
1872
1873 template <class Mesh>
1874 ACG::Vec3f* DrawMeshT<Mesh>::perHalfedgeVertexBuffer()
1875 {
1876 // Force update of the buffers if required
1877 if (updatePerHalfedgeBuffers_) {
1878 if (mesh_.has_face_normals())
1879 updatePerHalfedgeBuffers<&DrawMeshT::cachedNormalLookup>();
1880 else if (mesh_.is_trimesh())
1881 updatePerHalfedgeBuffers<&DrawMeshT::computedTriMeshNormal>();
1882 else
1883 updatePerHalfedgeBuffers<&DrawMeshT::computedNormal>();
1884 }
1885 return perHalfedgeVertexBuf_.empty() ? 0 : &(perHalfedgeVertexBuf_[0]);
1886 }
1887
1888 template <class Mesh>
1889 ACG::Vec4f* DrawMeshT<Mesh>::perHalfedgeColorBuffer()
1890 {
1891 // Force update of the buffers if required
1892 if (updatePerHalfedgeBuffers_) {
1893 if (mesh_.has_face_normals())
1894 updatePerHalfedgeBuffers<&DrawMeshT::cachedNormalLookup>();
1895 else if (mesh_.is_trimesh())
1896 updatePerHalfedgeBuffers<&DrawMeshT::computedTriMeshNormal>();
1897 else
1898 updatePerHalfedgeBuffers<&DrawMeshT::computedNormal>();
1899 }
1900 return perHalfedgeColorBuf_.empty() ? 0 : &(perHalfedgeColorBuf_[0]);
1901 }
1902
1903
1904
1905
1906 template <class Mesh>
1907 void DrawMeshT<Mesh>::updatePickingEdges(ACG::GLState& _state,
1908 unsigned int _offset)
1909 {
1910 updatePerEdgeBuffers();
1911
1912 pickEdgeBuf_.resize(mesh_.n_edges() * 2);
1913
1914
1915 int idx = 0;
1916
1917 typename Mesh::ConstEdgeIter e_it(mesh_.edges_sbegin()), e_end(mesh_.edges_end());
1918 for (; e_it!=e_end; ++e_it) {
1919
1920 const Vec4uc pickColor = _state.pick_get_name_color (e_it->idx() + _offset);
1921
1922 pickEdgeBuf_[idx] = pickColor;
1923 pickEdgeBuf_[idx+1] = pickColor;
1924
1925 idx += 2;
1926 }
1927 }
1928
1929
1930
1931 template <class Mesh>
1932 void DrawMeshT<Mesh>::updatePickingEdges_opt(ACG::GLState& _state )
1933 {
1934 // Make sure, the face buffers are up to date before generating the picking data!
1935 if (!numTris_ && mesh_.n_faces())
1936 {
1937 rebuild_ = REBUILD_FULL;
1938 rebuild();
1939 }
1940
1941 // nothing else to do, optimized edge picking method has no memory overhead
1942 }
1943
1944
1945 template <class Mesh>
1946 bool ACG::DrawMeshT<Mesh>::supportsPickingEdges_opt()
1947 {
1948 // fetch picking shader from cache (edge picking uses same shader as vertex picking)
1949 static ShaderGenDesc desc;
1950 desc.vertexTemplateFile = "Picking/vertex.glsl" ;
1951 desc.fragmentTemplateFile = "Picking/pick_vertices_fs2.glsl" ;
1952 pickEdgeShader_ = ShaderCache::getInstance()->getProgram(&desc, nullptr);
1953
1954 // check link status
1955 return pickEdgeShader_ && pickEdgeShader_->isLinked();
1956 }
1957
1958
1959 template <class Mesh>
1960 void ACG::DrawMeshT<Mesh>::drawPickingEdges_opt( const GLMatrixf& _mvp, size_t _pickOffset )
1961 {
1962 // optimized version which computes picking ids in the shader
1963
1964 /* optimization :
1965 - reuse draw vbo of drawmesh and line index buffer (which is used for wireframe mode)
1966 the line index buffer stores all edges in the same order as they appear in openmesh
1967 - use edge id of openmesh as gl_PrimitiveID in fragment shader to compute the picking id
1968
1969 -> no rendering from sysmem buffers
1970 -> no maintenance/update of picking colors required
1971 -> no additional memory allocation
1972 */
1973
1974 if (!numTris_)
1975 return;
1976
1977 // test support by loading and compiling picking shader
1978 if (!supportsPickingEdges_opt())
1979 return;
1980
1981 ACG::GLState::bindBufferARB(GL_ARRAY_BUFFER_ARB, getVBO());
1982 bindLineIbo();
1983
1984 // setup picking shader (same shader as in vertex picking)
1985 pickEdgeShader_->use();
1986 getVertexDeclaration()->activateShaderPipeline(pickEdgeShader_);
1987
1988 pickEdgeShader_->setUniform("pickVertexOffset", static_cast<GLint>(_pickOffset) );
1989 pickEdgeShader_->setUniform("mWVP", _mvp);
1990
1991 // draw call
1992 glDrawElements(GL_LINES, static_cast<GLsizei>(mesh_.n_edges() * 2), indexType_, 0);
1993
1994 // restore gl state
1995 getVertexDeclaration()->deactivateShaderPipeline(pickEdgeShader_);
1996 pickEdgeShader_->disable();
1997
1998 // unbind draw buffers
1999 ACG::GLState::bindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
2000 ACG::GLState::bindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
2001 }
2002
2003
2004
2005
2006
2007
2008
2009
2010 template <class Mesh>
2011 void DrawMeshT<Mesh>::updatePickingFaces(ACG::GLState& _state )
2012 {
2013 // Make sure, the face buffers are up to date before generating the picking data!
2014 if (!numTris_ && mesh_.n_faces())
2015 {
2016 rebuild_ = REBUILD_FULL;
2017 rebuild();
2018 }
2019
2020 pickFaceVertexBuf_.resize(3 * numTris_);
2021 pickFaceColBuf_.resize(3 * numTris_);
2022
2023 for (unsigned int i = 0; i < numTris_; ++i)
2024 {
2025 unsigned int faceId = (unsigned int)meshComp_->mapToOriginalFaceID((int)i);
2026
2027 const Vec4uc pickColor = _state.pick_get_name_color ( faceId );
2028 for (unsigned int k = 0; k < 3; ++k)
2029 {
2030 int idx = meshComp_->getIndex(i*3 + k);
2031
2032 typename Mesh::HalfedgeHandle hh = mapToHalfedgeHandle(idx);
2033 typename Mesh::VertexHandle vh;
2034
2035 if (hh.is_valid())
2036 vh = mesh_.to_vertex_handle( hh );
2037 else
2038 {
2039 int f_id, c_id;
2040 int posID = meshComp_->mapToOriginalVertexID(idx, f_id, c_id);
2041 vh = mesh_.vertex_handle(posID);
2042 }
2043
2044 pickFaceVertexBuf_[i * 3 + k] = mesh_.point( vh );
2045
2046 pickFaceColBuf_[i * 3 + k] = pickColor;
2047 }
2048 }
2049
2050
2051 }
2052
2053
2054
2055 template <class Mesh>
2056 void DrawMeshT<Mesh>::updatePickingFaces_opt(ACG::GLState& _state )
2057 {
2058 // Make sure, the face buffers are up to date before generating the picking data!
2059 if (!numTris_ && mesh_.n_faces())
2060 {
2061 rebuild_ = REBUILD_FULL;
2062 rebuild();
2063 }
2064
2065 if (meshComp_ && meshComp_->getNumTriangles())
2066 {
2067 // upload tri->face lookup-table to texture buffer
2068 pickFaceTriToFaceMapTBO_.setBufferData(sizeof(int) * meshComp_->getNumTriangles(), meshComp_->mapToOriginalFaceIDPtr(), GL_R32I, GL_STATIC_DRAW);
2069 }
2070
2071 }
2072
2073
2074 template <class Mesh>
2075 bool ACG::DrawMeshT<Mesh>::supportsPickingFaces_opt()
2076 {
2077 if (!ACG::Texture::supportsTextureBuffer())
2078 return false;
2079
2080 // fetch picking shader from cache
2081 static ShaderGenDesc desc;
2082 desc.vertexTemplateFile = "Picking/vertex.glsl";
2083 desc.fragmentTemplateFile = "Picking/pick_face.glsl";
2084 pickFaceShader_ = ShaderCache::getInstance()->getProgram(&desc, nullptr);
2085
2086 // check link status
2087 return pickFaceShader_ && pickFaceShader_->isLinked();
2088 }
2089
2090
2091 template <class Mesh>
2092 void ACG::DrawMeshT<Mesh>::drawPickingFaces_opt( const GLMatrixf& _mvp, size_t _pickOffset )
2093 {
2094 // optimized version which computes picking ids in the shader
2095
2096 /* optimization idea:
2097 - reuse draw buffers of drawmesh
2098 - create lookup table which maps from draw triangle id to openmesh face id (stored in textureBuffer)
2099 - get base offset of face picking: pickFaceOffset = _state.pick_get_name_color(0)
2100 - render with following fragment shader, which computes face picking ids on the fly:
2101
2102 uniform int pickFaceOffset;
2103 uniform isamplerBuffer triangleToFaceMap;
2104
2105 out int outPickID; // if possible to write integer. otherwise, convert to ubyte4 or sth.
2106
2107 void main()
2108 {
2109 // map from triangle id to face id
2110 int faceID = texelFetch(triangleToFaceMap, gl_PrimitiveID);
2111
2112 outPickID = pickFaceOffset + faceID;
2113 // maybe the integer id has to be converted to a vec4 color here, not sure
2114 }
2115
2116 -> no rendering from sysmem buffers
2117 -> no maintenance/update of picking colors required
2118 -> lower memory footprint: 4 bytes per triangle
2119
2120 keep old approach to stay compatible on systems which do not support texture buffers or integer arithmetic in shaders
2121 */
2122
2123 if (!numTris_)
2124 return;
2125
2126 // test support by loading and compiling picking shader
2127 if (!supportsPickingFaces_opt())
2128 return;
2129
2130 // reuse cache optimized draw buffers
2131 ACG::GLState::bindBufferARB(GL_ARRAY_BUFFER_ARB, getVBO());
2132 ACG::GLState::bindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, getIBO());
2133
2134 // setup picking shader
2135 pickFaceShader_->use();
2136 getVertexDeclaration()->activateShaderPipeline(pickFaceShader_);
2137
2138 pickFaceShader_->setUniform("pickFaceOffset", static_cast<GLint>(_pickOffset));
2139 pickFaceShader_->setUniform("triToFaceMap", 0);
2140
2141 pickFaceTriangleMap_opt()->bind(GL_TEXTURE0);
2142
2143 pickFaceShader_->setUniform("mWVP", _mvp);
2144
2145 // draw call
2146 glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(getNumTris() * 3), getIndexType(), 0);
2147
2148 // restore gl state
2149 getVertexDeclaration()->deactivateShaderPipeline(pickFaceShader_);
2150 pickFaceShader_->disable();
2151
2152 // unbind draw buffers
2153 ACG::GLState::bindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
2154 ACG::GLState::bindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
2155 }
2156
2157
2158
2159
2160 template <class Mesh>
2161 void DrawMeshT<Mesh>::updatePickingAny(ACG::GLState& _state )
2162 {
2163 if (!numTris_ && mesh_.n_faces())
2164 {
2165 rebuild_ = REBUILD_FULL;
2166 rebuild();
2167 }
2168
2169 pickFaceVertexBuf_.resize(3 * numTris_);
2170 pickAnyFaceColBuf_.resize(3 * numTris_);
2171
2172 for (unsigned int i = 0; i < numTris_; ++i)
2173 {
2174 int faceId = meshComp_->mapToOriginalFaceID(i);
2175 const Vec4uc pickColor = _state.pick_get_name_color ( faceId );
2176 for (unsigned int k = 0; k < 3; ++k)
2177 {
2178 int idx = meshComp_->getIndex(i*3 + k);
2179
2180
2181 typename Mesh::HalfedgeHandle hh = mapToHalfedgeHandle(idx);
2182 typename Mesh::VertexHandle vh;
2183
2184 if (hh.is_valid())
2185 vh = mesh_.to_vertex_handle( hh );
2186 else
2187 {
2188 int f_id, c_id;
2189 int posID = meshComp_->mapToOriginalVertexID(idx, f_id, c_id);
2190 vh = mesh_.vertex_handle(posID);
2191 }
2192
2193 pickFaceVertexBuf_[i * 3 + k] = mesh_.point( vh );
2194
2195 pickAnyFaceColBuf_[i * 3 + k] = pickColor;
2196 }
2197 }
2198
2199
2200
2201 updatePerEdgeBuffers();
2202
2203 pickAnyEdgeColBuf_.resize(mesh_.n_edges() * 2);
2204
2205 unsigned int idx = 0;
2206 typename Mesh::ConstEdgeIter e_it(mesh_.edges_sbegin()), e_end(mesh_.edges_end());
2207 for (; e_it!=e_end; ++e_it) {
2208
2209 const Vec4uc pickColor = _state.pick_get_name_color (e_it->idx() + mesh_.n_faces());
2210
2211 pickAnyEdgeColBuf_[idx] = pickColor;
2212 pickAnyEdgeColBuf_[idx+1] = pickColor;
2213
2214 idx += 2;
2215 }
2216
2217
2218
2219 idx = 0;
2220
2221 // Adjust size of the color buffer to the number of vertices in the mesh
2222 pickAnyVertexColBuf_.resize( mesh_.n_vertices() );
2223 pickVertBuf_.resize( mesh_.n_vertices() );
2224
2225 // Get the right picking colors from the gl state and add them per vertex to the color buffer
2226 typename Mesh::ConstVertexIter v_it(mesh_.vertices_begin()), v_end(mesh_.vertices_end());
2227 for (; v_it!=v_end; ++v_it, ++idx)
2228 {
2229 pickAnyVertexColBuf_[idx] = _state.pick_get_name_color(idx + mesh_.n_faces() + mesh_.n_edges());
2230 pickVertBuf_[idx] = mesh_.point(mesh_.vertex_handle(idx));
2231 }
2232 }
2233
2234
2235
2236 template <class Mesh>
2237 void DrawMeshT<Mesh>::updatePickingAny_opt(ACG::GLState& _state )
2238 {
2239 updatePickingFaces_opt(_state);
2240 updatePickingEdges_opt(_state);
2241 updatePickingVertices_opt(_state);
2242
2243 // optimized any picking does not require separate picking buffers
2244 }
2245
2246 template <class Mesh>
2247 bool ACG::DrawMeshT<Mesh>::supportsPickingAny_opt()
2248 {
2249 return supportsPickingFaces_opt() && supportsPickingEdges_opt() && supportsPickingVertices_opt();
2250 }
2251
2252
2253 template <class Mesh>
2254 void ACG::DrawMeshT<Mesh>::drawPickingAny_opt( const GLMatrixf& _mvp, size_t _pickOffset )
2255 {
2256 // optimized version which computes picking ids in the shader
2257
2258 /* optimization:
2259 draw picking ids of faces, edges and vertices with appropriate offsets
2260 */
2261
2262 // test support by loading and compiling picking shader
2263 if (!supportsPickingAny_opt())
2264 return;
2265
2266 drawPickingFaces_opt(_mvp, _pickOffset);
2267
2268 ACG::GLState::depthFunc(GL_LEQUAL);
2269
2270 drawPickingEdges_opt(_mvp, _pickOffset + mesh_.n_faces());
2271
2272 drawPickingVertices_opt(_mvp, _pickOffset + mesh_.n_faces() + mesh_.n_edges());
2273 }
2274
2275 template <class Mesh>
2276 void
2277 DrawMeshT<Mesh>::
2278 setTextureIndexPropertyName( std::string _indexPropertyName ) {
2279
2280 // Check if the given property exists
2281 OpenMesh::FPropHandleT< int > textureIndexProperty;
2282 if ( !mesh_.get_property_handle(textureIndexProperty,_indexPropertyName) ) {
2283 if ( _indexPropertyName != "No Texture Index" )
2284 std::cerr << "DrawMeshT: Unable to get per face texture Index property named " << _indexPropertyName << std::endl;
2285 return;
2286 }
2287
2288 // Remember the property name
2289 textureIndexPropertyName_ = _indexPropertyName;
2290
2291 // mark strips as invalid ( have to be regenerated to collect texture index information)
2292 // stripsValid_ = false;
2293 //
2294 // // mark the buffers as invalid as we have a new per face index array
2295 // invalidatePerFaceBuffers();
2296 rebuild_ |= REBUILD_TOPOLOGY;
2297 }
2298
2299 template <class Mesh>
2300 void
2301 DrawMeshT<Mesh>::
2302 setPerFaceTextureCoordinatePropertyName( std::string _perFaceTextureCoordinatePropertyName ) {
2303
2304 // Check if the given property exists
2305 OpenMesh::HPropHandleT< typename Mesh::TexCoord2D > perFaceTextureCoordinateProperty;
2306 if ( !mesh_.get_property_handle(perFaceTextureCoordinateProperty,_perFaceTextureCoordinatePropertyName) ) {
2307 if ( _perFaceTextureCoordinatePropertyName != "No Texture" )
2308 std::cerr << "DrawMeshT: Unable to get per face texture coordinate property named " << _perFaceTextureCoordinatePropertyName << std::endl;
2309 return;
2310 }
2311
2312 // Remember the property name
2313 perFaceTextureCoordinatePropertyName_ = _perFaceTextureCoordinatePropertyName;
2314
2315 // mark the buffers as invalid as we have a new per face index array
2316 // invalidatePerFaceBuffers();
2317 rebuild_ |= REBUILD_GEOMETRY;
2318 }
2319
2320
2321 template <class Mesh>
2322 unsigned int DrawMeshT<Mesh>::getNumTextures()
2323 {
2324 unsigned int n = 0;
2325 for (unsigned int i = 0; i < meshComp_->getNumSubsets(); ++i)
2326 {
2327 if (meshComp_->getSubset(i)->id > 0) ++n;
2328 }
2329 return n;
2330 }
2331
2332 template <class Mesh>
2333 int
2334 DrawMeshT<Mesh>::perFaceTextureCoordinateAvailable() {
2335
2336 // We really have to recheck, as the property might get lost externally (e.g. on restores of the mesh)
2337 OpenMesh::HPropHandleT< typename Mesh::TexCoord2D > perFaceTextureCoordinateProperty;
2338 if ( !mesh_.get_property_handle(perFaceTextureCoordinateProperty, perFaceTextureCoordinatePropertyName_) ) {
2339 return false;
2340 }
2341
2342 // Property available
2343 return true;
2344
2345 }
2346
2347
2348 template <class Mesh>
2349 int
2350 DrawMeshT<Mesh>::perFaceTextureIndexAvailable() {
2351
2352 // We really have to recheck, as the property might get lost externally (e.g. on restores of the mesh)
2353 OpenMesh::FPropHandleT< int > textureIndexProperty;
2354 if ( !mesh_.get_property_handle(textureIndexProperty, textureIndexPropertyName_) ) {
2355 return false;
2356 }
2357
2358 // Property available
2359 return true;
2360 }
2361
2362
2363
2364
2365
2366
2367 template <class Mesh>
2368 void ACG::DrawMeshT<Mesh>::createVertexDeclaration()
2369 {
2370 vertexDecl_->clear();
2371
2372 vertexDecl_->addElement(GL_FLOAT, 3, VERTEX_USAGE_POSITION);
2373 vertexDecl_->addElement(GL_FLOAT, 2, VERTEX_USAGE_TEXCOORD);
2374 vertexDecl_->addElement(GL_FLOAT, 3, VERTEX_USAGE_NORMAL);
2375 vertexDecl_->addElement(GL_UNSIGNED_BYTE, 4, VERTEX_USAGE_COLOR);
2376
2377 for (size_t i = 0; i < additionalElements_.size(); ++i)
2378 {
2379 VertexProperty* prop = &additionalElements_[i];
2380
2381 // invalidate detected type
2382 prop->sourceType_.numElements_ = 0;
2383 prop->sourceType_.pointer_ = 0;
2384 prop->sourceType_.type_ = 0;
2385 prop->sourceType_.shaderInputName_ = 0;
2386 prop->sourceType_.usage_ = VERTEX_USAGE_SHADER_INPUT;
2387 prop->propDataPtr_ = 0;
2388 prop->declElementID_ = -1;
2389
2390 // get property handle in openmesh by name
2391 OpenMesh::BaseProperty* baseProp = 0;
2392
2393 switch (prop->source_)
2394 {
2395 case PROPERTY_SOURCE_VERTEX: baseProp = mesh_._get_vprop(prop->name_); break;
2396 case PROPERTY_SOURCE_FACE: baseProp = mesh_._get_fprop(prop->name_); break;
2397 case PROPERTY_SOURCE_HALFEDGE: baseProp = mesh_._get_hprop(prop->name_); break;
2398 default: baseProp = mesh_._get_vprop(prop->name_); break;
2399 }
2400
2401 // detect data type of property
2402 prop->propDataPtr_ = getMeshPropertyType(baseProp, &prop->sourceType_.type_, &prop->sourceType_.numElements_);
2403
2404
2405 if (prop->propDataPtr_)
2406 {
2407 prop->sourceType_.shaderInputName_ = prop->name_.c_str();
2408
2409 // should have same type in vbo
2410 prop->destType_ = prop->sourceType_;
2411
2412 prop->destType_.shaderInputName_ = prop->vertexShaderInputName_.c_str();
2413
2414 prop->declElementID_ = int(vertexDecl_->getNumElements());
2415
2416 vertexDecl_->addElement(&prop->destType_);
2417 }
2418 else
2419 std::cerr << "Could not detect data type of property " << prop->name_ << std::endl;
2420 }
2421 }
2422
2423
2424 template <class Mesh>
2425 void ACG::DrawMeshT<Mesh>::updateEdgeHalfedgeVertexDeclarations()
2426 {
2427 vertexDeclEdgeCol_->clear();
2428 vertexDeclEdgeCol_->addElement(GL_FLOAT, 3, VERTEX_USAGE_POSITION, perEdgeVertexBuffer());
2429 vertexDeclEdgeCol_->addElement(GL_FLOAT, 4, VERTEX_USAGE_COLOR, perEdgeColorBuffer());
2430
2431 vertexDeclHalfedgeCol_->clear();
2432 vertexDeclHalfedgeCol_->addElement(GL_FLOAT, 3, VERTEX_USAGE_POSITION, perHalfedgeVertexBuffer());
2433 vertexDeclHalfedgeCol_->addElement(GL_FLOAT, 4, VERTEX_USAGE_COLOR, perHalfedgeColorBuffer());
2434
2435 vertexDeclHalfedgePos_->clear();
2436 vertexDeclHalfedgePos_->addElement(GL_FLOAT, 3, VERTEX_USAGE_POSITION, perHalfedgeVertexBuffer());
2437
2438 vertexDeclEdgeCol_->setVertexStride(0);
2439 vertexDeclHalfedgeCol_->setVertexStride(0);
2440 vertexDeclHalfedgePos_->setVertexStride(0);
2441 }
2442
2443 template <class Mesh>
2444 VertexDeclaration* ACG::DrawMeshT<Mesh>::getVertexDeclaration()
2445 {
2446 return vertexDecl_;
2447 }
2448
2449
2450 template<class Mesh>
2451 typename Mesh::HalfedgeHandle ACG::DrawMeshT<Mesh>::mapToHalfedgeHandle(size_t _vertexId)
2452 {
2453 int faceId = -1, cornerId = -1;
2454
2455 // map to halfedge handle
2456 if (meshComp_)
2457 meshComp_->mapToOriginalVertexID(_vertexId, faceId, cornerId);
2458
2459 if (faceId >= 0)
2460 {
2461 typename Mesh::FaceHandle fh = mesh_.face_handle(faceId);
2462 typename Mesh::FaceHalfedgeIter hh_it = mesh_.fh_iter(fh);
2463
2464 // seek to halfedge
2465 for (int k = 0; k < cornerId && hh_it.is_valid(); ++k )
2466 ++hh_it;
2467
2468 return *hh_it;
2469 }
2470 else
2471 return typename Mesh::HalfedgeHandle(-1);
2472 }
2473
2474
2475 template <class Mesh>
2476 void ACG::DrawMeshT<Mesh>::writeVertexElement( void* _dstBuf, size_t _vertex, size_t _stride, size_t _elementOffset, size_t _elementSize, const void* _elementData )
2477 {
2478 // byte offset
2479 size_t offset = _vertex * _stride + _elementOffset;
2480
2481 // write address
2482 char* dst = static_cast<char*>(_dstBuf) + offset;
2483
2484 // copy
2485 memcpy(dst, _elementData, _elementSize);
2486 }
2487
2488 template <class Mesh>
2489 void ACG::DrawMeshT<Mesh>::writePosition( size_t _vertex, const ACG::Vec3d& _n )
2490 {
2491 // store float3 position
2492 float f3[3] = {float(_n[0]), float(_n[1]), float(_n[2])};
2493
2494 writeVertexElement(&vertices_[0], _vertex, vertexDecl_->getVertexStride(), 0, 12, f3);
2495 }
2496
2497 template <class Mesh>
2498 void ACG::DrawMeshT<Mesh>::writeNormal( size_t _vertex, const ACG::Vec3d& _n )
2499 {
2500 // store float3 normal
2501 float f3[3] = {float(_n[0]), float(_n[1]), float(_n[2])};
2502
2503 writeVertexElement(&vertices_[0], _vertex, vertexDecl_->getVertexStride(), offsetNormal_, 12, f3);
2504 }
2505
2506
2507 template <class Mesh>
2508 void ACG::DrawMeshT<Mesh>::writeTexcoord( size_t _vertex, const ACG::Vec2f& _uv )
2509 {
2510 writeVertexElement(&vertices_[0], _vertex, vertexDecl_->getVertexStride(), offsetTexc_, 8, _uv.data());
2511 }
2512
2513 template <class Mesh>
2514 void ACG::DrawMeshT<Mesh>::writeColor( size_t _vertex, unsigned int _color )
2515 {
2516 writeVertexElement(&vertices_[0], _vertex, vertexDecl_->getVertexStride(), offsetColor_, 4, &_color);
2517 }
2518
2519
2520 template <class Mesh>
2521 void ACG::DrawMeshT<Mesh>::writeVertexProperty( size_t _vertex, const VertexElement* _elementDesc, const ACG::Vec4f& _propf )
2522 {
2523 const size_t elementSize = VertexDeclaration::getElementSize(_elementDesc);
2524
2525 writeVertexElement(&vertices_[0], _vertex, vertexDecl_->getVertexStride(), _elementDesc->getByteOffset(), elementSize, _propf.data());
2526 }
2527
2528
2529
2530 template <class Mesh>
2531 void ACG::DrawMeshT<Mesh>::addVertexElement( const std::string& _propertyName, PropertySource _source )
2532 {
2533 // check if element has already been requested before
2534
2535 for (size_t i = 0; i < additionalElements_.size(); ++i)
2536 {
2537 if (additionalElements_[i].name_ == _propertyName)
2538 {
2539 additionalElements_[i].source_ = _source;
2540
2541 return;
2542 }
2543 }
2544
2545
2546 // request new property
2547 VertexProperty prop;
2548
2549 prop.name_ = _propertyName;
2550 prop.source_ = _source;
2551 prop.vertexShaderInputName_ = _propertyName;
2552 // rest of property desc is initialized later in createVertexDeclaration()
2553
2554 additionalElements_.push_back(prop);
2555
2556 updateFull();
2557 }
2558
2559
2560 template <class Mesh>
2561 bool ACG::DrawMeshT<Mesh>::scanVertexShaderForInput( const std::string& _vertexShaderFile )
2562 {
2563 bool success = true;
2564
2565 std::ifstream file;
2566
2567 file.open(_vertexShaderFile.c_str(), std::ios_base::in);
2568
2569 if (file.is_open())
2570 {
2571 while (!file.eof())
2572 {
2573 char line[0xff];
2574
2575 file.getline(line, 0xff);
2576
2577 // get rid of whitespaces at begin/end, and internal padding
2578 QString strLine = line;
2579 strLine = strLine.simplified();
2580
2581 // pattern matching for vertex input attributes
2582 if (!strLine.startsWith("//") && !strLine.startsWith("*/"))
2583 {
2584
2585 if (strLine.startsWith("in ") || strLine.contains(" in "))
2586 {
2587 // extract
2588 int semIdx = strLine.indexOf(';');
2589
2590
2591 if (semIdx >= 0)
2592 {
2593 // property name = string before semicolon without whitespace
2594
2595 // remove parts after semicolon
2596 QString strName = strLine;
2597 strName.remove(semIdx, strName.length());
2598
2599 strName = strName.simplified();
2600
2601 // property name = string between last whitespace and last character
2602 int lastWhite = strName.lastIndexOf(' ');
2603
2604 if (lastWhite >= 0)
2605 {
2606 strName.remove(0, lastWhite);
2607
2608 strName = strName.simplified();
2609
2610 // check for reserved input attributes
2611 if (strName != "inPosition" &&
2612 strName != "inTexCoord" &&
2613 strName != "inNormal" &&
2614 strName != "inColor")
2615 {
2616 // custom property
2617
2618 std::string propName = strName.toStdString();
2619
2620 // choose property source
2621 PropertySource src = PROPERTY_SOURCE_VERTEX;
2622
2623 if (strLine.contains("flat "))
2624 {
2625 // per face attribute
2626 src = PROPERTY_SOURCE_FACE;
2627
2628 if (!mesh_._get_fprop(propName))
2629 src = PROPERTY_SOURCE_VERTEX; // face source not available, try vertex next..
2630 }
2631
2632 if (src == PROPERTY_SOURCE_VERTEX)
2633 {
2634 if (!mesh_._get_vprop(propName))
2635 src = PROPERTY_SOURCE_HALFEDGE; // vertex source not available, try halfedge next..
2636 }
2637
2638 // prefer halfedge props over vertex props
2639 if (src == PROPERTY_SOURCE_VERTEX)
2640 {
2641 if ( mesh_._get_hprop(propName) && src == PROPERTY_SOURCE_VERTEX)
2642 src = PROPERTY_SOURCE_HALFEDGE;
2643 }
2644
2645 // error output if property does not exist
2646 if (src == PROPERTY_SOURCE_HALFEDGE && !mesh_._get_hprop(propName))
2647 {
2648 std::cerr << "DrawMesh error - requested property " << propName << " does not exist" << std::endl;
2649 success = false;
2650 }
2651 else
2652 {
2653 addVertexElement(propName, src);
2654 }
2655
2656 }
2657
2658 }
2659 }
2660
2661
2662 }
2663
2664 }
2665
2666 }
2667
2668
2669 }
2670
2671 return success;
2672 }
2673
2674 template<class Mesh>
2675 void DrawMeshT<Mesh>::dumpObj(const char* _filename) const
2676 {
2677 std::ofstream file;
2678 file.open(_filename);
2679
2680 if (file.is_open())
2681 {
2682 for (int attrId = 0; attrId < 3; ++attrId)
2683 {
2684 for (int i = 0; i < numVerts_; ++i)
2685 {
2686 // ptr to vertex
2687 const char* v = &vertices_[i * vertexDecl_->getVertexStride()];
2688
2689 const float* pos = reinterpret_cast<const float*>((const void*)(v + offsetPos_));
2690 const float* n = reinterpret_cast<const float*>((const void*)(v + offsetNormal_));
2691 const float* texc = reinterpret_cast<const float*>((const void*)(v + offsetTexc_));
2692 // unsigned int col = *reinterpret_cast<const unsigned int*>(v + offsetColor_);
2693
2694 switch (attrId)
2695 {
2696 case 0: file << "v "<<pos[0]<<" "<<pos[1]<<" "<<pos[2]<<"\n"; break;
2697 case 1: file << "vt "<<texc[0]<<" "<<texc[1]<<"\n"; break;
2698 case 2: file << "vn "<<n[0]<<" "<<n[1]<<" "<<n[2]<<"\n"; break;
2699 default: break;
2700 }
2701 }
2702 }
2703
2704
2705 for (int i = 0; i < numTris_; ++i)
2706 {
2707 // ptr to triangle
2708 const int* tri = meshComp_->getIndexBuffer() + i*3;
2709
2710 file << "f "<<tri[0]+1<<"/"<<tri[0]+1<<"/"<<tri[0]+1<<" "<<tri[1]+1<<"/"<<tri[1]+1<<"/"<<tri[1]+1<<" "<<tri[2]+1<<"/"<<tri[2]+1<<"/"<<tri[2]+1<<"\n";
2711 }
2712
2713 file.close();
2714 }
2715 }
2716
2717
2718
2719 template <class Mesh>
2720 void ACG::DrawMeshT<Mesh>::readVertexFromVBO(unsigned int _vertex, void* _dst)
2721 {
2722 assert(_dst != 0);
2723
2724 unsigned int stride = vertexDecl_->getVertexStride();
2725
2726 // byte offset
2727 unsigned int offset = _vertex * stride;
2728
2729 // copy
2730 memcpy(_dst, &vertices_[offset], stride);
2731 }
2732
2733
2734
2735
2736
2737 template <class Mesh>
2738 void ACG::DrawMeshT<Mesh>::invalidateFullVBO()
2739 {
2740 updateFullVBO_ = true;
2741 }
2742
2743
2744 template <class Mesh>
2745 void ACG::DrawMeshT<Mesh>::updateFullVBO()
2746 {
2747 // update indexed vbo first, in the next step this vbo is resolved into non-indexed
2748 updateGPUBuffers();
2749
2750 if (updateFullVBO_)
2751 {
2752 MeshCompiler* mc = getMeshCompiler();
2753
2754 if (mc)
2755 {
2756 int numTris = mc->getNumTriangles();
2757
2758 // alloc buffer
2759 int numVerts = 3 * numTris;
2760 int stride = mc->getVertexDeclaration()->getVertexStride();
2761 std::vector<char> fullBuf(numVerts * stride);
2762
2763 // fill buffer
2764 for (int i = 0; i < numTris; ++i)
2765 {
2766 for (int k = 0; k < 3; ++k)
2767 {
2768 int idx = i * 3 + k;
2769 int vertexID = mc->getIndex(idx);
2770 readVertexFromVBO(vertexID, &fullBuf[idx * stride]);
2771
2772 if (colorMode_ == 2)
2773 {
2774 // read face color
2775
2776 int faceId = meshComp_->mapToOriginalFaceID(i);
2777 unsigned int fcolor = getFaceColor(mesh_.face_handle(faceId));
2778
2779 // store face color
2780 writeVertexElement(&fullBuf[0], idx, vertexDecl_->getVertexStride(), offsetColor_, 4, &fcolor);
2781 }
2782
2783 }
2784 }
2785
2786 if (!fullBuf.empty())
2787 vboFull_.upload(fullBuf.size(), &fullBuf[0], GL_STATIC_DRAW);
2788
2789 // clean update flag
2790 updateFullVBO_ = false;
2791 }
2792 }
2793 }
2794
2795
2796
2797
2798
2799 }
OpenMesh::TriMesh_ArrayKernelT
Definition: PolyMesh_ArrayKernelT.hh:73
ACG
Namespace providing different geometric functions concerning angles.
Definition: BaseObjectData.hh:68
ACG::GLState::texcoordPointer
static void texcoordPointer(GLint _size, GLenum _type, GLsizei _stride, const GLvoid *_pointer)
replaces glTexcoordPointer, supports locking
Definition: GLState.cc:1984
ACG::VertexDeclaration
Class to define the vertex input layout.
Definition: VertexDeclaration.hh:268
ACG::RenderObject::addTexture
void addTexture(const Texture &_t)
adds a texture to stage RenderObjects::numTextures()
Definition: RenderObject.hh:326
ACG::DrawMeshT::getMemoryUsage
unsigned int getMemoryUsage(bool _printReport=false)
measures the size in bytes of allocated memory. eventually prints a report to std::cout ...
Definition: DrawMeshT_impl.hh:1164
ACG::DrawMeshT::invalidateFullVBO
void invalidateFullVBO()
the mesh has been changed
Definition: DrawMeshT_impl.hh:2738
ACG::DrawMeshT::addVertexElement
void addVertexElement(const std::string &_propertyName, PropertySource _source=PROPERTY_SOURCE_VERTEX)
Add custom elements to the vertex layout.
Definition: DrawMeshT_impl.hh:2531
ACG::DrawMeshT::addTriRenderObjects
void addTriRenderObjects(IRenderer *_renderer, const RenderObject *_baseObj, std::map< int, GLuint > *_textureMap, bool _nonindexed=false)
adds RenderObjects to a deferred draw call renderer
Definition: DrawMeshT_impl.hh:1408
ACG::DrawMeshT::supportsPickingFaces_opt
bool supportsPickingFaces_opt()
Check if optimized face picking is supported.
Definition: DrawMeshT_impl.hh:2075
ACG::GLState::pick_get_name_color
Vec4uc pick_get_name_color(size_t _idx)
Definition: GLState.cc:1068
OpenMesh::PolyMeshT::Point
Kernel::Point Point
Coordinate type.
Definition: PolyMeshT.hh:112
ACG::Vec4uc
VectorT< unsigned char, 4 > Vec4uc
Definition: VectorT.hh:128
ACG::Vec3f
VectorT< float, 3 > Vec3f
Definition: VectorT.hh:119
ACG::GLState::colorPointer
static void colorPointer(GLint _size, GLenum _type, GLsizei _stride, const GLvoid *_pointer)
replaces glColorPointer, supports locking
Definition: GLState.cc:1962
ACG::DrawMeshT::readVertexFromVBO
void readVertexFromVBO(unsigned int _vertex, void *_dst)
Read one vertex from the rendering vbo.
Definition: DrawMeshT_impl.hh:2720
ACG::GLState::depthFunc
const GLenum & depthFunc() const
get glDepthFunc() that is supposed to be active
Definition: GLState.cc:941
ACG::DrawMeshT::getVertexDeclaration
VertexDeclaration * getVertexDeclaration()
get vertex declaration of the current vbo layout
Definition: DrawMeshT_impl.hh:2444
ACG::VERTEX_USAGE_SHADER_INPUT
defined by user via VertexElement::shaderInputName_
Definition: VertexDeclaration.hh:71
ACG::DrawMeshT::drawPickingEdges_opt
void drawPickingEdges_opt(const GLMatrixf &_mvp, size_t _pickOffset)
Optimized rendering of edge picking ids with a shader.
Definition: DrawMeshT_impl.hh:1960
ACG::DrawMeshFaceInput
Definition: DrawMeshT_impl.hh:245
ACG::MeshCompiler
Definition: MeshCompiler.hh:240
OpenMesh::PolyMeshT::ConstFaceHalfedgeIter
Kernel::ConstFaceHalfedgeIter ConstFaceHalfedgeIter
Circulator.
Definition: PolyMeshT.hh:178
ACG::DrawMeshT::supportsPickingVertices_opt
bool supportsPickingVertices_opt()
Check if optimized vertex picking is supported.
Definition: DrawMeshT_impl.hh:1655
OpenMesh::HalfedgeHandle
Handle for a halfedge entity.
Definition: Handles.hh:127
OpenMesh::BaseProperty::n_elements
virtual size_t n_elements() const =0
Number of elements in property.
OpenMesh::PolyMeshT::ConstVertexFaceIter
Kernel::ConstVertexFaceIter ConstVertexFaceIter
Circulator.
Definition: PolyMeshT.hh:176
ACG::MeshCompiler::getVertexDeclaration
const VertexDeclaration * getVertexDeclaration() const
Definition: MeshCompiler.hh:605
OpenMesh::VectorT::data
Scalar * data()
access to Scalar array
Definition: Vector11T.hh:195
ACG::VERTEX_USAGE_COLOR
"inColor"
Definition: VertexDeclaration.hh:68
ACG::RenderObject
Interface class between scenegraph and renderer.
Definition: RenderObject.hh:98
ACG::VertexDeclaration::getVertexStride
unsigned int getVertexStride(unsigned int i=0) const
Definition: VertexDeclaration.cc:545
ACG::DrawMeshT::updateFullVBO
void updateFullVBO()
update the full mesh vbo
Definition: DrawMeshT_impl.hh:2745
ACG::DrawMeshT::drawPickingAny_opt
void drawPickingAny_opt(const GLMatrixf &_mvp, size_t _pickOffset)
Optimized rendering of any picking ids with a shader.
Definition: DrawMeshT_impl.hh:2254
ACG::DrawMeshT::scanVertexShaderForInput
bool scanVertexShaderForInput(const std::string &_vertexShaderFile)
Scan vertex layout from vertex shader.
Definition: DrawMeshT_impl.hh:2561
OpenMesh::PolyMeshT::VertexHandle
Kernel::VertexHandle VertexHandle
Handle for referencing the corresponding item.
Definition: PolyMeshT.hh:136
OpenMesh::TriMeshT::is_trimesh
static constexpr bool is_trimesh()
Determine whether this is a PolyMeshT or TriMeshT (This function does not check the per face vertex c...
Definition: TriMeshT.hh:104
ACG::DrawMeshT::drawPickingFaces_opt
void drawPickingFaces_opt(const GLMatrixf &_mvp, size_t _pickOffset)
Optimized rendering of face picking ids with a shader.
Definition: DrawMeshT_impl.hh:2092
ACG::MeshCompiler::getNumTriangles
int getNumTriangles() const
Definition: MeshCompiler.hh:587
ACG::GLState
Definition: GLState.hh:213
ACG::DrawMeshFaceInput::getFaceAttr
int * getFaceAttr(const int _faceID, const int _attrID) const
Definition: DrawMeshT_impl.hh:362
ACG::DrawMeshT::drawPickingVertices_opt
void drawPickingVertices_opt(const GLMatrixf &_mvp, size_t _pickOffset)
Optimized rendering of vertex picking ids with a shader.
Definition: DrawMeshT_impl.hh:1679
ACG::GLState::disableClientState
static void disableClientState(GLenum _cap)
replaces glDisableClientState, supports locking
Definition: GLState.cc:1584
ACG::DrawMeshT::createVertexDeclaration
void createVertexDeclaration()
creates all vertex declarations needed for deferred draw call renderer
Definition: DrawMeshT_impl.hh:2368
ACG::VertexElement::usage_
VERTEX_USAGE usage_
position, normal, shader input ..
Definition: VertexDeclaration.hh:84
ACG::GLMatrixT< float >
ACG::ShaderGenDesc
Definition: ShaderGenerator.hh:83
ACG::RenderObject::vertexBuffer
GLuint vertexBuffer
VBO, IBO ids, ignored if VAO is provided.
Definition: RenderObject.hh:162
OpenMesh::PropertyT
Default property class for any type T.
Definition: Property.hh:89
ACG::DrawMeshFaceInput::getFaceAttr
bool getFaceAttr(const int _faceID, const int _attrID, int *_out) const
Definition: DrawMeshT_impl.hh:341
ACG::GLState::normalPointer
static void normalPointer(GLenum _type, GLsizei _stride, const GLvoid *_pointer)
replaces glNormalPointer, supports locking
Definition: GLState.cc:1940
ACG::openGLVersionTest
bool ACGDLLEXPORT openGLVersionTest(const int _major, const int _minor)
Definition: gl.hh:265
ACG::IRenderer::addRenderObject
virtual void addRenderObject(RenderObject *_renderObject)
Callback for the scenegraph nodes, which send new render objects via this function.
Definition: IRenderer.cc:104
ACG::VertexElement
Description of one vertex element.
Definition: VertexDeclaration.hh:78
ACG::MeshCompiler::getIndex
int getIndex(int _i) const
Definition: MeshCompiler.cc:3035
OpenMesh::PropertyT::data
const T * data() const
Get pointer to array (does not work for T==bool)
Definition: Property.hh:169
OpenMesh::HPropHandleT
Definition: Property.hh:496
ACG::GLState::bindBufferARB
static void bindBufferARB(GLenum _target, GLuint _buffer)
same function as bindBuffer
Definition: GLState.hh:573
ACG::MeshCompiler::Subset
Definition: MeshCompiler.hh:448
ACG::GLState::vertexPointer
static void vertexPointer(GLint _size, GLenum _type, GLsizei _stride, const GLvoid *_pointer)
replaces glVertexPointer, supports locking
Definition: GLState.cc:1918
ACG::DrawMeshFaceInput::getVertexAdjCount
int getVertexAdjCount(const int _vertexID) const
Definition: DrawMeshT_impl.hh:370
ACG::RenderObject::shaderDesc
ShaderGenDesc shaderDesc
Drawmode and other shader params.
Definition: RenderObject.hh:225
OpenMesh::PolyMeshT::FaceHalfedgeIter
Kernel::FaceHalfedgeIter FaceHalfedgeIter
Circulator.
Definition: PolyMeshT.hh:168
ACG::DrawMeshFaceInput::getSingleFaceAttr
int getSingleFaceAttr(const int _faceID, const int _faceCorner, const int _attrID) const
Definition: DrawMeshT_impl.hh:279
ACG::RenderObject::indexBuffer
GLuint indexBuffer
Use vertex array object.
Definition: RenderObject.hh:162
OpenMesh::VectorT
Definition: Vector11T.hh:83
ACG::RenderObject::Texture
Texture to be used.
Definition: RenderObject.hh:313
ACG::RenderObject::indexType
GLenum indexType
Index element type.
Definition: RenderObject.hh:197
ACG::GLState::bindBuffer
static void bindBuffer(GLenum _target, GLuint _buffer)
replaces glBindBuffer, supports locking
Definition: GLState.cc:1820
ACG::DrawMeshT::updateEdgeHalfedgeVertexDeclarations
void updateEdgeHalfedgeVertexDeclarations()
updates per edge and halfedge vertex declarations
Definition: DrawMeshT_impl.hh:2425
OpenMesh::BaseProperty
Definition: BaseProperty.hh:60
ACG::IRenderer
Definition: IRenderer.hh:78
ACG::VERTEX_USAGE_NORMAL
"inNormal"
Definition: VertexDeclaration.hh:66
ACG::DrawMeshT::supportsPickingEdges_opt
bool supportsPickingEdges_opt()
Check if optimized face picking is supported.
Definition: DrawMeshT_impl.hh:1946
ACG::VertexElement::getByteOffset
unsigned int getByteOffset() const
Definition: VertexDeclaration.cc:77
ACG::VERTEX_USAGE_POSITION
"inPosition"
Definition: VertexDeclaration.hh:65
ACG::DrawMeshFaceInput::getFaceSize
int getFaceSize(const int _faceID) const
Definition: DrawMeshT_impl.hh:267
ACG::GLState::enableClientState
static void enableClientState(GLenum _cap)
replaces glEnableClientState, supports locking
Definition: GLState.cc:1570
ACG::RenderObject::vertexDecl
const VertexDeclaration * vertexDecl
Defines the vertex buffer layout, ignored if VAO is provided.
Definition: RenderObject.hh:208
ACG::MeshCompilerFaceInput
Definition: MeshCompiler.hh:128
ACG::DrawMeshT
Mesh Drawing Class.
Definition: DrawMesh.hh:173
ACG::DrawMeshFaceInput::getVertexAdjFace
int getVertexAdjFace(const int _vertexID, const int _k) const
Definition: DrawMeshT_impl.hh:384
OpenMesh::FPropHandleT
Definition: Property.hh:524
ACG::VERTEX_USAGE_TEXCOORD
"inTexCoord"
Definition: VertexDeclaration.hh:67
ACG::DrawMeshFaceInput::getNumIndices
int getNumIndices() const
Definition: DrawMeshT_impl.hh:262
ACG::GLState::bindTexture
static void bindTexture(GLenum _target, GLuint _buffer)
replaces glBindTexture, supports locking
Definition: GLState.cc:1868
ACG::DrawMeshT::supportsPickingAny_opt
bool supportsPickingAny_opt()
Check if optimized any picking is supported.
Definition: DrawMeshT_impl.hh:2247