Developer Documentation
StripProcessorT_impl.hh
1 /*===========================================================================*\
2  * *
3  * OpenMesh *
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  * $Revision$ *
45  * $Date$ *
46  * *
47 \*===========================================================================*/
48 
49 //=============================================================================
50 //
51 // CLASS StripProcessorT - IMPLEMENTATION
52 //
53 //=============================================================================
54 
55 #define ACG_STRIP_PROCESSOR_C
56 
57 //== INCLUDES =================================================================
58 
59 #include <list>
60 #include <iostream>
61 
62 #include <OpenMesh/Core/Utils/color_cast.hh>
63 
64 //== NAMESPACES ===============================================================
65 
66 
67 namespace ACG {
68 namespace SceneGraph {
69 
70  //== IMPLEMENTATION ==========================================================
71 
72 template <class Mesh>
75 mesh_(_mesh),
76 stripsValid_(false),
77 updatePerEdgeBuffers_(true),
78 updatePerHalfedgeBuffers_(true),
79 updatePerFaceBuffers_(true),
80 textureIndexPropertyName_("Not Set"),
81 perFaceTextureCoordinatePropertyName_("Not Set")
82 {
83  mesh_.request_face_normals();
84 }
85 
86 template <class Mesh>
89 
90 }
91 
92 /*template <class Mesh>
93 uint
94 StripProcessorT<Mesh>::getPolyDim() {
95 
96  typename Mesh::FaceIter f_it, f_end = mesh_.faces_end();
97  typename Mesh::FaceVertexIter fv_it;
98  uint n = 0;
99 
100  for(f_it = mesh_.faces_begin(); f_it != f_end; ++f_it) {
101  uint count = 0;
102  for ( fv_it = mesh_.fv_iter(f_it); fv_it; ++fv_it ) {
103  ++count;
104  }
105 
106  if(count > n) n = count;
107  }
108 
109  return n;
110 }
111 
112 template <class Mesh>
113 uint
114 StripProcessorT<Mesh>::getFaceDimension(FaceHandle _fh) {
115  uint count = 0;
116  for ( typename Mesh::FaceVertexIter fv_it = mesh_.fv_iter(_fh); fv_it; ++fv_it )
117  ++count;
118  return count;
119 }*/
120 
121 template <class Mesh>
122 void
124 }
125 
126 template <class Mesh>
127 unsigned int
130 {
131  if ( stripsValid_)
132  return nStrips();
133 
134  // preprocess: add new properties
135  mesh_.add_property( processed_ );
136  mesh_.add_property( used_ );
137  mesh_.request_face_status();
138 
139  // build strips
140  clear();
141  buildStrips();
142 
143  // postprocess: remove properties
144  mesh_.remove_property(processed_);
145  mesh_.remove_property(used_);
146  mesh_.release_face_status();
147 
148  stripsValid_ = true;
149 
150  return nStrips();
151 }
152 
153 
154 //-----------------------------------------------------------------------------
155 
156 template <class Mesh>
157 void
160 {
161  // init faces to be un-processed and un-used
162  // deleted or hidden faces are marked processed
163  if (mesh_.has_face_status()) {
164  for (typename Mesh::FaceIter f_it=mesh_.faces_begin(); f_it != mesh_.faces_end(); ++f_it)
165  if (mesh_.status(f_it).hidden() || mesh_.status(f_it).deleted())
166  processed(f_it) = used(f_it) = true;
167  else
168  processed(f_it) = used(f_it) = false;
169  } else {
170  for (typename Mesh::FaceIter f_it=mesh_.faces_begin(); f_it != mesh_.faces_end() ; ++f_it)
171  processed(f_it) = used(f_it) = false;
172  }
173 
174  if ( mesh_.is_trimesh() ) {
176  } else {
178  }
179 
180  // In this case, we have to sort the array to have all strips with the same texture in one block (reduce texture switching)
182  std::sort(strips_.begin(),strips_.end(),&stripTextureCompare);
183  }
184 
185 }
186 
187 template <class Mesh>
188 void
191 
192  // Note: Limiting number of strips to be built to three, even for n-gons.
193 
194  std::vector<Strip> experiments; // Three strips to be built. Take longest one after all.
195  std::vector< typename Mesh::HalfedgeHandle > h; // Three halfedges to start from.
196  std::vector< FaceHandles > faces; // Lists of faces.
197  typename FaceHandles::iterator fh_it, fh_end;
198  typename Mesh::FaceIter f_it, f_end=mesh_.faces_end();
199 
200  for (f_it=mesh_.faces_begin(); true; ) {
201 
202  // find start face
203  for (; f_it != f_end; ++f_it)
204  if (!processed(f_it)) break;
205 
206  // stop if all have been processed
207  if (f_it == f_end)
208  break;
209 
210  // Number of experiments equals number of edges of the face
211  experiments.clear();
212  experiments.resize( mesh_.valence(f_it) );
213  faces.clear();
214  faces.resize(mesh_.valence(f_it));
215 
216  // Store all adjacent halfedges
217  h.clear();
218  for ( typename Mesh::FaceHalfedgeIter fhalfedge_it(mesh_,f_it); fhalfedge_it; ++fhalfedge_it )
219  h.push_back( fhalfedge_it.handle() );
220 
221  // build all strips, take best one
222  unsigned int best_length = 0;
223  unsigned int best_idx = 0;
224  for (unsigned int i = 0; i < mesh_.valence(f_it) ; ++i)
225  {
226  buildStripPolyMesh(h[i], experiments[i], faces[i]);
227  const unsigned int length = experiments[i].indexArray.size();
228  if (length > best_length) {
229  best_length = length;
230  best_idx = i;
231  }
232 
233  // unset the used flag for the following experiments
234  for (fh_it=faces[i].begin(), fh_end=faces[i].end(); fh_it!=fh_end; ++fh_it)
235  used(*fh_it) = false;
236  }
237 
238  // update processed status
239  // The processed flag indicates that the whole face has been rendered
240  fh_it = faces[best_idx].begin();
241  fh_end = faces[best_idx].end();
242  for (; fh_it!=fh_end; ++fh_it)
243  processed(*fh_it) = true;
244 
245  // add best strip to strip-list
246  strips_.push_back(experiments[best_idx]);
247  }
248 }
249 
250 template <class Mesh>
251 void
254 {
255  Strip experiments[3];
256  typename Mesh::HalfedgeHandle h[3];
257 
258  FaceHandles faces[3];
259  typename FaceHandles::iterator fh_it, fh_end;
260  typename Mesh::FaceIter f_it, f_end=mesh_.faces_end();
261 
262  for (f_it=mesh_.faces_begin(); true; )
263  {
264  // find start face
265  for (; f_it!=f_end; ++f_it)
266  if (!processed(f_it))
267  break;
268  if (f_it==f_end) break; // stop if all have been processed
269 
270 
271  // collect starting halfedges
272  h[0] = mesh_.halfedge_handle(f_it.handle());
273  h[1] = mesh_.next_halfedge_handle(h[0]);
274  h[2] = mesh_.next_halfedge_handle(h[1]);
275 
276  // build 3 strips, take best one
277  unsigned int best_length = 0;
278  unsigned int best_idx = 0;
279 
280  for (unsigned int i=0; i<3; ++i)
281  {
282  buildStripTriMesh(h[i], experiments[i], faces[i]);
283 
284  const unsigned int length = experiments[i].indexArray.size();
285  if ( length > best_length)
286  {
287  best_length = length;
288  best_idx = i;
289  }
290 
291  for (fh_it=faces[i].begin(), fh_end=faces[i].end();
292  fh_it!=fh_end; ++fh_it)
293  used(*fh_it) = false;
294  }
295 
296 
297  // update processed status
298  fh_it = faces[best_idx].begin();
299  fh_end = faces[best_idx].end();
300  for (; fh_it!=fh_end; ++fh_it)
301  processed(*fh_it) = true;
302 
303  // add best strip to strip-list
304  strips_.push_back(experiments[best_idx]);
305  }
306 }
307 
308 //-----------------------------------------------------------------------------
309 
310 
311 template <class Mesh>
312 void
314 buildStripPolyMesh(typename Mesh::HalfedgeHandle _start_hh,
315  Strip& _strip,
316  FaceHandles& _faces) {
317 
318  std::list<unsigned int> strip;
319  std::list<typename Mesh::FaceHandle > faceMap;
320  typename Mesh::FaceHandle fh;
321  typename Mesh::HalfedgeHandle hh_left, hh_right; // Keep the hh of the halfedge where we started
322 
323  // reset list
324  _faces.clear();
325 
326  // Init strip
327  strip.push_back(mesh_.from_vertex_handle(_start_hh).idx());
328  strip.push_back(mesh_.to_vertex_handle(_start_hh).idx());
329 
330  // Check if we have to take care of textures
331  // If this property is not available, we do not have texture info and will therefore
332  // skip texture handling in strip generation
333  OpenMesh::FPropHandleT< int > textureIndexProperty;
334  bool textureHandling = false;
335  if ( mesh_.get_property_handle(textureIndexProperty, textureIndexPropertyName_) ) {
336  textureHandling = true;
337  _strip.textureIndex = mesh_.property(textureIndexProperty,mesh_.face_handle(_start_hh));
338  }
339 
341 
342  // Walk along the strip: 1st direction
343  // We construct the strip by using alternating vertices
344  // of each side.
345  hh_left = hh_right = _start_hh;
346 
347  while(true) {
348 
349  // Go right
350  hh_right = mesh_.prev_halfedge_handle(hh_right);
351 
352  // Add vertex to triangle strip
353  strip.push_back(mesh_.from_vertex_handle(hh_right).idx());
354  faceMap.push_back(mesh_.face_handle(hh_right));
355 
356  // Test if we're at the very last halfedge of the polygon
357  if(mesh_.to_vertex_handle(mesh_.next_halfedge_handle(hh_left)) == mesh_.from_vertex_handle(hh_right)) {
358 
359  // Mark face as processed and used
360  fh = mesh_.face_handle(hh_left);
361  _faces.push_back(fh);
362  used(fh) = true;
363 
364  // Go over to next face via the exit halfedge
365  hh_left = hh_right = mesh_.opposite_halfedge_handle(mesh_.next_halfedge_handle(hh_left));
366 
367  // Test if polygon is convex (only for testing purposes a.t.m.)
368  convexityTest(fh);
369 
370  if(mesh_.is_boundary(hh_left)) break;
371  fh = mesh_.face_handle(hh_left);
372  if (processed(fh) || used(fh)) break;
373 
374  // texture check
375  if ( textureHandling && ( _strip.textureIndex != mesh_.property(textureIndexProperty,fh ) ) ) break;
376 
377 // continue;
378  }
379 
380  // Go left
381  hh_left = mesh_.next_halfedge_handle(hh_left);
382 
383  // Add vertex to triangle strip
384  strip.push_back(mesh_.to_vertex_handle(hh_left).idx());
385  faceMap.push_back(mesh_.face_handle(hh_left));
386 
387  // Test if we're at the very last halfedge of the polygon
388  if(mesh_.to_vertex_handle(mesh_.next_halfedge_handle(hh_left)) == mesh_.from_vertex_handle(hh_right)) {
389  // Mark face as processed and used
390  fh = mesh_.face_handle(hh_left);
391  _faces.push_back(fh);
392  used(fh) = true;
393 
394  // Go over to next face via the exit halfedge
395  hh_left = hh_right = mesh_.opposite_halfedge_handle(mesh_.next_halfedge_handle(hh_left));
396 
397  // Test if polygon is convex (only for testing purposes a.t.m.)
398  convexityTest(fh);
399 
400  if(mesh_.is_boundary(hh_left)) break;
401  fh = mesh_.face_handle(hh_left);
402  if (processed(fh) || used(fh)) break;
403 
404  // texture check
405  if ( textureHandling && ( _strip.textureIndex != mesh_.property(textureIndexProperty,fh ) ) ) break;
406 
407  }
408 
409  }
410 
411  // Be carefull with the map. As we run in the opposite direction now,
412  // we have to finish the map at the end of the strip
413 
414  // Walk along the strip: 2nd direction
415  // We construct the strip by using alternating vertices
416  // of each side.
417  hh_left = hh_right = mesh_.opposite_halfedge_handle(_start_hh);
418 
419  bool flip(false);
420  while(true) {
421  // Boundary check as the first might be at the boundary
422  if(mesh_.is_boundary(hh_left)) break;
423 
424  // Go right
425  hh_right = mesh_.prev_halfedge_handle(hh_right);
426 
427  // Add vertex to triangle strip
428  strip.push_front(mesh_.from_vertex_handle(hh_right).idx());
429  faceMap.push_front(mesh_.face_handle(hh_right));
430  flip = !flip;
431 
432  // Test if we're at the very last halfedge of the polygon
433  if(mesh_.to_vertex_handle(mesh_.next_halfedge_handle(hh_left)) == mesh_.from_vertex_handle(hh_right)) {
434 
435  // Mark face as processed and used
436  fh = mesh_.face_handle(hh_right);
437  _faces.push_back(fh);
438  used(fh) = true;
439 
440  // Go over to next face via the exit halfedge
441  hh_left = hh_right = mesh_.opposite_halfedge_handle(mesh_.next_halfedge_handle(hh_left));
442 
443  if(mesh_.is_boundary(hh_left)) break;
444  fh = mesh_.face_handle(hh_left);
445  if (processed(fh) || used(fh)) break;
446 
447  // texture check
448  if ( textureHandling && ( _strip.textureIndex != mesh_.property(textureIndexProperty,fh ) ) ) break;
449 
450  // Test if polygon is convex (only for testing purposes a.t.m.)
451  convexityTest(fh);
452 
453 // continue;
454 
455  }
456 
457  // Go left
458  hh_left = mesh_.next_halfedge_handle(hh_left);
459 
460  // Add vertex to triangle strip
461  strip.push_front( mesh_.to_vertex_handle(hh_left).idx() );
462  faceMap.push_front( mesh_.face_handle(hh_left) );
463  flip = !flip;
464 
465  // Test if we're at the very last halfedge of the polygon
466  if(mesh_.to_vertex_handle(mesh_.next_halfedge_handle(hh_left)) == mesh_.from_vertex_handle(hh_right)) {
467 
468  // Mark face as processed and used
469  fh = mesh_.face_handle(hh_right);
470  _faces.push_back(fh);
471  used(fh) = true;
472 
473  // Go over to next face via the exit halfedge
474  hh_left = hh_right = mesh_.opposite_halfedge_handle(mesh_.next_halfedge_handle(hh_left));
475 
476  if(mesh_.is_boundary(hh_left)) break;
477  fh = mesh_.face_handle(hh_left);
478  if (processed(fh) || used(fh)) break;
479 
480  // texture check
481  if ( textureHandling && ( _strip.textureIndex != mesh_.property(textureIndexProperty,fh ) ) ) break;
482 
483  // Test if polygon is convex (only for testing purposes a.t.m.)
484  convexityTest(fh);
485  }
486 
487  }
488 
489  if ( flip ) {
490  strip.push_front(strip.front());
491  faceMap.push_front(mesh_.face_handle(0));
492  }
493 
494  // Finish the map ( As this is the start of the strip now, this data will be ignored!
495  faceMap.push_front(mesh_.face_handle(0));
496  faceMap.push_front(mesh_.face_handle(0));
497 
498  // copy final strip to _strip
499  _strip.indexArray.clear();
500  _strip.indexArray.reserve(strip.size());
501  std::copy(strip.begin(), strip.end(), std::back_inserter(_strip.indexArray));
502 
503  _strip.faceMap.clear();
504  _strip.faceMap.reserve(strip.size());
505  std::copy(faceMap.begin(), faceMap.end(), std::back_inserter(_strip.faceMap));
506 }
507 
508 
509 //-----------------------------------------------------------------------------
510 
511 
512 template <class Mesh>
513 void
515 buildStripTriMesh(typename Mesh::HalfedgeHandle _start_hh,
516  Strip& _strip,
517  FaceHandles& _faces)
518 {
519  std::list<unsigned int> strip;
520  typename Mesh::HalfedgeHandle hh;
521  typename Mesh::FaceHandle fh;
522 
523  std::list<typename Mesh::FaceHandle > faceMap;
524 
525 
526  // reset face list
527  _faces.clear();
528 
529 
530  // init strip
531  strip.push_back(mesh_.from_vertex_handle(_start_hh).idx());
532  strip.push_back(mesh_.to_vertex_handle(_start_hh).idx());
533 
534  // Check if we have to take care of textures
535  // If this property is not available, we do not have texture info and will therefore
536  // skip texture handling in strip generation
537  bool textureHandling = false;
538  OpenMesh::FPropHandleT< int > textureIndexProperty;
539  if ( mesh_.get_property_handle(textureIndexProperty, textureIndexPropertyName_) ) {
540  textureHandling = true;
541  _strip.textureIndex = mesh_.property(textureIndexProperty,mesh_.face_handle(_start_hh));
542  } else {
543  // Set to no texture!
544  // This is not really necessary but cleans up for debugging
545  _strip.textureIndex = 0;
546  }
547 
549 
550  // walk along the strip: 1st direction
551  hh = mesh_.prev_halfedge_handle(mesh_.opposite_halfedge_handle(_start_hh));
552  while (1)
553  {
554  // go right
555  hh = mesh_.next_halfedge_handle(hh);
556  hh = mesh_.opposite_halfedge_handle(hh);
557  hh = mesh_.next_halfedge_handle(hh);
558  if (mesh_.is_boundary(hh)) break;
559  fh = mesh_.face_handle(hh);
560  if (processed(fh) || used(fh)) break;
561 
562  // texture check
563  if ( textureHandling && ( _strip.textureIndex != mesh_.property(textureIndexProperty,fh ) ) ) break;
564 
565  _faces.push_back(fh);
566  used(fh) = true;
567  strip.push_back(mesh_.to_vertex_handle(hh).idx());
568  faceMap.push_back(mesh_.face_handle(hh));
569 
570  // go left
571  hh = mesh_.opposite_halfedge_handle(hh);
572  hh = mesh_.next_halfedge_handle(hh);
573  if (mesh_.is_boundary(hh)) break;
574  fh = mesh_.face_handle(hh);
575  if (processed(fh) || used(fh)) break;
576 
577  // texture check
578  if ( textureHandling && ( _strip.textureIndex != mesh_.property(textureIndexProperty,fh ) ) ) break;
579 
580  _faces.push_back(fh);
581  used(fh) = true;
582  strip.push_back(mesh_.to_vertex_handle(hh).idx());
583  faceMap.push_back(mesh_.face_handle(hh));
584  }
585 
586 
587  // walk along the strip: 2nd direction
588  bool flip(false);
589  hh = mesh_.prev_halfedge_handle(_start_hh);
590  while (1)
591  {
592  // go right
593  hh = mesh_.next_halfedge_handle(hh);
594  hh = mesh_.opposite_halfedge_handle(hh);
595  hh = mesh_.next_halfedge_handle(hh);
596  if (mesh_.is_boundary(hh)) break;
597  fh = mesh_.face_handle(hh);
598  if (processed(fh) || used(fh)) break;
599 
600  // texture check
601  if ( textureHandling && ( _strip.textureIndex != mesh_.property(textureIndexProperty,fh ) ) ) break;
602 
603  _faces.push_back(fh);
604  used(fh) = true;
605  strip.push_front(mesh_.to_vertex_handle(hh).idx());
606  faceMap.push_front(mesh_.face_handle(hh));
607  flip = true;
608 
609  // go left
610  hh = mesh_.opposite_halfedge_handle(hh);
611  hh = mesh_.next_halfedge_handle(hh);
612  if (mesh_.is_boundary(hh)) break;
613  fh = mesh_.face_handle(hh);
614  if (processed(fh) || used(fh)) break;
615 
616  // texture check
617  if ( textureHandling && ( _strip.textureIndex != mesh_.property(textureIndexProperty,fh ) ) ) break;
618 
619  _faces.push_back(fh);
620  used(fh) = true;
621  strip.push_front(mesh_.to_vertex_handle(hh).idx());
622  faceMap.push_front(mesh_.face_handle(hh));
623  flip = false;
624  }
625 
626  if (flip) {
627  strip.push_front(strip.front());
628  faceMap.push_front(mesh_.face_handle(0));
629  }
630 
631  // Add two empty faces at the front. They will not be used to render anything as only the third one defines the
632  // face properties in the strip.
633  faceMap.push_front(mesh_.face_handle(0));
634  faceMap.push_front(mesh_.face_handle(0));
635 
636  // copy final strip to _strip
637  _strip.indexArray.clear();
638  _strip.indexArray.reserve(strip.size());
639  std::copy(strip.begin(), strip.end(), std::back_inserter(_strip.indexArray));
640 
641  _strip.faceMap.clear();
642  _strip.faceMap.reserve(strip.size());
643  std::copy(faceMap.begin(), faceMap.end(), std::back_inserter(_strip.faceMap));
644 }
645 
646 template <class Mesh>
647 void
649 updatePickingVertices(ACG::GLState& _state, uint _offset) {
650 
651  unsigned int idx = 0;
652 
653  // Adjust size of the color buffer to the number of vertices in the mesh
654  pickVertexColorBuf_.resize( mesh_.n_vertices() );
655 
656  // Get the right picking colors from the gl state and add them per vertex to the color buffer
657  typename Mesh::ConstVertexIter v_it(mesh_.vertices_begin()), v_end(mesh_.vertices_end());
658  for (; v_it!=v_end; ++v_it, ++idx)
659  pickVertexColorBuf_[idx] = _state.pick_get_name_color(idx + _offset);
660 }
661 
662 template <class Mesh>
663 void
665 updatePickingEdges(ACG::GLState& _state, uint _offset ) {
666 
668 
669  pickEdgeColorBuf_.resize(mesh_.n_edges() * 2);
670 
671 
672  int idx = 0;
673 
674  typename Mesh::ConstEdgeIter e_it(mesh_.edges_sbegin()), e_end(mesh_.edges_end());
675  for (; e_it!=e_end; ++e_it) {
676 
677  const Vec4uc pickColor = _state.pick_get_name_color (e_it->idx() + _offset);
678 
679  pickEdgeColorBuf_[idx] = pickColor;
680  pickEdgeColorBuf_[idx+1] = pickColor;
681 
682  idx += 2;
683  }
684 }
685 
686 template <class Mesh>
687 void
690 
691  // Make sure, the face buffers are up to date before generating the picking data!
693 
694  // Get total number of triangles
695  // Each strip has two vertices more than triangles
696  unsigned int n_faces = 0;
697  for(StripsIterator it = strips_.begin(); it != strips_.end(); ++it)
698  n_faces += (*it).indexArray.size() - 2;
699 
700  // 3 vertices per face.
701  pickFaceColorBuf_.resize(n_faces * 3);
702 
703  // Index to the current buffer position
704  unsigned int bufferIndex = 0;
705 
706  // Process all strips
707  for ( unsigned int i = 0 ; i < strips_.size() ; ++i ) {
708 
709  // The order of the vertices in the strip is alternating but as the last vertex still defines
710  // points to the associated face, we dont need to swap here!
711 
712  // process all faces in the strip
713  // The strip contains 2 faces less then number of vertices in the strip.
714  // As we need seperate faces during rendering, the strips are splitted into triangles
715  // The last vertex of each triangle defines the picking color for the last face.
716  // The handles and indices are collected during the strip generation.
717  for (unsigned int stripIndex = 2 ; stripIndex < strips_[ i ].indexArray.size() ; ++stripIndex) {
718 
719  // We have to provide a vertex color for each of the vertices as we need flat shading!
720  const Vec4uc pickColor = _state.pick_get_name_color ( strips_[ i ].faceMap[ stripIndex ].idx() );
721  pickFaceColorBuf_[ bufferIndex + 0 ] = pickColor;
722  pickFaceColorBuf_[ bufferIndex + 1 ] = pickColor;
723  pickFaceColorBuf_[ bufferIndex + 2 ] = pickColor;
724 
725  bufferIndex += 3;
726  }
727  }
728 
729 }
730 
731 template <class Mesh>
732 void
735  // Update strip information if necessary
736  stripify();
737 
738  updatePickingFaces(_state);
739  updatePickingEdges(_state,mesh_.n_faces());
740  updatePickingVertices(_state,mesh_.n_faces() + mesh_.n_edges());
741 }
742 
743 template <class Mesh>
744 void
747  // Only update buffers if they are invalid
748  if (!updatePerEdgeBuffers_)
749  return;
750 
751  perEdgeVertexBuffer_.resize(mesh_.n_edges() * 2);
752 
753  if ( mesh_.has_edge_colors() ) {
754  perEdgeColorBuffer_.resize(mesh_.n_edges() * 2);
755  } else
756  perEdgeColorBuffer_.clear();
757 
758  unsigned int idx = 0;
759 
760  typename Mesh::ConstEdgeIter e_it(mesh_.edges_sbegin()), e_end(mesh_.edges_end());
761  for (; e_it!=e_end; ++e_it) {
762 
763  perEdgeVertexBuffer_[idx] = mesh_.point(mesh_.to_vertex_handle(mesh_.halfedge_handle(e_it, 0)));
764  perEdgeVertexBuffer_[idx+1] = mesh_.point(mesh_.to_vertex_handle(mesh_.halfedge_handle(e_it, 1)));
765 
766  if ( mesh_.has_edge_colors() ) {
767  const Vec4f color = OpenMesh::color_cast<Vec4f>( mesh_.color(e_it) ) ;
768  perEdgeColorBuffer_[ idx ] = color;
769  perEdgeColorBuffer_[ idx + 1 ] = color;
770  }
771 
772  idx += 2;
773  }
774 
775  updatePerEdgeBuffers_ = false;
776 
777 }
778 
779 template <class Mesh>
780 ACG::Vec3f *
783  // Force update of the buffers if required
786  return &(perEdgeVertexBuffer_)[0];
787 }
788 
789 template <class Mesh>
790 ACG::Vec4f *
793  // Force update of the buffers if required
796  return &(perEdgeColorBuffer_)[0];
797 }
798 
799 
800 template <class Mesh>
801 void
804  // Only update buffers if they are invalid
806  return;
807 
808  perHalfedgeVertexBuffer_.resize(mesh_.n_halfedges() * 2);
809 
810  if ( mesh_.has_halfedge_colors() ) {
811  perHalfedgeColorBuffer_.resize(mesh_.n_halfedges() * 2);
812  } else
813  perHalfedgeColorBuffer_.clear();
814 
815  unsigned int idx = 0;
816 
817  typename Mesh::ConstHalfedgeIter he_it(mesh_.halfedges_sbegin()), he_end(mesh_.halfedges_end());
818  for (; he_it!=he_end; ++he_it) {
819 
821  perHalfedgeVertexBuffer_[idx+1] = halfedge_point(mesh_.prev_halfedge_handle(he_it));
822 
823  if ( mesh_.has_halfedge_colors() ) {
824  const Vec4f color = OpenMesh::color_cast<Vec4f>( mesh_.color(he_it) ) ;
825  perHalfedgeColorBuffer_[ idx ] = color;
826  perHalfedgeColorBuffer_[ idx + 1 ] = color;
827  }
828 
829  idx += 2;
830  }
831 
833 
834 }
835 
836 template <class Mesh>
837 typename Mesh::Point
839 halfedge_point(const typename Mesh::HalfedgeHandle _heh) {
840 
841  typename Mesh::Point p = mesh_.point(mesh_.to_vertex_handle (_heh));
842  typename Mesh::Point pp = mesh_.point(mesh_.from_vertex_handle(_heh));
843  typename Mesh::Point pn = mesh_.point(mesh_.to_vertex_handle(mesh_.next_halfedge_handle(_heh)));
844 
845  // typename Mesh::Point n = (p-pp)%(pn-p);
846  typename Mesh::Point fn;
847  if( !mesh_.is_boundary(_heh))
848  fn = mesh_.normal(mesh_.face_handle(_heh));
849  else
850  fn = mesh_.normal(mesh_.face_handle(mesh_.opposite_halfedge_handle(_heh)));
851 
852  typename Mesh::Point upd = ((fn%(pn-p)).normalize() + (fn%(p-pp)).normalize()).normalize();
853 
854  upd *= ((pn-p).norm()+(p-pp).norm())*0.08;
855 
856  return (p+upd);
857 
858  // double alpha = 0.1;
859  // // correct weighting for concave triangles (or at concave boundaries)
860  // if( (fn | n) < 0.0) alpha *=-1.0;
861 
862  // return (p*(1.0-2.0*alpha) + pp*alpha + pn*alpha);
863 }
864 
865 template <class Mesh>
866 ACG::Vec3f *
869  // Force update of the buffers if required
872  return &(perHalfedgeVertexBuffer_)[0];
873 }
874 
875 template <class Mesh>
876 ACG::Vec4f *
879  // Force update of the buffers if required
882  return &(perHalfedgeColorBuffer_)[0];
883 }
884 
885 template <class Mesh>
886 void
889 
890  stripify();
891 
892  // Only update buffers if they are invalid
893  if (!updatePerFaceBuffers_)
894  return;
895 
896 
897  // Get and Recheck property
898  OpenMesh::HPropHandleT< typename Mesh::TexCoord2D > perFaceTextureCoordinateProperty;
899  const bool usePerFaceTextureCoordinateProperty = mesh_.get_property_handle(perFaceTextureCoordinateProperty,perFaceTextureCoordinatePropertyName_);
900 
901  const bool usePerFaceTextureIndex = perFaceTextureIndexAvailable();
902 
903  unsigned int n_faces = 0;
904 
905  // For the polyMeshes we have to count the faces in all strips
906  // Each strip has two vertices more than triangles
907  for(StripsIterator it = strips_.begin(); it != strips_.end(); ++it)
908  n_faces += (*it).indexArray.size() - 2;
909 
910  // 3 vertices per face.
911  perFaceVertexBuffer_.resize(n_faces * 3);
912 
913  // Index to the current buffer position
914  unsigned int bufferIndex = 0;
915 
916  if ( mesh_.has_face_normals() )
917  perFaceNormalBuffer_.resize(n_faces * 3);
918  else
919  perFaceNormalBuffer_.clear();
920 
921  if ( mesh_.has_vertex_normals() )
922  perFacePerVertexNormalBuffer_.resize(n_faces * 3);
923  else
925 
926  if ( mesh_.has_face_colors() )
927  perFaceColorBuffer_.resize(n_faces * 3);
928  else
929  perFaceColorBuffer_.clear();
930 
931  if ( usePerFaceTextureCoordinateProperty )
932  perFaceTextureCoordArray_.resize(n_faces * 3);
933  else
934  perFaceTextureCoordArray_.clear();
935 
936  textureRenderData_.clear();
937 
938  if ( usePerFaceTextureIndex )
939  textureRenderData_.reserve( strips_.size() );
940 
941  // Process all strips
942  for ( unsigned int i = 0 ; i < strips_.size() ; ++i ) {
943 
944  // Record strip information
945  // Or store a simple strip info with texture 0
946  if ( usePerFaceTextureIndex ) {
947  textureRenderData_.push_back( TextureRenderInfo(strips_[i].textureIndex , strips_[ i ].indexArray.size() -2 ,bufferIndex) );
948  }
949 
950  // The order of the vertices in the strip is alternating so we have to alter the directions as well
951  // or we get backfacing triangles although they are frontfacing
952  bool swap = true;
953 
954  // process all faces in the strip
955  // The strip contains 2 faces less then number of vertices in the strip.
956  // As we need seperate faces during rendering, the strips are splitted into triangles
957  // The last vertex of each triangle defines the color and the normal for the last face.
958  // Handles and indices are collected during the strip generation.
959  for (unsigned int stripIndex = 2 ; stripIndex < strips_[ i ].indexArray.size() ; ++stripIndex) {
960 
961  if ( mesh_.has_face_normals() ) {
962  const Vec3d normal = mesh_.normal( strips_[ i ].faceMap[ stripIndex ] );
963  perFaceNormalBuffer_[ bufferIndex + 0 ] = normal;
964  perFaceNormalBuffer_[ bufferIndex + 1 ] = normal;
965  perFaceNormalBuffer_[ bufferIndex + 2 ] = normal;
966  }
967 
968  if ( mesh_.has_face_colors() ) {
969  const Vec4f color = OpenMesh::color_cast<Vec4f>( mesh_.color( strips_[ i ].faceMap[ stripIndex ] ) );
970  perFaceColorBuffer_[ bufferIndex + 0 ] = color;
971  perFaceColorBuffer_[ bufferIndex + 1 ] = color;
972  perFaceColorBuffer_[ bufferIndex + 2 ] = color;
973  }
974 
975  if ( swap ) {
976  // Cant render triangle strips as we need one color per face and this means duplicating vertices
977  perFaceVertexBuffer_[ bufferIndex + 0 ] = mesh_.point(mesh_.vertex_handle( strips_[ i ].indexArray[ stripIndex - 2 ] ));
978  perFaceVertexBuffer_[ bufferIndex + 1 ] = mesh_.point(mesh_.vertex_handle( strips_[ i ].indexArray[ stripIndex - 1 ] ));
979  perFaceVertexBuffer_[ bufferIndex + 2 ] = mesh_.point(mesh_.vertex_handle( strips_[ i ].indexArray[ stripIndex - 0 ] ));
980 
981  // Get the normals of all vertices at this face
982  if ( mesh_.has_vertex_normals() ) {
983  perFacePerVertexNormalBuffer_[ bufferIndex + 0 ] = mesh_.normal(mesh_.vertex_handle( strips_[ i ].indexArray[ stripIndex - 2 ] ));
984  perFacePerVertexNormalBuffer_[ bufferIndex + 1 ] = mesh_.normal(mesh_.vertex_handle( strips_[ i ].indexArray[ stripIndex - 1 ] ));
985  perFacePerVertexNormalBuffer_[ bufferIndex + 2 ] = mesh_.normal(mesh_.vertex_handle( strips_[ i ].indexArray[ stripIndex - 0 ] ));
986  }
987 
988 
989  if ( usePerFaceTextureCoordinateProperty ) {
990  typename Mesh::ConstFaceHalfedgeIter fhe_it(mesh_.cfh_iter(strips_[ i ].faceMap[ stripIndex ]));
991 
992  for ( ; fhe_it ; ++fhe_it ) {
993  typename Mesh::VertexHandle cvh = mesh_.to_vertex_handle(fhe_it);
994  Vec2f texcoord = mesh_.property(perFaceTextureCoordinateProperty,fhe_it);
995 
996  if ( mesh_.vertex_handle( strips_[ i ].indexArray[ stripIndex - 2 ] ) == cvh ) {
997  perFaceTextureCoordArray_[ bufferIndex + 0 ] = texcoord;
998  continue;
999  } else if ( mesh_.vertex_handle( strips_[ i ].indexArray[ stripIndex - 1 ] ) == cvh ) {
1000  perFaceTextureCoordArray_[ bufferIndex + 1 ] = texcoord;
1001  continue;
1002  } else if ( mesh_.vertex_handle( strips_[ i ].indexArray[ stripIndex - 0 ] ) == cvh ) {
1003  perFaceTextureCoordArray_[ bufferIndex + 2 ] = texcoord;
1004  continue;
1005  }
1006  }
1007 
1008  }
1009 
1010  swap = false;
1011  } else {
1012  // Cant render triangle strips as we need one color per face and this means duplicating vertices
1013  perFaceVertexBuffer_[ bufferIndex + 2 ] = mesh_.point(mesh_.vertex_handle( strips_[ i ].indexArray[ stripIndex - 2 ] ));
1014  perFaceVertexBuffer_[ bufferIndex + 1 ] = mesh_.point(mesh_.vertex_handle( strips_[ i ].indexArray[ stripIndex - 1 ] ));
1015  perFaceVertexBuffer_[ bufferIndex + 0 ] = mesh_.point(mesh_.vertex_handle( strips_[ i ].indexArray[ stripIndex - 0 ] ));
1016 
1017  // Get the normals of all vertices at this face
1018  if ( mesh_.has_vertex_normals() ) {
1019  perFacePerVertexNormalBuffer_[ bufferIndex + 2 ] = mesh_.normal(mesh_.vertex_handle( strips_[ i ].indexArray[ stripIndex - 2 ] ));
1020  perFacePerVertexNormalBuffer_[ bufferIndex + 1 ] = mesh_.normal(mesh_.vertex_handle( strips_[ i ].indexArray[ stripIndex - 1 ] ));
1021  perFacePerVertexNormalBuffer_[ bufferIndex + 0 ] = mesh_.normal(mesh_.vertex_handle( strips_[ i ].indexArray[ stripIndex - 0 ] ));
1022  }
1023 
1024  if ( usePerFaceTextureCoordinateProperty ) {
1025  typename Mesh::ConstFaceHalfedgeIter fhe_it(mesh_.cfh_iter(strips_[ i ].faceMap[ stripIndex ]));
1026 
1027  for ( ; fhe_it ; ++fhe_it ) {
1028  typename Mesh::VertexHandle cvh = mesh_.to_vertex_handle(fhe_it);
1029  const Vec2f texcoord = mesh_.property(perFaceTextureCoordinateProperty,fhe_it);
1030 
1031  if ( mesh_.vertex_handle( strips_[ i ].indexArray[ stripIndex - 2 ] ) == cvh ) {
1032  perFaceTextureCoordArray_[ bufferIndex + 2 ] = texcoord;
1033  continue;
1034  } else if ( mesh_.vertex_handle( strips_[ i ].indexArray[ stripIndex - 1 ] ) == cvh ) {
1035  perFaceTextureCoordArray_[ bufferIndex + 1 ] = texcoord;
1036  continue;
1037  } else if ( mesh_.vertex_handle( strips_[ i ].indexArray[ stripIndex - 0 ] ) == cvh ) {
1038  perFaceTextureCoordArray_[ bufferIndex + 0 ] = texcoord;
1039  continue;
1040  }
1041  }
1042 
1043  }
1044 
1045  swap = true;
1046  }
1047 
1048  bufferIndex += 3;
1049  }
1050  }
1051 
1052  updatePerFaceBuffers_ = false;
1053 }
1054 
1055 
1056 template <class Mesh>
1057 ACG::Vec3f *
1060 
1061  // Force update of the buffers if required
1064 
1065  return &(perFaceVertexBuffer_)[0];
1066 }
1067 
1068 template <class Mesh>
1069 ACG::Vec3f *
1072  // Force update of the buffers if required
1075 
1076  return &(perFaceNormalBuffer_)[0];
1077 }
1078 
1079 template <class Mesh>
1080 ACG::Vec3f *
1083  // Force update of the buffers if required
1086 
1087  return &(perFacePerVertexNormalBuffer_)[0];
1088 }
1089 
1090 template <class Mesh>
1091 ACG::Vec4f *
1094  // Force update of the buffers if required
1097 
1098  return &(perFaceColorBuffer_)[0];
1099 }
1100 
1101 template <class Mesh>
1102 void
1104 setPerFaceTextureCoordinatePropertyName( std::string _perFaceTextureCoordinatePropertyName ) {
1105 
1106  // Check if the given property exists
1107  OpenMesh::HPropHandleT< typename Mesh::TexCoord2D > perFaceTextureCoordinateProperty;
1108  if ( !mesh_.get_property_handle(perFaceTextureCoordinateProperty,_perFaceTextureCoordinatePropertyName) ) {
1109  std::cerr << "StripProcessor: Unable to get per face texture coordinate property named " << _perFaceTextureCoordinatePropertyName << std::endl;
1110  return;
1111  }
1112 
1113  // Remember the property name
1114  perFaceTextureCoordinatePropertyName_ = _perFaceTextureCoordinatePropertyName;
1115 
1116  // mark the buffers as invalid as we have a new per face index array
1118 }
1119 
1120 template <class Mesh>
1121 bool
1123 
1124  // We really have to recheck, as the property might get lost externally (e.g. on restores of the mesh)
1125  OpenMesh::HPropHandleT< typename Mesh::TexCoord2D > perFaceTextureCoordinateProperty;
1126  if ( !mesh_.get_property_handle(perFaceTextureCoordinateProperty, perFaceTextureCoordinatePropertyName_) ) {
1127  return false;
1128  }
1129 
1130  // Property available
1131  return true;
1132 
1133 }
1134 
1135 template <class Mesh>
1136 bool
1138 
1139  // We really have to recheck, as the property might get lost externally (e.g. on restores of the mesh)
1140  OpenMesh::FPropHandleT< int > textureIndexProperty;
1141  if ( !mesh_.get_property_handle(textureIndexProperty, textureIndexPropertyName_) ) {
1142  return false;
1143  }
1144 
1145  // Property available
1146  return true;
1147 }
1148 
1149 template <class Mesh>
1150 void
1152 setIndexPropertyName( std::string _indexPropertyName ) {
1153 
1154  // Check if the given property exists
1155  OpenMesh::FPropHandleT< int > textureIndexProperty;
1156  if ( !mesh_.get_property_handle(textureIndexProperty,_indexPropertyName) ) {
1157  std::cerr << "StripProcessor: Unable to get per face texture Index property named " << _indexPropertyName << std::endl;
1158  return;
1159  }
1160 
1161  // Remember the property name
1162  textureIndexPropertyName_ = _indexPropertyName;
1163 
1164  // mark strips as invalid ( have to be regenerated to collect texture index information)
1165  stripsValid_ = false;
1166 
1167  // mark the buffers as invalid as we have a new per face index array
1169 }
1170 
1171 //=============================================================================
1172 } // namespace SceneGraph
1173 } // namespace ACG
1174 //=============================================================================
unsigned int stripify()
Compute triangle strips, returns number of strips.
ACG::Vec3f * perFacePerVertexNormalBuffer()
get a pointer to the per face per vertex normal buffer
std::vector< unsigned int > indexArray
This array cotains the actual triangle strip used for rendering.
Namespace providing different geometric functions concerning angles.
StripsIterator begin() const
Access strips.
ACG::Vec3f * perFaceVertexBuffer()
get a pointer to the per face vertex buffer
bool stripsValid_
This flag shows if the strips have to be regenerated.
bool perFaceTextureCoordinateAvailable()
Check if per Face Texture coordinates are available.
Kernel::Point Point
Coordinate type.
Definition: PolyMeshT.hh:112
unsigned int nStrips() const
returns number of strips
std::vector< OpenMesh::FaceHandle > faceMap
This map contains for each vertex in the strips a handle to the face it closes.
void updatePickingVertices(ACG::GLState &_state, uint _offset=0)
bool updatePerHalfedgeBuffers_
This flag controls if an update is really necessary.
void buildStrips()
this method does the main work
int textureIndex
This contains the texture index used for rendering this strip.
ACG::Vec4f * perHalfedgeColorBuffer()
get a pointer to the per edge color buffer
void clear()
delete all strips
void updatePickingFaces(ACG::GLState &_state)
Call this function to update the color picking array.
void updatePerEdgeBuffers()
Update all per edge drawing buffer n The updated buffers are: per edge vertex buffer ( 2 vertices per...
std::vector< ACG::Vec3f > perFacePerVertexNormalBuffer_
Buffer holding vertices for per face rendering.
StripsIterator end() const
Access strips.
Kernel::ConstFaceHalfedgeIter ConstFaceHalfedgeIter
Circulator.
Definition: PolyMeshT.hh:178
std::vector< ACG::Vec3f > perEdgeVertexBuffer_
Per Edge vertex buffer (glLines)
void updatePickingAny(ACG::GLState &_state)
Call this function to update the color picking array.
bool perFaceTextureIndexAvailable()
Check if textureindicies are available.
void buildStripPolyMesh(typename Mesh::HalfedgeHandle _start_hh, Strip &_strip, FaceHandles &_faces)
build a strip from a given halfedge (in both directions) of a polymesh
std::vector< ACG::Vec3f > perHalfedgeVertexBuffer_
Per Edge vertex buffer (glLines)
void updatePerHalfedgeBuffers()
Update all per edge drawing buffer n The updated buffers are: per edge vertex buffer ( 2 vertices per...
std::vector< ACG::Vec4uc > pickVertexColorBuf_
The color buffer used for vertex picking.
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 buildStripsTriMesh()
This method generates strips for triangle meshes.
class for managing a single triangle strip.
StripProcessorT(Mesh &_mesh)
Default constructor.
void convexityTest(FaceHandle _fh)
Test whether face is convex.
ACG::Vec3f * perHalfedgeVertexBuffer()
get a pointer to the per edge vertex buffer
void updatePerFaceBuffers()
Update all per face buffers.
std::vector< TextureRenderInfo > textureRenderData_
Property for the per face texture index.
std::string textureIndexPropertyName_
Property for the per face texture index.
ACG::Vec4f * perEdgeColorBuffer()
get a pointer to the per edge color buffer
std::vector< ACG::Vec2f > perFaceTextureCoordArray_
Property for the per face texture index.
bool updatePerFaceBuffers_
This flag controls if an update is really necessary.
bool updatePerEdgeBuffers_
This flag controls if an update is really necessary.
void updatePickingEdges(ACG::GLState &_state, uint _offset=0)
ACG::Vec4f * perFaceColorBuffer()
get a pointer to the per face color buffer
bool stripTextureCompare(const Strip &i, const Strip &j)
Compare function for sorting Strips depending on their texture index.
std::vector< typename Mesh::FaceHandle > FaceHandles
This flag shows if the strips have to be regenerated.
std::vector< ACG::Vec4uc > pickEdgeColorBuf_
void buildStripTriMesh(typename Mesh::HalfedgeHandle _start_hh, Strip &_strip, FaceHandles &_faces)
build a strip from a given halfedge (in both directions) of a triangle mesh
ACG::Vec3f * perFaceNormalBuffer()
get a pointer to the per face normal buffer
std::vector< ACG::Vec3f > perFaceVertexBuffer_
Buffer holding vertices for per face rendering.
Kernel::FaceHalfedgeIter FaceHalfedgeIter
Circulator.
Definition: PolyMeshT.hh:168
std::vector< ACG::Vec4uc > pickFaceColorBuf_
Call this function to update the color picking array.
ACG::Vec3f * perEdgeVertexBuffer()
get a pointer to the per edge vertex buffer
std::vector< ACG::Vec3f > perFaceNormalBuffer_
Buffer holding vertices for per face rendering.
std::vector< ACG::Vec4f > perHalfedgeColorBuffer_
Per Edge color buffer.
void setIndexPropertyName(std::string _indexPropertyName)
set the name of the property used for texture index specification
void setPerFaceTextureCoordinatePropertyName(std::string _perFaceTextureCoordinatePropertyName)
set the name of the property used for texture coordinate
Mesh::Point halfedge_point(const typename Mesh::HalfedgeHandle _heh)
compute halfedge point compute visulization point for halfedge (shifted to interior of face) ...
std::vector< ACG::Vec4f > perFaceColorBuffer_
Buffer holding vertices for per face rendering.
std::string perFaceTextureCoordinatePropertyName_
Property for the per face texture coordinates.
void invalidatePerFaceBuffers()
Update of the buffers.
std::vector< ACG::Vec4f > perEdgeColorBuffer_
Per Edge color buffer.
Vec4uc pick_get_name_color(size_t _idx)