Visualization Library 2.0.0-b5

A lightweight C++ OpenGL middleware for 2D/3D graphics

VL     Star     Watch     Fork     Issue

[Download] [Tutorials] [All Classes] [Grouped Classes]
TriStrip_tri_stripper.cpp
Go to the documentation of this file.
1 /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2  *
3  * This library is open source and may be redistributed and/or modified under
4  * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5  * (at your option) any later version. The full license is in LICENSE file
6  * included with this distribution, and on the openscenegraph.org website.
7  *
8  * This library is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * OpenSceneGraph Public License for more details.
12 */
13 // tri_stripper.cpp: implementation of the Tri Stripper class.
14 //
15 // Copyright (C) 2002 Tanguy Fautré.
16 // For conditions of distribution and use,
17 // see copyright notice in tri_stripper.h
18 //
20 
21 #include "TriStrip_tri_stripper.h"
22 
23 
24 
25 // namespace triangle_stripper
26 namespace triangle_stripper {
27 
28 
29 
30 
32 // Construction/Destruction
34 
35 
36 
38 // Members Functions
40 
41 void tri_stripper::Strip(primitives_vector * out_pPrimitivesVector)
42 {
43  // verify that the number of indices is correct
44  if (m_TriIndices.size() % 3 != 0)
46 
47  // clear possible garbage
48  m_PrimitivesVector.clear();
49  out_pPrimitivesVector->clear();
50 
51  // Initialize the triangle graph
52  InitTriGraph();
53 
54  // Initialize the triangle priority queue
55  InitTriHeap();
56 
57  // Initialize the cache simulator
58  InitCache();
59 
60  // Launch the triangle strip generator
61  Stripify();
62 
63  // Add the triangles that couldn't be stripped
64  AddLeftTriangles();
65 
66  // Free ressources
67  m_Triangles.clear();
68 
69  // Put the results into the user's vector
70  std::swap(m_PrimitivesVector, (* out_pPrimitivesVector));
71 // m_PrimitivesVector.swap(* out_pPrimitivesVector);
72 }
73 
74 
75 
76 void tri_stripper::InitTriGraph()
77 {
78  // Set up the graph size and complete the triangles data
79  // note: setsize() completely resets the graph as well as the node markers
80  m_Triangles.setsize(m_TriIndices.size() / 3);
81 
82  size_t i;
83  for (i = 0; i < m_Triangles.size(); ++i)
84  m_Triangles[i] = triangle(m_TriIndices[i * 3 + 0], m_TriIndices[i * 3 + 1], m_TriIndices[i * 3 + 2]);
85 
86  // Build the edges lookup table
87  triangle_edges TriInterface;
88  TriInterface.reserve(m_Triangles.size() * 3);
89 
90  for (i = 0; i < m_Triangles.size(); ++i) {
91  TriInterface.push_back(triangle_edge(m_Triangles[i]->A(), m_Triangles[i]->B(), i));
92  TriInterface.push_back(triangle_edge(m_Triangles[i]->B(), m_Triangles[i]->C(), i));
93  TriInterface.push_back(triangle_edge(m_Triangles[i]->C(), m_Triangles[i]->A(), i));
94  }
95 
96  // Sort the lookup table for faster searches
97  std::sort(TriInterface.begin(), TriInterface.end(), _cmp_tri_interface_lt());
98 
99  // Link neighbour triangles together using the edges lookup table
100  for (i = 0; i < m_Triangles.size(); ++i) {
101 
102  const triangle_edge EdgeBA(m_Triangles[i]->B(), m_Triangles[i]->A(), i);
103  const triangle_edge EdgeCB(m_Triangles[i]->C(), m_Triangles[i]->B(), i);
104  const triangle_edge EdgeAC(m_Triangles[i]->A(), m_Triangles[i]->C(), i);
105 
106  LinkNeighboursTri(TriInterface, EdgeBA);
107  LinkNeighboursTri(TriInterface, EdgeCB);
108  LinkNeighboursTri(TriInterface, EdgeAC);
109  }
110 }
111 
112 
113 
114 void tri_stripper::LinkNeighboursTri(const triangle_edges & TriInterface, const triangle_edge Edge)
115 {
116  typedef triangle_edges::const_iterator edge_const_it;
117 
118  // Find the first edge equal to Edge
119  edge_const_it It = std::lower_bound(TriInterface.begin(), TriInterface.end(), Edge, _cmp_tri_interface_lt());
120 
121  // See if there are any other edges that are equal
122  // (if so, it means that more than 2 triangles are sharing the same edge,
123  // which is unlikely but not impossible)
124  for (; (It != TriInterface.end()) && ((It->A() == Edge.A()) && (It->B() == Edge.B())); ++It)
125  m_Triangles.insert(Edge.TriPos(), It->TriPos());
126 
127  // Note: degenerated triangles will also point themselves as neighbour triangles
128 }
129 
130 
131 
132 void tri_stripper::InitTriHeap()
133 {
134  m_TriHeap.clear();
135  m_TriHeap.reserve(m_Triangles.size());
136 
137  // Set up the triangles priority queue
138  // The lower the number of available neighbour triangles, the higher the priority.
139  for (size_t i = 0; i < m_Triangles.size(); ++i)
140  m_TriHeap.push(triangle_degree(i, m_Triangles[i].number_of_out_arcs()));
141 
142  // Remove useless triangles
143  // (Note: we had to put all of them into the heap before to ensure coherency of the heap_array object)
144  while ((! m_TriHeap.empty()) && (m_TriHeap.top().Degree() == 0))
145  m_TriHeap.pop();
146 }
147 
148 
149 
150 void tri_stripper::InitCache()
151 {
152  m_IndicesCache.clear();
153 
154  if (m_CacheSize > 0)
155  m_IndicesCache.resize(m_CacheSize, static_cast<indice>(-1));
156 }
157 
158 
159 
160 void tri_stripper::Stripify()
161 {
162  // Reset the triangle strip id selector
163  m_StripID = 0;
164 
165  // Reset the candidate list
166  m_NextCandidates.clear();
167 
168  // Loop untill there is no available candidate triangle left
169  while (! m_TriHeap.empty()) {
170 
171  // There is no triangle in the candidates list, refill it with the loneliest triangle
172  const size_t HeapTop = m_TriHeap.top().TriPos();
173  m_NextCandidates.push_back(HeapTop);
174 
175  // Loop while BuildStrip can find good candidates for us
176  while (! m_NextCandidates.empty()) {
177 
178  // Choose the best strip containing that triangle
179  // Note: FindBestStrip empties m_NextCandidates
180  const triangle_strip TriStrip = FindBestStrip();
181 
182  // Build it if it's long enough, otherwise discard it
183  // Note: BuildStrip refills m_NextCandidates
184  if (TriStrip.Size() >= m_MinStripSize)
185  BuildStrip(TriStrip);
186  }
187 
188  // We must discard the triangle we inserted in the candidate list from the heap
189  // if it led to nothing. (We simply removed it if it hasn't been removed by BuildStrip() yet)
190  if (! m_TriHeap.removed(HeapTop))
191  m_TriHeap.erase(HeapTop);
192 
193 
194  // Eliminate all the triangles that have now become useless
195  while ((! m_TriHeap.empty()) && (m_TriHeap.top().Degree() == 0))
196  m_TriHeap.pop();
197  }
198 }
199 
200 
201 
202 triangle_strip tri_stripper::FindBestStrip()
203 {
204  triangle_strip BestStrip;
205  size_t BestStripDegree = 0;
206  size_t BestStripCacheHits = 0;
207 
208  // Backup the cache, because it'll be erased during the simulations
209  indices_cache CacheBackup = m_IndicesCache;
210 
211  while (! m_NextCandidates.empty()) {
212 
213  // Discard useless triangles from the candidates list
214  if ((m_Triangles[m_NextCandidates.back()].marked()) || (m_TriHeap[m_NextCandidates.back()].Degree() == 0)) {
215  m_NextCandidates.pop_back();
216 
217  // "continue" is evil! But it really makes things easier here.
218  // The useless triangle is discarded, and the "while" just rebegins again
219  continue;
220  }
221 
222  // Invariant: (CandidateTri's Degree() >= 1) && (CandidateTri is not marked).
223  // So it can directly be used.
224  const size_t CandidateTri = m_NextCandidates.back();
225  m_NextCandidates.pop_back();
226 
227  // Try to extend the triangle in the 3 possible directions
228  for (size_t i = 0; i < 3; ++i) {
229 
230  // Reset the cache hit count
231  m_CacheHits = 0;
232 
233  // Try a new strip with that triangle in a particular direction
234  const triangle_strip TempStrip = ExtendTriToStrip(CandidateTri, triangle_strip::start_order(i));
235 
236  // Restore the cache (modified by ExtendTriToStrip)
237  m_IndicesCache = CacheBackup;
238 
239  // We want to keep the best strip
240  // Discard strips that don't match the minimum required size
241  if (TempStrip.Size() >= m_MinStripSize) {
242 
243  // Cache simulator disabled?
244  if (m_CacheSize == 0) {
245 
246  // Cache is disabled, take the longest strip
247  if (TempStrip.Size() > BestStrip.Size())
248  BestStrip = TempStrip;
249 
250  // Cache simulator enabled
251  // Use other criteria to find the "best" strip
252  } else {
253 
254  // Priority 1: Keep the strip with the best cache hit count
255  if (m_CacheHits > BestStripCacheHits) {
256  BestStrip = TempStrip;
257  BestStripDegree = m_TriHeap[TempStrip.StartTriPos()].Degree();
258  BestStripCacheHits = m_CacheHits;
259 
260  } else if (m_CacheHits == BestStripCacheHits) {
261 
262  // Priority 2: Keep the strip with the loneliest start triangle
263  if ((BestStrip.Size() != 0) && (m_TriHeap[TempStrip.StartTriPos()].Degree() < BestStripDegree)) {
264  BestStrip = TempStrip;
265  BestStripDegree = m_TriHeap[TempStrip.StartTriPos()].Degree();
266 
267  // Priority 3: Keep the longest strip
268  } else if (TempStrip.Size() > BestStrip.Size()) {
269  BestStrip = TempStrip;
270  BestStripDegree = m_TriHeap[TempStrip.StartTriPos()].Degree();
271  }
272  }
273  }
274  }
275 
276  }
277 
278  }
279 
280  return BestStrip;
281 }
282 
283 
284 
285 triangle_strip tri_stripper::ExtendTriToStrip(const size_t StartTriPos, const triangle_strip::start_order StartOrder)
286 {
287  typedef triangles_graph::const_out_arc_iterator const_tri_link_iter;
288  typedef triangles_graph::node_iterator tri_node_iter;
289 
290  size_t Size = 1;
291  bool ClockWise = false;
292  triangle_strip::start_order Order = StartOrder;
293 
294  // Begin a new strip
295  ++m_StripID;
296 
297  // Mark the first triangle as used for this strip
298  m_Triangles[StartTriPos]->SetStripID(m_StripID);
299 
300  // Update the indice cache
301  AddTriToCache((* m_Triangles[StartTriPos]), Order);
302 
303 
304  // Loop while we can further extend the strip
305  for (tri_node_iter TriNodeIt = (m_Triangles.begin() + StartTriPos);
306  (TriNodeIt != m_Triangles.end()) && ((m_CacheSize <= 0) || ((Size + 2) < m_CacheSize));
307  ++Size) {
308 
309  // Get the triangle edge that would lead to the next triangle
310  const triangle_edge Edge = GetLatestEdge(** TriNodeIt, Order);
311 
312  // Link to a neighbour triangle
313  const_tri_link_iter LinkIt;
314  for (LinkIt = TriNodeIt->out_begin(); LinkIt != TriNodeIt->out_end(); ++LinkIt) {
315 
316  // Get the reference to the possible next triangle
317  const triangle & Tri = (** (LinkIt->terminal()));
318 
319  // Check whether it's already been used
320  if ((Tri.StripID() != m_StripID) && (! (LinkIt->terminal()->marked()))) {
321 
322  // Does the current candidate triangle match the required for the strip?
323 
324  if ((Edge.B() == Tri.A()) && (Edge.A() == Tri.B())) {
325  Order = (ClockWise) ? triangle_strip::ABC : triangle_strip::BCA;
326  AddIndiceToCache(Tri.C(), true);
327  break;
328  }
329 
330  else if ((Edge.B() == Tri.B()) && (Edge.A() == Tri.C())) {
331  Order = (ClockWise) ? triangle_strip::BCA : triangle_strip::CAB;
332  AddIndiceToCache(Tri.A(), true);
333  break;
334  }
335 
336  else if ((Edge.B() == Tri.C()) && (Edge.A() == Tri.A())) {
337  Order = (ClockWise) ? triangle_strip::CAB : triangle_strip::ABC;
338  AddIndiceToCache(Tri.B(), true);
339  break;
340  }
341  }
342  }
343 
344  // Is it the end of the strip?
345  if (LinkIt == TriNodeIt->out_end()) {
346  TriNodeIt = m_Triangles.end();
347  --Size;
348  } else {
349  TriNodeIt = LinkIt->terminal();
350 
351  // Setup for the next triangle
352  (* TriNodeIt)->SetStripID(m_StripID);
353  ClockWise = ! ClockWise;
354  }
355  }
356 
357 
358  return triangle_strip(StartTriPos, StartOrder, Size);
359 }
360 
361 
362 
363 triangle_edge tri_stripper::GetLatestEdge(const triangle & Triangle, const triangle_strip::start_order Order) const
364 {
365  switch (Order) {
366  case triangle_strip::ABC:
367  return triangle_edge(Triangle.B(), Triangle.C(), 0);
368  case triangle_strip::BCA:
369  return triangle_edge(Triangle.C(), Triangle.A(), 0);
370  case triangle_strip::CAB:
371  return triangle_edge(Triangle.A(), Triangle.B(), 0);
372  default:
373  return triangle_edge(0, 0, 0);
374  }
375 }
376 
377 
378 
379 void tri_stripper::BuildStrip(const triangle_strip TriStrip)
380 {
381  typedef triangles_graph::const_out_arc_iterator const_tri_link_iter;
382  typedef triangles_graph::node_iterator tri_node_iter;
383 
384  const size_t StartTriPos = TriStrip.StartTriPos();
385 
386  bool ClockWise = false;
387  triangle_strip::start_order Order = TriStrip.StartOrder();
388 
389  // Create a new strip
390  m_PrimitivesVector.push_back(primitives());
391  m_PrimitivesVector.back().m_Type = PT_Triangle_Strip;
392 
393  // Put the first triangle into the strip
394  AddTriToIndices((* m_Triangles[StartTriPos]), Order);
395 
396  // Mark the first triangle as used
397  MarkTriAsTaken(StartTriPos);
398 
399 
400  // Loop while we can further extend the strip
401  tri_node_iter TriNodeIt = (m_Triangles.begin() + StartTriPos);
402 
403  for (size_t Size = 1; Size < TriStrip.Size(); ++Size) {
404 
405  // Get the triangle edge that would lead to the next triangle
406  const triangle_edge Edge = GetLatestEdge(** TriNodeIt, Order);
407 
408  // Link to a neighbour triangle
409  const_tri_link_iter LinkIt;
410  for (LinkIt = TriNodeIt->out_begin(); LinkIt != TriNodeIt->out_end(); ++LinkIt) {
411 
412  // Get the reference to the possible next triangle
413  const triangle & Tri = (** (LinkIt->terminal()));
414 
415  // Check whether it's already been used
416  if (! (LinkIt->terminal()->marked())) {
417 
418  // Does the current candidate triangle match the required for the strip?
419  // If it does, then add it to the Indices
420  if ((Edge.B() == Tri.A()) && (Edge.A() == Tri.B())) {
421  Order = (ClockWise) ? triangle_strip::ABC : triangle_strip::BCA;
422  AddIndice(Tri.C());
423  break;
424  }
425 
426  else if ((Edge.B() == Tri.B()) && (Edge.A() == Tri.C())) {
427  Order = (ClockWise) ? triangle_strip::BCA : triangle_strip::CAB;
428  AddIndice(Tri.A());
429  break;
430  }
431 
432  else if ((Edge.B() == Tri.C()) && (Edge.A() == Tri.A())) {
433  Order = (ClockWise) ? triangle_strip::CAB : triangle_strip::ABC;
434  AddIndice(Tri.B());
435  break;
436  }
437  }
438  }
439 
440  // Debug check: we must have found the next triangle
441  //assert(LinkIt != TriNodeIt->out_end());
442  if (LinkIt == TriNodeIt->out_end()) throw "tri_stripper::BuildStrip(,) error, next triangle not found";
443 
444 
445  // Go to the next triangle
446  TriNodeIt = LinkIt->terminal();
447  MarkTriAsTaken(TriNodeIt - m_Triangles.begin());
448 
449  // Setup for the next triangle
450  ClockWise = ! ClockWise;
451  }
452 }
453 
454 
455 
456 void tri_stripper::MarkTriAsTaken(const size_t i)
457 {
458  typedef triangles_graph::node_iterator tri_node_iter;
459  typedef triangles_graph::out_arc_iterator tri_link_iter;
460 
461  // Mark the triangle node
462  m_Triangles[i].mark();
463 
464  // Remove triangle from priority queue if it isn't yet
465  if (! m_TriHeap.removed(i))
466  m_TriHeap.erase(i);
467 
468  // Adjust the degree of available neighbour triangles
469  for (tri_link_iter LinkIt = m_Triangles[i].out_begin(); LinkIt != m_Triangles[i].out_end(); ++LinkIt) {
470 
471  const size_t j = LinkIt->terminal() - m_Triangles.begin();
472 
473  if ((! m_Triangles[j].marked()) && (! m_TriHeap.removed(j))) {
474  triangle_degree NewDegree = m_TriHeap.peek(j);
475  NewDegree.SetDegree(NewDegree.Degree() - 1);
476  m_TriHeap.update(j, NewDegree);
477 
478  // Update the candidate list if cache is enabled
479  if ((m_CacheSize > 0) && (NewDegree.Degree() > 0))
480  m_NextCandidates.push_back(j);
481  }
482  }
483 }
484 
485 
486 
487 void tri_stripper::AddIndiceToCache(const indice i, bool CacheHitCount)
488 {
489  // Cache simulator enabled?
490  if (m_CacheSize > 0) {
491 
492  // Should we simulate the cache hits and count them?
493  if (CacheHitCount) {
494  if (std::find(m_IndicesCache.begin(), m_IndicesCache.end(), i) != m_IndicesCache.end())
495  ++m_CacheHits;
496  }
497 
498  // Manage the indices cache as a FIFO structure
499  m_IndicesCache.pop_back();
500  m_IndicesCache.push_front(i);
501  }
502 }
503 
504 
505 
506 void tri_stripper::AddIndice(const indice i)
507 {
508  // Add the indice to the current indices array
509  m_PrimitivesVector.back().m_Indices.push_back(i);
510 
511  // Run cache simulator
512  AddIndiceToCache(i);
513 }
514 
515 
516 
517 void tri_stripper::AddTriToCache(const triangle & Tri, const triangle_strip::start_order Order)
518 {
519  // Add Tri indices in the right order into the indices cache simulator.
520  // And enable the cache hit count
521  switch (Order) {
522  case triangle_strip::ABC:
523  AddIndiceToCache(Tri.A(), true);
524  AddIndiceToCache(Tri.B(), true);
525  AddIndiceToCache(Tri.C(), true);
526  return;
527  case triangle_strip::BCA:
528  AddIndiceToCache(Tri.B(), true);
529  AddIndiceToCache(Tri.C(), true);
530  AddIndiceToCache(Tri.A(), true);
531  return;
532  case triangle_strip::CAB:
533  AddIndiceToCache(Tri.C(), true);
534  AddIndiceToCache(Tri.A(), true);
535  AddIndiceToCache(Tri.B(), true);
536  return;
537  }
538 }
539 
540 
541 
542 void tri_stripper::AddTriToIndices(const triangle & Tri, const triangle_strip::start_order Order)
543 {
544  // Add Tri indices in the right order into the latest Indices vector.
545  switch (Order) {
546  case triangle_strip::ABC:
547  AddIndice(Tri.A());
548  AddIndice(Tri.B());
549  AddIndice(Tri.C());
550  return;
551  case triangle_strip::BCA:
552  AddIndice(Tri.B());
553  AddIndice(Tri.C());
554  AddIndice(Tri.A());
555  return;
556  case triangle_strip::CAB:
557  AddIndice(Tri.C());
558  AddIndice(Tri.A());
559  AddIndice(Tri.B());
560  return;
561  }
562 }
563 
564 
565 
566 void tri_stripper::AddLeftTriangles()
567 {
568  // Create the latest indices array
569  // and fill it with all the triangles that couldn't be stripped
570  primitives Primitives;
571  Primitives.m_Type = PT_Triangles;
572  m_PrimitivesVector.push_back(Primitives);
573  indices & Indices = m_PrimitivesVector.back().m_Indices;
574 
575  for (size_t i = 0; i < m_Triangles.size(); ++i)
576  if (! m_Triangles[i].marked()) {
577  Indices.push_back(m_Triangles[i]->A());
578  Indices.push_back(m_Triangles[i]->B());
579  Indices.push_back(m_Triangles[i]->C());
580  }
581 
582  // Undo if useless
583  if (Indices.size() == 0)
584  m_PrimitivesVector.pop_back();
585 }
586 
587 
588 
589 
590 } // namespace triangle_stripper
void Strip(primitive_vector *out_pPrimitivesVector)
void update(size_t i, const T &Elem)
Definition: heap_array.h:236
png_uint_32 i
Definition: png.h:2640
const T & peek(size_t i) const
Definition: heap_array.h:143
std::vector< primitives > primitives_vector