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