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;
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>
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
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 
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
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
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
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
889 {
890  return getTextureIDofFace(meshComp_->mapToOriginalFaceID(_tri));
891 }
892 
893 
894 template <class Mesh>
895 void
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
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>
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>
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>
1270 {
1271  updateGPUBuffers();
1272  return vbo_;
1273 }
1274 
1275 template <class Mesh>
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>
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>
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>
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  {
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 
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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)>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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
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
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>
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
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
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>
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>
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>
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>
2739 {
2740  updateFullVBO_ = true;
2741 }
2742 
2743 
2744 template <class Mesh>
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 }
Namespace providing different geometric functions concerning angles.
static void texcoordPointer(GLint _size, GLenum _type, GLsizei _stride, const GLvoid *_pointer)
replaces glTexcoordPointer, supports locking
Definition: GLState.cc:1984
Class to define the vertex input layout.
void addTexture(const Texture &_t)
adds a texture to stage RenderObjects::numTextures()
unsigned int getMemoryUsage(bool _printReport=false)
measures the size in bytes of allocated memory. eventually prints a report to std::cout ...
void invalidateFullVBO()
the mesh has been changed
void addVertexElement(const std::string &_propertyName, PropertySource _source=PROPERTY_SOURCE_VERTEX)
Add custom elements to the vertex layout.
void addTriRenderObjects(IRenderer *_renderer, const RenderObject *_baseObj, std::map< int, GLuint > *_textureMap, bool _nonindexed=false)
adds RenderObjects to a deferred draw call renderer
bool supportsPickingFaces_opt()
Check if optimized face picking is supported.
Vec4uc pick_get_name_color(size_t _idx)
Definition: GLState.cc:1068
Kernel::Point Point
Coordinate type.
Definition: PolyMeshT.hh:112
VectorT< unsigned char, 4 > Vec4uc
Definition: VectorT.hh:128
VectorT< float, 3 > Vec3f
Definition: VectorT.hh:119
static void colorPointer(GLint _size, GLenum _type, GLsizei _stride, const GLvoid *_pointer)
replaces glColorPointer, supports locking
Definition: GLState.cc:1962
void readVertexFromVBO(unsigned int _vertex, void *_dst)
Read one vertex from the rendering vbo.
const GLenum & depthFunc() const
get glDepthFunc() that is supposed to be active
Definition: GLState.cc:941
VertexDeclaration * getVertexDeclaration()
get vertex declaration of the current vbo layout
defined by user via VertexElement::shaderInputName_
void drawPickingEdges_opt(const GLMatrixf &_mvp, size_t _pickOffset)
Optimized rendering of edge picking ids with a shader.
Kernel::ConstFaceHalfedgeIter ConstFaceHalfedgeIter
Circulator.
Definition: PolyMeshT.hh:178
bool supportsPickingVertices_opt()
Check if optimized vertex picking is supported.
Handle for a halfedge entity.
Definition: Handles.hh:127
virtual size_t n_elements() const =0
Number of elements in property.
Kernel::ConstVertexFaceIter ConstVertexFaceIter
Circulator.
Definition: PolyMeshT.hh:176
const VertexDeclaration * getVertexDeclaration() const
Scalar * data()
access to Scalar array
Definition: Vector11T.hh:195
Interface class between scenegraph and renderer.
Definition: RenderObject.hh:98
unsigned int getVertexStride(unsigned int i=0) const
void updateFullVBO()
update the full mesh vbo
void drawPickingAny_opt(const GLMatrixf &_mvp, size_t _pickOffset)
Optimized rendering of any picking ids with a shader.
bool scanVertexShaderForInput(const std::string &_vertexShaderFile)
Scan vertex layout from vertex shader.
Kernel::VertexHandle VertexHandle
Handle for referencing the corresponding item.
Definition: PolyMeshT.hh:136
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
void drawPickingFaces_opt(const GLMatrixf &_mvp, size_t _pickOffset)
Optimized rendering of face picking ids with a shader.
int getNumTriangles() const
int * getFaceAttr(const int _faceID, const int _attrID) const
void drawPickingVertices_opt(const GLMatrixf &_mvp, size_t _pickOffset)
Optimized rendering of vertex picking ids with a shader.
static void disableClientState(GLenum _cap)
replaces glDisableClientState, supports locking
Definition: GLState.cc:1584
void createVertexDeclaration()
creates all vertex declarations needed for deferred draw call renderer
VERTEX_USAGE usage_
position, normal, shader input ..
GLuint vertexBuffer
VBO, IBO ids, ignored if VAO is provided.
Default property class for any type T.
Definition: Property.hh:89
bool getFaceAttr(const int _faceID, const int _attrID, int *_out) const
static void normalPointer(GLenum _type, GLsizei _stride, const GLvoid *_pointer)
replaces glNormalPointer, supports locking
Definition: GLState.cc:1940
bool ACGDLLEXPORT openGLVersionTest(const int _major, const int _minor)
Definition: gl.hh:265
virtual void addRenderObject(RenderObject *_renderObject)
Callback for the scenegraph nodes, which send new render objects via this function.
Definition: IRenderer.cc:104
Description of one vertex element.
int getIndex(int _i) const
const T * data() const
Get pointer to array (does not work for T==bool)
Definition: Property.hh:169
static void bindBufferARB(GLenum _target, GLuint _buffer)
same function as bindBuffer
Definition: GLState.hh:573
static void vertexPointer(GLint _size, GLenum _type, GLsizei _stride, const GLvoid *_pointer)
replaces glVertexPointer, supports locking
Definition: GLState.cc:1918
int getVertexAdjCount(const int _vertexID) const
ShaderGenDesc shaderDesc
Drawmode and other shader params.
Kernel::FaceHalfedgeIter FaceHalfedgeIter
Circulator.
Definition: PolyMeshT.hh:168
int getSingleFaceAttr(const int _faceID, const int _faceCorner, const int _attrID) const
GLuint indexBuffer
Use vertex array object.
Texture to be used.
GLenum indexType
Index element type.
static void bindBuffer(GLenum _target, GLuint _buffer)
replaces glBindBuffer, supports locking
Definition: GLState.cc:1820
void updateEdgeHalfedgeVertexDeclarations()
updates per edge and halfedge vertex declarations
bool supportsPickingEdges_opt()
Check if optimized face picking is supported.
unsigned int getByteOffset() const
int getFaceSize(const int _faceID) const
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.
Mesh Drawing Class.
Definition: DrawMesh.hh:173
int getVertexAdjFace(const int _vertexID, const int _k) const
static void bindTexture(GLenum _target, GLuint _buffer)
replaces glBindTexture, supports locking
Definition: GLState.cc:1868
bool supportsPickingAny_opt()
Check if optimized any picking is supported.