From Tanguy Fautre and Robert Osfield, updated tristripper code to use the latest tristripper_r94 code.

This commit is contained in:
Robert Osfield
2009-12-15 12:37:49 +00:00
parent aec8c8ac10
commit 1977338cce
17 changed files with 2127 additions and 1774 deletions

View File

@@ -87,16 +87,27 @@ ADD_LIBRARY(${LIB_NAME}
Tessellator.cpp
TransformAttributeFunctor.cpp
TransformCallback.cpp
TriStrip_graph_array.h
TriStrip_heap_array.h
TriStrip_tri_stripper.cpp
TriStrip_tri_stripper.h
tristripper/include/detail/graph_array.h
tristripper/include/detail/types.h
tristripper/include/detail/cache_simulator.h
tristripper/include/detail/policy.h
tristripper/include/detail/heap_array.h
tristripper/include/detail/connectivity_graph.h
tristripper/include/tri_stripper.h
tristripper/include/public_types.h
tristripper/src/tri_stripper.cpp
tristripper/src/policy.cpp
tristripper/src/connectivity_graph.cpp
TriStripVisitor.cpp
UpdateVisitor.cpp
Version.cpp
${OPENSCENEGRAPH_VERSIONINFO_RC}
)
INCLUDE_DIRECTORIES("tristripper/include")
LINK_INTERNAL(${LIB_NAME}
osg
OpenThreads

View File

@@ -22,7 +22,7 @@
#include <map>
#include <iterator>
#include "TriStrip_tri_stripper.h"
#include "tristripper/include/tri_stripper.h"
using namespace osg;
using namespace osgUtil;
@@ -182,7 +182,7 @@ struct MyTriangleOperator
{
IndexList _remapIndices;
triangle_stripper::tri_stripper::indices _in_indices;
triangle_stripper::indices _in_indices;
inline void operator()(unsigned int p1, unsigned int p2, unsigned int p3)
{
@@ -390,7 +390,7 @@ void TriStripVisitor::stripify(Geometry& geom)
osg::notify(osg::INFO)<<"TriStripVisitor::stripify(Geometry&): doing tri strip"<< std::endl;
unsigned int in_numVertices = 0;
for(triangle_stripper::tri_stripper::indices::iterator itr=taf._in_indices.begin();
for(triangle_stripper::indices::iterator itr=taf._in_indices.begin();
itr!=taf._in_indices.end();
++itr)
{
@@ -408,19 +408,20 @@ void TriStripVisitor::stripify(Geometry& geom)
stripifier.SetCacheSize(_cacheSize);
stripifier.SetMinStripSize(_minStripSize);
triangle_stripper::tri_stripper::primitives_vector outPrimitives;
if (!stripifier.Strip(&outPrimitives))
triangle_stripper::primitive_vector outPrimitives;
stripifier.Strip(&outPrimitives);
if (outPrimitives.empty())
{
osg::notify(osg::WARN)<<"Error: TriStripVisitor::stripify(Geometry& geom) failed."<<std::endl;
return;
}
triangle_stripper::tri_stripper::primitives_vector::iterator pitr;
triangle_stripper::primitive_vector::iterator pitr;
if (_generateFourPointPrimitivesQuads)
{
osg::notify(osg::INFO)<<"Collecting all quads"<<std::endl;
typedef triangle_stripper::tri_stripper::primitives_vector::iterator prim_iterator;
typedef triangle_stripper::primitive_vector::iterator prim_iterator;
typedef std::multimap<unsigned int,prim_iterator> QuadMap;
QuadMap quadMap;
@@ -429,10 +430,10 @@ void TriStripVisitor::stripify(Geometry& geom)
pitr!=outPrimitives.end();
++pitr)
{
if (pitr->m_Indices.size()==4)
if (pitr->Indices.size()==4)
{
std::swap(pitr->m_Indices[2],pitr->m_Indices[3]);
unsigned int minValue = *(std::max_element(pitr->m_Indices.begin(),pitr->m_Indices.end()));
std::swap(pitr->Indices[2],pitr->Indices[3]);
unsigned int minValue = *(std::max_element(pitr->Indices.begin(),pitr->Indices.end()));
quadMap.insert(QuadMap::value_type(minValue,pitr));
}
}
@@ -455,13 +456,13 @@ void TriStripVisitor::stripify(Geometry& geom)
unsigned int min_pos = 0;
for(i=1;i<4;++i)
{
if (pitr->m_Indices[min_pos]>pitr->m_Indices[i])
if (pitr->Indices[min_pos]>pitr->Indices[i])
min_pos = i;
}
indices.push_back(pitr->m_Indices[min_pos]);
indices.push_back(pitr->m_Indices[(min_pos+1)%4]);
indices.push_back(pitr->m_Indices[(min_pos+2)%4]);
indices.push_back(pitr->m_Indices[(min_pos+3)%4]);
indices.push_back(pitr->Indices[min_pos]);
indices.push_back(pitr->Indices[(min_pos+1)%4]);
indices.push_back(pitr->Indices[(min_pos+2)%4]);
indices.push_back(pitr->Indices[(min_pos+3)%4]);
}
bool inOrder = true;
@@ -504,12 +505,12 @@ void TriStripVisitor::stripify(Geometry& geom)
pitr!=outPrimitives.end();
++pitr)
{
if (!_generateFourPointPrimitivesQuads || pitr->m_Indices.size()!=4)
if (!_generateFourPointPrimitivesQuads || pitr->Indices.size()!=4)
{
bool inOrder = true;
unsigned int previousValue = pitr->m_Indices.front();
for(triangle_stripper::tri_stripper::indices::iterator qi_itr=pitr->m_Indices.begin()+1;
qi_itr!=pitr->m_Indices.end() && inOrder;
unsigned int previousValue = pitr->Indices.front();
for(triangle_stripper::indices::iterator qi_itr=pitr->Indices.begin()+1;
qi_itr!=pitr->Indices.end() && inOrder;
++qi_itr)
{
inOrder = (previousValue+1)==*qi_itr;
@@ -518,23 +519,23 @@ void TriStripVisitor::stripify(Geometry& geom)
if (inOrder)
{
new_primitives.push_back(new osg::DrawArrays(pitr->m_Type,pitr->m_Indices.front(),pitr->m_Indices.size()));
new_primitives.push_back(new osg::DrawArrays(pitr->Type,pitr->Indices.front(),pitr->Indices.size()));
}
else
{
unsigned int maxValue = *(std::max_element(pitr->m_Indices.begin(),pitr->m_Indices.end()));
unsigned int maxValue = *(std::max_element(pitr->Indices.begin(),pitr->Indices.end()));
if (maxValue>=65536)
{
osg::DrawElementsUInt* elements = new osg::DrawElementsUInt(pitr->m_Type);
elements->reserve(pitr->m_Indices.size());
std::copy(pitr->m_Indices.begin(),pitr->m_Indices.end(),std::back_inserter(*elements));
osg::DrawElementsUInt* elements = new osg::DrawElementsUInt(pitr->Type);
elements->reserve(pitr->Indices.size());
std::copy(pitr->Indices.begin(),pitr->Indices.end(),std::back_inserter(*elements));
new_primitives.push_back(elements);
}
else
{
osg::DrawElementsUShort* elements = new osg::DrawElementsUShort(pitr->m_Type);
elements->reserve(pitr->m_Indices.size());
std::copy(pitr->m_Indices.begin(),pitr->m_Indices.end(),std::back_inserter(*elements));
osg::DrawElementsUShort* elements = new osg::DrawElementsUShort(pitr->Type);
elements->reserve(pitr->Indices.size());
std::copy(pitr->Indices.begin(),pitr->Indices.end(),std::back_inserter(*elements));
new_primitives.push_back(elements);
}
}

View File

@@ -1,423 +0,0 @@
// graph_array.h: interface for the graph_array class.
//
//////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002 Tanguy Fautr<74>.
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//
// Tanguy Fautr<74>
// softdev@pandora.be
//
//////////////////////////////////////////////////////////////////////
//
// Semi-dynamic directed graph
// ***************************
//
// Current version: 3.00 BETA 3 (04/12/2002)
//
// Comment: graph_array is equivalent to an array of nodes linked by
// arcs.
// This means you can't change the size (the number of nodes)
// of the graph once you created it (setsize() will delete
// any previous nodes and arcs).
// But you can add or remove arcs.
//
// History: - 3.00 BETA 3 (04/12/2002) - Added empty()
// - Changed some parameters from copy to reference
// - Fixed a bug with erase_arc
// - Un-inlined external functions
// - Added "insert_arc" which is equivalent to "insert"
// - 3.00 BETA 2 (16/11/2002) - Improved portability
// - 3.00 BETA 1 (27/08/2002) - First public release
//
//////////////////////////////////////////////////////////////////////
#ifndef TRISTRIP_GRAPH_ARRAY_H
#define TRISTRIP_GRAPH_ARRAY_H
#include <stdlib.h>
// namespace common_structures
namespace common_structures {
// graph_array main class
template <class nodetype, class arctype>
class graph_array
{
public:
class arc;
class node;
// New types
typedef size_t nodeid;
typedef typename std::vector<node>::iterator node_iterator;
typedef typename std::vector<node>::const_iterator const_node_iterator;
typedef typename std::vector<node>::reverse_iterator node_reverse_iterator;
typedef typename std::vector<node>::const_reverse_iterator const_node_reverse_iterator;
typedef graph_array<nodetype, arctype> _mytype;
// graph_array::arc class
class arc
{
public:
arc() {}
arc & mark() { m_Marker = true; return (* this); }
arc & unmark() { m_Marker = false; return (* this); }
bool marked() const { return m_Marker; }
node_iterator initial() const { return m_Initial; }
node_iterator terminal() const { return m_Terminal; }
arctype & operator * () { return m_Elem; }
const arctype & operator * () const { return m_Elem; }
protected:
friend class graph_array<nodetype, arctype>;
arc(const node_iterator & Initial, const node_iterator & Terminal)
: m_Initial(Initial), m_Terminal(Terminal), m_Marker(false) { }
arc(const node_iterator & Initial, const node_iterator & Terminal, const arctype & Elem)
: m_Initial(Initial), m_Terminal(Terminal), m_Elem(Elem), m_Marker(false) { }
node_iterator m_Initial;
node_iterator m_Terminal;
arctype m_Elem;
bool m_Marker;
};
// New types
typedef typename std::list<arc>::iterator out_arc_iterator;
typedef typename std::list<arc>::const_iterator const_out_arc_iterator;
// graph_array::node class
class node
{
public:
node & mark() { m_Marker = true; return (* this); }
node & unmark() { m_Marker = false; return (* this); }
bool marked() const { return m_Marker; }
bool out_empty() const { return m_OutArcs.empty(); }
size_t number_of_out_arcs() const { return m_OutArcs.size(); }
out_arc_iterator out_begin() { return m_OutArcs.begin(); }
out_arc_iterator out_end() { return m_OutArcs.end(); }
const_out_arc_iterator out_begin() const { return m_OutArcs.begin(); }
const_out_arc_iterator out_end() const { return m_OutArcs.end(); }
nodetype & operator * () { return m_Elem; }
nodetype * operator -> () { return &m_Elem; }
const nodetype & operator * () const { return m_Elem; }
const nodetype * operator -> () const { return &m_Elem; }
nodetype & operator = (const nodetype & Elem) { return (m_Elem = Elem); }
node() : m_Marker(false) { }
protected:
friend class graph_array<nodetype, arctype>;
friend class std::vector<node>;
std::list<arc> m_OutArcs;
nodetype m_Elem;
bool m_Marker;
};
// Construction/Destruction
graph_array();
explicit graph_array(const size_t NbNodes);
// Node related member functions
void clear();
bool empty() const;
void setsize(const size_t NbNodes);
size_t size() const;
node & operator [] (const nodeid & i);
const node & operator [] (const nodeid & i) const;
node_iterator begin();
node_iterator end();
const_node_iterator begin() const;
const_node_iterator end() const;
node_reverse_iterator rbegin();
node_reverse_iterator rend();
const_node_reverse_iterator rbegin() const;
const_node_reverse_iterator rend() const;
// Arc related member functions
size_t number_of_arcs() const;
void erase_arcs();
void erase_arcs(const node_iterator & Initial);
out_arc_iterator erase_arc(const out_arc_iterator & Pos);
out_arc_iterator insert_arc(const nodeid & Initial, const nodeid & Terminal);
out_arc_iterator insert_arc(const nodeid & Initial, const nodeid & Terminal, const arctype & Elem);
out_arc_iterator insert_arc(const node_iterator & Initial, const node_iterator & Terminal);
out_arc_iterator insert_arc(const node_iterator & Initial, const node_iterator & Terminal, const arctype & Elem);
// Another interface for insert_arc
out_arc_iterator insert(const nodeid & Initial, const nodeid & Terminal) { return insert_arc(Initial, Terminal); }
out_arc_iterator insert(const nodeid & Initial, const nodeid & Terminal, const arctype & Elem) { return insert_arc(Initial, Terminal, Elem); }
out_arc_iterator insert(const node_iterator & Initial, const node_iterator & Terminal) { return insert_arc(Initial, Terminal); }
out_arc_iterator insert(const node_iterator & Initial, const node_iterator & Terminal, const arctype & Elem) { return insert_arc(Initial, Terminal, Elem); }
// Optimized (overloaded) functions
void swap(_mytype & Right);
// removed since it was causing g++ 2.95.3 to produce many compile errors
// presumably due to implicit import of the std::swap implementation.
// Robert Osfield, Jan 2002.
// friend void swap(_mytype & Left, _mytype & Right) { Left.swap(Right); }
protected:
graph_array& operator = (const graph_array&) { return *this; }
size_t m_NbArcs;
std::vector<node> m_Nodes;
};
// Additional "low level", graph related, functions
template <class nodetype, class arctype>
void unmark_nodes(graph_array<nodetype, arctype> & G);
template <class nodetype, class arctype>
void unmark_arcs_from_node(typename graph_array<nodetype, arctype>::node & N);
template <class nodetype, class arctype>
void unmark_arcs(graph_array<nodetype, arctype> & G);
//////////////////////////////////////////////////////////////////////////
// graph_array Inline functions
//////////////////////////////////////////////////////////////////////////
template <class nodetype, class arctype>
inline graph_array<nodetype, arctype>::graph_array() : m_NbArcs(0) { }
template <class nodetype, class arctype>
inline graph_array<nodetype, arctype>::graph_array(const size_t NbNodes) : m_NbArcs(0), m_Nodes(NbNodes) { }
template <class nodetype, class arctype>
inline void graph_array<nodetype, arctype>::clear() {
m_NbArcs = 0;
m_Nodes.clear();
}
template <class nodetype, class arctype>
inline bool graph_array<nodetype, arctype>::empty() const {
return m_Nodes.empty();
}
template <class nodetype, class arctype>
inline size_t graph_array<nodetype, arctype>::size() const {
return m_Nodes.size();
}
template <class nodetype, class arctype>
inline void graph_array<nodetype, arctype>::setsize(const size_t NbNodes) {
clear();
m_Nodes.resize(NbNodes);
}
template <class nodetype, class arctype>
inline typename graph_array<nodetype, arctype>::node & graph_array<nodetype, arctype>::operator [] (const nodeid & i) {
return m_Nodes[i];
}
template <class nodetype, class arctype>
inline const typename graph_array<nodetype, arctype>::node & graph_array<nodetype, arctype>::operator [] (const nodeid & i) const {
return m_Nodes[i];
}
template <class nodetype, class arctype>
inline typename graph_array<nodetype, arctype>::node_iterator graph_array<nodetype, arctype>::begin() {
return m_Nodes.begin();
}
template <class nodetype, class arctype>
inline typename graph_array<nodetype, arctype>::node_iterator graph_array<nodetype, arctype>::end() {
return m_Nodes.end();
}
template <class nodetype, class arctype>
inline typename graph_array<nodetype, arctype>::const_node_iterator graph_array<nodetype, arctype>::begin() const {
return m_Nodes.begin();
}
template <class nodetype, class arctype>
inline typename graph_array<nodetype, arctype>::const_node_iterator graph_array<nodetype, arctype>::end() const {
return m_Nodes.end();
}
template <class nodetype, class arctype>
inline typename graph_array<nodetype, arctype>::node_reverse_iterator graph_array<nodetype, arctype>::rbegin() {
return m_Nodes.rbegin();
}
template <class nodetype, class arctype>
inline typename graph_array<nodetype, arctype>::node_reverse_iterator graph_array<nodetype, arctype>::rend() {
return m_Nodes.rend();
}
template <class nodetype, class arctype>
inline typename graph_array<nodetype, arctype>::const_node_reverse_iterator graph_array<nodetype, arctype>::rbegin() const {
return m_Nodes.rbegin();
}
template <class nodetype, class arctype>
inline typename graph_array<nodetype, arctype>::const_node_reverse_iterator graph_array<nodetype, arctype>::rend() const {
return m_Nodes.rend();
}
template <class nodetype, class arctype>
inline size_t graph_array<nodetype, arctype>::number_of_arcs() const {
return m_NbArcs;
}
template <class nodetype, class arctype>
inline typename graph_array<nodetype, arctype>::out_arc_iterator graph_array<nodetype, arctype>::insert_arc(const nodeid & Initial, const nodeid & Terminal) {
return (insert(begin() + Initial, begin() + Terminal));
}
template <class nodetype, class arctype>
inline typename graph_array<nodetype, arctype>::out_arc_iterator graph_array<nodetype, arctype>::insert_arc(const nodeid & Initial, const nodeid & Terminal, const arctype & Elem) {
return (insert(begin() + Initial, begin() + Terminal, Elem));
}
template <class nodetype, class arctype>
inline typename graph_array<nodetype, arctype>::out_arc_iterator graph_array<nodetype, arctype>::insert_arc(const node_iterator & Initial, const node_iterator & Terminal) {
++m_NbArcs;
Initial->m_OutArcs.push_back(arc(Initial, Terminal));
return (--(Initial->m_OutArcs.end()));
}
template <class nodetype, class arctype>
inline typename graph_array<nodetype, arctype>::out_arc_iterator graph_array<nodetype, arctype>::insert_arc(const node_iterator & Initial, const node_iterator & Terminal, const arctype & Elem) {
++m_NbArcs;
Initial->m_OutArcs.push_back(arc(Initial, Terminal, Elem));
return (--(Initial->m_OutArcs.end()));
}
template <class nodetype, class arctype>
inline typename graph_array<nodetype, arctype>::out_arc_iterator graph_array<nodetype, arctype>::erase_arc(const out_arc_iterator & Pos) {
--m_NbArcs;
return (Pos->initial()->m_OutArcs.erase(Pos));
}
template <class nodetype, class arctype>
inline void graph_array<nodetype, arctype>::erase_arcs(const node_iterator & Initial) {
m_NbArcs -= (Initial->m_OutArcs.size());
Initial->m_OutArcs.clear();
}
template <class nodetype, class arctype>
inline void graph_array<nodetype, arctype>::erase_arcs() {
m_NbArcs = 0;
for (nodeid i = 0; i < this->Size(); ++i)
m_Nodes[i].m_OutArcs.clear();
}
template <class nodetype, class arctype>
inline void graph_array<nodetype, arctype>::swap(_mytype & Right) {
std::swap(m_NbArcs, Right.m_NbArcs);
std::swap(m_Nodes, Right.m_Nodes);
}
//////////////////////////////////////////////////////////////////////////
// additional functions
//////////////////////////////////////////////////////////////////////////
template <class nodetype, class arctype>
void unmark_nodes(graph_array<nodetype, arctype> & G)
{
typedef typename graph_array<nodetype, arctype>::node_iterator node_it;
for (node_it NodeIt = G.begin(); NodeIt != G.end(); ++NodeIt)
NodeIt->unmark();
}
template <class nodetype, class arctype>
void unmark_arcs_from_node(typename graph_array<nodetype, arctype>::node & N)
{
typedef typename graph_array<nodetype, arctype>::out_arc_iterator arc_it;
for (arc_it ArcIt = N.out_begin(); ArcIt != N.out_end(); ++ArcIt)
ArcIt->unmark();
}
template <class nodetype, class arctype>
void unmark_arcs(graph_array<nodetype, arctype> & G)
{
typedef typename graph_array<nodetype, arctype>::node_iterator node_it;
for (node_it NodeIt = G.begin(); NodeIt != G.end(); ++NodeIt)
unmark_arcs_from_node(* NodeIt);
}
} // namespace common_structures
#endif

View File

@@ -1,312 +0,0 @@
// heap_array.h: interface for the heap_array class.
//
//////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002 Tanguy Fautr<74>.
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//
// Tanguy Fautr<74>
// softdev@pandora.be
//
//////////////////////////////////////////////////////////////////////
//
// Semi-dynamic indexed heap
// *************************
//
// Current version: 1.00 BETA 1 (24/10/2002)
//
// Comment: heap_array acts like a normal heap, you can push elements
// and then get the greatest one.
// However you cannot push any more element once an element
// has been removed (pop, erase, etc...).
// Elements can be modified after they've been pushed into
// the heap via their indice.
//
// History: -
//
//////////////////////////////////////////////////////////////////////
#ifndef TRISTRIP_HEAP_ARRAY_H
#define TRISTRIP_HEAP_ARRAY_H
// namespace common_structures
namespace common_structures {
template <class T, class CmpT = std::less<T> >
class heap_array
{
public:
struct heap_is_locked { };
// heap_array main interface. Pre = PreCondition, Post = PostCondition
heap_array() : m_Locked(false) { } // Post: ((size() == 0) && ! locked())
void clear(); // Post: ((size() == 0) && ! locked())
void reserve(size_t Size);
size_t size() const;
bool empty() const;
bool locked() const;
bool removed(size_t i) const; // Pre: (valid(i))
bool valid(size_t i) const;
const T & top() const; // Pre: (! empty())
const T & peek(size_t i) const; // Pre: (valid(i) && ! removed(i))
const T & operator [] (size_t i) const; // Pre: (valid(i) && ! removed(i))
size_t push(const T & Elem); // Pre: (! locked()) else throw (heap_is_locked)
void pop(); // Pre: (! empty()) Post: (locked())
void erase(size_t i); // Pre: (valid(i) && ! removed(i)) Post: (locked())
void update(size_t i, const T & Elem); // Pre: (valid(i) && ! removed(i)) Post: (locked())
protected:
struct linker {
linker(const T & Elem, size_t i) : m_Elem(Elem), m_Indice(i) { }
T m_Elem;
size_t m_Indice;
};
typedef std::vector<linker> linked_heap;
typedef std::vector<size_t> finder;
void Adjust(size_t i);
void Swap(size_t a, size_t b);
bool Less(const linker & a, const linker & b) const;
linked_heap m_Heap;
finder m_Finder;
CmpT m_Compare;
bool m_Locked;
};
//////////////////////////////////////////////////////////////////////////
// heap_indexed Inline functions
//////////////////////////////////////////////////////////////////////////
template <class T, class CmpT>
inline void heap_array<T, CmpT>::clear() {
m_Heap.clear();
m_Finder.clear();
m_Locked = false;
}
template <class T, class CmpT>
inline bool heap_array<T, CmpT>::empty() const {
return m_Heap.empty();
}
template <class T, class CmpT>
inline bool heap_array<T, CmpT>::locked() const {
return m_Locked;
}
template <class T, class CmpT>
inline void heap_array<T, CmpT>::reserve(size_t Size) {
m_Heap.reserve(Size);
m_Finder.reserve(Size);
}
template <class T, class CmpT>
inline size_t heap_array<T, CmpT>::size() const {
return m_Heap.size();
}
template <class T, class CmpT>
inline const T & heap_array<T, CmpT>::top() const {
// Debug check to ensure heap is not empty
if (empty())
{
osg::notify(osg::NOTICE)<<"TriStripVisitor:: heap_array<T, CmpT>::top() error, heap empty."<<std::endl;
}
return m_Heap.front().m_Elem;
}
template <class T, class CmpT>
inline const T & heap_array<T, CmpT>::peek(size_t i) const {
// Debug check to ensure element is still present
//assert(! removed(i));
if (removed(i))
{
osg::notify(osg::NOTICE)<<"TriStripVisitor:: heap_array<T, CmpT>::peek(size_t i) error."<<std::endl;
}
return (m_Heap[m_Finder[i]].m_Elem);
}
template <class T, class CmpT>
inline const T & heap_array<T, CmpT>::operator [] (size_t i) const {
return peek(i);
}
template <class T, class CmpT>
inline void heap_array<T, CmpT>::pop() {
m_Locked = true;
// Debug check to ensure heap is not empty
if (empty())
{
osg::notify(osg::NOTICE)<<"TriStripVisitor:: heap_array<T, CmpT>::pop() error, heap empty."<<std::endl;;
return;
}
Swap(0, size() - 1);
m_Heap.pop_back();
Adjust(0);
}
template <class T, class CmpT>
inline size_t heap_array<T, CmpT>::push(const T & Elem) {
if (m_Locked)
{
osg::notify(osg::NOTICE)<<"TriStripVisitor:: heap_array<T, CmpT>::push() heap_is_locked."<<std::endl;;
return 0;
}
size_t Id = size();
m_Finder.push_back(Id);
m_Heap.push_back(linker(Elem, Id));
Adjust(Id);
return Id;
}
template <class T, class CmpT>
inline void heap_array<T, CmpT>::erase(size_t i) {
m_Locked = true;
// Debug check to ensure element is still present
if (removed(i))
{
osg::notify(osg::NOTICE)<<"TriStripVisitor:: heap_array<T, CmpT>::erase(size_t i) error."<<std::endl;;
return;
}
size_t j = m_Finder[i];
if (j==m_Heap.size()-1)
{
m_Heap.pop_back();
}
else
{
Swap(j, size() - 1);
m_Heap.pop_back();
Adjust(j);
}
}
template <class T, class CmpT>
inline bool heap_array<T, CmpT>::removed(size_t i) const {
return (m_Finder[i] >= m_Heap.size());
}
template <class T, class CmpT>
inline bool heap_array<T, CmpT>::valid(size_t i) const {
return (i < m_Finder.size());
}
template <class T, class CmpT>
inline void heap_array<T, CmpT>::update(size_t i, const T & Elem) {
// Debug check to ensure element is still present
// assert(! removed(i));
if (removed(i))
{
osg::notify(osg::NOTICE)<<"TriStripVisitor:: heap_array<T, CmpT>::update(size_t i, const T & Elem) error."<<std::endl;;
return;
}
size_t j = m_Finder[i];
m_Heap[j].m_Elem = Elem;
Adjust(j);
}
template <class T, class CmpT>
inline void heap_array<T, CmpT>::Adjust(size_t i)
{
if (m_Heap.size()<=1) return; // nothing to swap, so just return.
size_t j;
// Check the upper part of the heap
for (j = i; (j > 0) && (Less(m_Heap[(j - 1) / 2], m_Heap[j])); j = ((j - 1) / 2))
Swap(j, (j - 1) / 2);
// Check the lower part of the heap
for (i = j; (j = 2 * i + 1) < size(); i = j) {
if ((j + 1 < size()) && (Less(m_Heap[j], m_Heap[j + 1])))
++j;
if (Less(m_Heap[j], m_Heap[i]))
return;
Swap(i, j);
}
}
template <class T, class CmpT>
inline void heap_array<T, CmpT>::Swap(size_t a, size_t b) {
std::swap(m_Heap[a], m_Heap[b]);
// use (size_t &) to get rid of a bogus compile warning
(size_t &) (m_Finder[(m_Heap[a].m_Indice)]) = a;
(size_t &) (m_Finder[(m_Heap[b].m_Indice)]) = b;
}
template <class T, class CmpT>
inline bool heap_array<T, CmpT>::Less(const linker & a, const linker & b) const {
return m_Compare(a.m_Elem, b.m_Elem);
}
} // namespace common_structures
#endif

View File

@@ -1,607 +0,0 @@
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*/
// tri_stripper.cpp: implementation of the Tri Stripper class.
//
// Copyright (C) 2002 Tanguy Fautr<74>.
// For conditions of distribution and use,
// see copyright notice in tri_stripper.h
//
//////////////////////////////////////////////////////////////////////
#include <osg/Notify>
#include "TriStrip_tri_stripper.h"
// namespace triangle_stripper
namespace triangle_stripper {
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// Members Functions
//////////////////////////////////////////////////////////////////////
bool tri_stripper::Strip(primitives_vector * out_pPrimitivesVector)
{
// verify that the number of indices is correct
if (m_TriIndices.size() % 3 != 0)
{
osg::notify(osg::NOTICE)<<"Warning: tri_stripper::Strip(..) invalid number of triangle indices."<<std::endl;
return false;
}
// clear possible garbage
m_PrimitivesVector.clear();
out_pPrimitivesVector->clear();
// Initialize the triangle graph
InitTriGraph();
// Initialize the triangle priority queue
InitTriHeap();
// Initialize the cache simulator
InitCache();
// Launch the triangle strip generator
if (!Stripify())
{
return false;
}
// Add the triangles that couldn't be stripped
AddLeftTriangles();
// Free ressources
m_Triangles.clear();
// Put the results into the user's vector
std::swap(m_PrimitivesVector, (* out_pPrimitivesVector));
// m_PrimitivesVector.swap(* out_pPrimitivesVector);
return true;
}
void tri_stripper::InitTriGraph()
{
// Set up the graph size and complete the triangles data
// note: setsize() completely resets the graph as well as the node markers
m_Triangles.setsize(m_TriIndices.size() / 3);
size_t i;
for (i = 0; i < m_Triangles.size(); ++i)
m_Triangles[i] = triangle(m_TriIndices[i * 3 + 0], m_TriIndices[i * 3 + 1], m_TriIndices[i * 3 + 2]);
// Build the edges lookup table
triangle_edges TriInterface;
TriInterface.reserve(m_Triangles.size() * 3);
for (i = 0; i < m_Triangles.size(); ++i) {
TriInterface.push_back(triangle_edge(m_Triangles[i]->A(), m_Triangles[i]->B(), i));
TriInterface.push_back(triangle_edge(m_Triangles[i]->B(), m_Triangles[i]->C(), i));
TriInterface.push_back(triangle_edge(m_Triangles[i]->C(), m_Triangles[i]->A(), i));
}
// Sort the lookup table for faster searches
std::sort(TriInterface.begin(), TriInterface.end(), _cmp_tri_interface_lt());
// Link neighbour triangles together using the edges lookup table
for (i = 0; i < m_Triangles.size(); ++i) {
const triangle_edge EdgeBA(m_Triangles[i]->B(), m_Triangles[i]->A(), i);
const triangle_edge EdgeCB(m_Triangles[i]->C(), m_Triangles[i]->B(), i);
const triangle_edge EdgeAC(m_Triangles[i]->A(), m_Triangles[i]->C(), i);
LinkNeighboursTri(TriInterface, EdgeBA);
LinkNeighboursTri(TriInterface, EdgeCB);
LinkNeighboursTri(TriInterface, EdgeAC);
}
}
void tri_stripper::LinkNeighboursTri(const triangle_edges & TriInterface, const triangle_edge Edge)
{
typedef triangle_edges::const_iterator edge_const_it;
// Find the first edge equal to Edge
edge_const_it It = std::lower_bound(TriInterface.begin(), TriInterface.end(), Edge, _cmp_tri_interface_lt());
// See if there are any other edges that are equal
// (if so, it means that more than 2 triangles are sharing the same edge,
// which is unlikely but not impossible)
for (; (It != TriInterface.end()) && ((It->A() == Edge.A()) && (It->B() == Edge.B())); ++It)
m_Triangles.insert(Edge.TriPos(), It->TriPos());
// Note: degenerated triangles will also point themselves as neighbour triangles
}
void tri_stripper::InitTriHeap()
{
m_TriHeap.clear();
m_TriHeap.reserve(m_Triangles.size());
// Set up the triangles priority queue
// The lower the number of available neighbour triangles, the higher the priority.
for (size_t i = 0; i < m_Triangles.size(); ++i)
m_TriHeap.push(triangle_degree(i, m_Triangles[i].number_of_out_arcs()));
// Remove useless triangles
// (Note: we had to put all of them into the heap before to ensure coherency of the heap_array object)
while ((! m_TriHeap.empty()) && (m_TriHeap.top().Degree() == 0))
m_TriHeap.pop();
}
void tri_stripper::InitCache()
{
m_IndicesCache.clear();
if (m_CacheSize > 0)
m_IndicesCache.resize(m_CacheSize, static_cast<indice>(-1));
}
bool tri_stripper::Stripify()
{
// Reset the triangle strip id selector
m_StripID = 0;
// Reset the candidate list
m_NextCandidates.clear();
// Loop untill there is no available candidate triangle left
while (! m_TriHeap.empty()) {
// There is no triangle in the candidates list, refill it with the loneliest triangle
const size_t HeapTop = m_TriHeap.top().TriPos();
m_NextCandidates.push_back(HeapTop);
// Loop while BuildStrip can find good candidates for us
while (! m_NextCandidates.empty()) {
// Choose the best strip containing that triangle
// Note: FindBestStrip empties m_NextCandidates
const triangle_strip TriStrip = FindBestStrip();
// Build it if it's long enough, otherwise discard it
// Note: BuildStrip refills m_NextCandidates
if (TriStrip.Size() >= m_MinStripSize)
{
if (!BuildStrip(TriStrip)) return false;
}
}
// We must discard the triangle we inserted in the candidate list from the heap
// if it led to nothing. (We simply removed it if it hasn't been removed by BuildStrip() yet)
if (! m_TriHeap.removed(HeapTop))
m_TriHeap.erase(HeapTop);
// Eliminate all the triangles that have now become useless
while ((! m_TriHeap.empty()) && (m_TriHeap.top().Degree() == 0))
m_TriHeap.pop();
}
return true;
}
triangle_strip tri_stripper::FindBestStrip()
{
triangle_strip BestStrip;
size_t BestStripDegree = 0;
size_t BestStripCacheHits = 0;
// Backup the cache, because it'll be erased during the simulations
indices_cache CacheBackup = m_IndicesCache;
while (! m_NextCandidates.empty()) {
// Discard useless triangles from the candidates list
if ((m_Triangles[m_NextCandidates.back()].marked()) || (m_TriHeap[m_NextCandidates.back()].Degree() == 0)) {
m_NextCandidates.pop_back();
// "continue" is evil! But it really makes things easier here.
// The useless triangle is discarded, and the "while" just rebegins again
continue;
}
// Invariant: (CandidateTri's Degree() >= 1) && (CandidateTri is not marked).
// So it can directly be used.
const size_t CandidateTri = m_NextCandidates.back();
m_NextCandidates.pop_back();
// Try to extend the triangle in the 3 possible directions
for (size_t i = 0; i < 3; ++i) {
// Reset the cache hit count
m_CacheHits = 0;
// Try a new strip with that triangle in a particular direction
const triangle_strip TempStrip = ExtendTriToStrip(CandidateTri, triangle_strip::start_order(i));
// Restore the cache (modified by ExtendTriToStrip)
m_IndicesCache = CacheBackup;
// We want to keep the best strip
// Discard strips that don't match the minimum required size
if (TempStrip.Size() >= m_MinStripSize) {
// Cache simulator disabled?
if (m_CacheSize == 0) {
// Cache is disabled, take the longest strip
if (TempStrip.Size() > BestStrip.Size())
BestStrip = TempStrip;
// Cache simulator enabled
// Use other criteria to find the "best" strip
} else {
// Priority 1: Keep the strip with the best cache hit count
if (m_CacheHits > BestStripCacheHits) {
BestStrip = TempStrip;
BestStripDegree = m_TriHeap[TempStrip.StartTriPos()].Degree();
BestStripCacheHits = m_CacheHits;
} else if (m_CacheHits == BestStripCacheHits) {
// Priority 2: Keep the strip with the loneliest start triangle
if ((BestStrip.Size() != 0) && (m_TriHeap[TempStrip.StartTriPos()].Degree() < BestStripDegree)) {
BestStrip = TempStrip;
BestStripDegree = m_TriHeap[TempStrip.StartTriPos()].Degree();
// Priority 3: Keep the longest strip
} else if (TempStrip.Size() > BestStrip.Size()) {
BestStrip = TempStrip;
BestStripDegree = m_TriHeap[TempStrip.StartTriPos()].Degree();
}
}
}
}
}
}
return BestStrip;
}
triangle_strip tri_stripper::ExtendTriToStrip(const size_t StartTriPos, const triangle_strip::start_order StartOrder)
{
typedef triangles_graph::const_out_arc_iterator const_tri_link_iter;
typedef triangles_graph::node_iterator tri_node_iter;
size_t Size = 1;
bool ClockWise = false;
triangle_strip::start_order Order = StartOrder;
// Begin a new strip
++m_StripID;
// Mark the first triangle as used for this strip
m_Triangles[StartTriPos]->SetStripID(m_StripID);
// Update the indice cache
AddTriToCache((* m_Triangles[StartTriPos]), Order);
// Loop while we can further extend the strip
for (tri_node_iter TriNodeIt = (m_Triangles.begin() + StartTriPos);
(TriNodeIt != m_Triangles.end()) && ((m_CacheSize <= 0) || ((Size + 2) < m_CacheSize));
++Size) {
// Get the triangle edge that would lead to the next triangle
const triangle_edge Edge = GetLatestEdge(** TriNodeIt, Order);
// Link to a neighbour triangle
const_tri_link_iter LinkIt;
for (LinkIt = TriNodeIt->out_begin(); LinkIt != TriNodeIt->out_end(); ++LinkIt) {
// Get the reference to the possible next triangle
const triangle & Tri = (** (LinkIt->terminal()));
// Check whether it's already been used
if ((Tri.StripID() != m_StripID) && (! (LinkIt->terminal()->marked()))) {
// Does the current candidate triangle match the required for the strip?
if ((Edge.B() == Tri.A()) && (Edge.A() == Tri.B())) {
Order = (ClockWise) ? triangle_strip::ABC : triangle_strip::BCA;
AddIndiceToCache(Tri.C(), true);
break;
}
else if ((Edge.B() == Tri.B()) && (Edge.A() == Tri.C())) {
Order = (ClockWise) ? triangle_strip::BCA : triangle_strip::CAB;
AddIndiceToCache(Tri.A(), true);
break;
}
else if ((Edge.B() == Tri.C()) && (Edge.A() == Tri.A())) {
Order = (ClockWise) ? triangle_strip::CAB : triangle_strip::ABC;
AddIndiceToCache(Tri.B(), true);
break;
}
}
}
// Is it the end of the strip?
if (LinkIt == TriNodeIt->out_end()) {
TriNodeIt = m_Triangles.end();
--Size;
} else {
TriNodeIt = LinkIt->terminal();
// Setup for the next triangle
(* TriNodeIt)->SetStripID(m_StripID);
ClockWise = ! ClockWise;
}
}
return triangle_strip(StartTriPos, StartOrder, Size);
}
triangle_edge tri_stripper::GetLatestEdge(const triangle & Triangle, const triangle_strip::start_order Order) const
{
switch (Order) {
case triangle_strip::ABC:
return triangle_edge(Triangle.B(), Triangle.C(), 0);
case triangle_strip::BCA:
return triangle_edge(Triangle.C(), Triangle.A(), 0);
case triangle_strip::CAB:
return triangle_edge(Triangle.A(), Triangle.B(), 0);
default:
return triangle_edge(0, 0, 0);
}
}
bool tri_stripper::BuildStrip(const triangle_strip TriStrip)
{
typedef triangles_graph::const_out_arc_iterator const_tri_link_iter;
typedef triangles_graph::node_iterator tri_node_iter;
const size_t StartTriPos = TriStrip.StartTriPos();
bool ClockWise = false;
triangle_strip::start_order Order = TriStrip.StartOrder();
// Create a new strip
m_PrimitivesVector.push_back(primitives());
m_PrimitivesVector.back().m_Type = PT_Triangle_Strip;
// Put the first triangle into the strip
AddTriToIndices((* m_Triangles[StartTriPos]), Order);
// Mark the first triangle as used
MarkTriAsTaken(StartTriPos);
// Loop while we can further extend the strip
tri_node_iter TriNodeIt = (m_Triangles.begin() + StartTriPos);
for (size_t Size = 1; Size < TriStrip.Size(); ++Size) {
// Get the triangle edge that would lead to the next triangle
const triangle_edge Edge = GetLatestEdge(** TriNodeIt, Order);
// Link to a neighbour triangle
const_tri_link_iter LinkIt;
for (LinkIt = TriNodeIt->out_begin(); LinkIt != TriNodeIt->out_end(); ++LinkIt) {
// Get the reference to the possible next triangle
const triangle & Tri = (** (LinkIt->terminal()));
// Check whether it's already been used
if (! (LinkIt->terminal()->marked())) {
// Does the current candidate triangle match the required for the strip?
// If it does, then add it to the Indices
if ((Edge.B() == Tri.A()) && (Edge.A() == Tri.B())) {
Order = (ClockWise) ? triangle_strip::ABC : triangle_strip::BCA;
AddIndice(Tri.C());
break;
}
else if ((Edge.B() == Tri.B()) && (Edge.A() == Tri.C())) {
Order = (ClockWise) ? triangle_strip::BCA : triangle_strip::CAB;
AddIndice(Tri.A());
break;
}
else if ((Edge.B() == Tri.C()) && (Edge.A() == Tri.A())) {
Order = (ClockWise) ? triangle_strip::CAB : triangle_strip::ABC;
AddIndice(Tri.B());
break;
}
}
}
// Debug check: we must have found the next triangle
//assert(LinkIt != TriNodeIt->out_end());
if (LinkIt == TriNodeIt->out_end())
{
osg::notify(osg::NOTICE)<<"Warning: tri_stripper::BuildStrip(,) error, next triangle not found."<<std::endl;
return false;
}
// Go to the next triangle
TriNodeIt = LinkIt->terminal();
MarkTriAsTaken(TriNodeIt - m_Triangles.begin());
// Setup for the next triangle
ClockWise = ! ClockWise;
}
return true;
}
void tri_stripper::MarkTriAsTaken(const size_t i)
{
typedef triangles_graph::node_iterator tri_node_iter;
typedef triangles_graph::out_arc_iterator tri_link_iter;
// Mark the triangle node
m_Triangles[i].mark();
// Remove triangle from priority queue if it isn't yet
if (! m_TriHeap.removed(i))
m_TriHeap.erase(i);
// Adjust the degree of available neighbour triangles
for (tri_link_iter LinkIt = m_Triangles[i].out_begin(); LinkIt != m_Triangles[i].out_end(); ++LinkIt) {
const size_t j = LinkIt->terminal() - m_Triangles.begin();
if ((! m_Triangles[j].marked()) && (! m_TriHeap.removed(j))) {
triangle_degree NewDegree = m_TriHeap.peek(j);
NewDegree.SetDegree(NewDegree.Degree() - 1);
m_TriHeap.update(j, NewDegree);
// Update the candidate list if cache is enabled
if ((m_CacheSize > 0) && (NewDegree.Degree() > 0))
m_NextCandidates.push_back(j);
}
}
}
void tri_stripper::AddIndiceToCache(const indice i, bool CacheHitCount)
{
// Cache simulator enabled?
if (m_CacheSize > 0) {
// Should we simulate the cache hits and count them?
if (CacheHitCount) {
if (std::find(m_IndicesCache.begin(), m_IndicesCache.end(), i) != m_IndicesCache.end())
++m_CacheHits;
}
// Manage the indices cache as a FIFO structure
m_IndicesCache.pop_back();
m_IndicesCache.push_front(i);
}
}
void tri_stripper::AddIndice(const indice i)
{
// Add the indice to the current indices array
m_PrimitivesVector.back().m_Indices.push_back(i);
// Run cache simulator
AddIndiceToCache(i);
}
void tri_stripper::AddTriToCache(const triangle & Tri, const triangle_strip::start_order Order)
{
// Add Tri indices in the right order into the indices cache simulator.
// And enable the cache hit count
switch (Order) {
case triangle_strip::ABC:
AddIndiceToCache(Tri.A(), true);
AddIndiceToCache(Tri.B(), true);
AddIndiceToCache(Tri.C(), true);
return;
case triangle_strip::BCA:
AddIndiceToCache(Tri.B(), true);
AddIndiceToCache(Tri.C(), true);
AddIndiceToCache(Tri.A(), true);
return;
case triangle_strip::CAB:
AddIndiceToCache(Tri.C(), true);
AddIndiceToCache(Tri.A(), true);
AddIndiceToCache(Tri.B(), true);
return;
}
}
void tri_stripper::AddTriToIndices(const triangle & Tri, const triangle_strip::start_order Order)
{
// Add Tri indices in the right order into the latest Indices vector.
switch (Order) {
case triangle_strip::ABC:
AddIndice(Tri.A());
AddIndice(Tri.B());
AddIndice(Tri.C());
return;
case triangle_strip::BCA:
AddIndice(Tri.B());
AddIndice(Tri.C());
AddIndice(Tri.A());
return;
case triangle_strip::CAB:
AddIndice(Tri.C());
AddIndice(Tri.A());
AddIndice(Tri.B());
return;
}
}
void tri_stripper::AddLeftTriangles()
{
// Create the latest indices array
// and fill it with all the triangles that couldn't be stripped
primitives Primitives;
Primitives.m_Type = PT_Triangles;
m_PrimitivesVector.push_back(Primitives);
indices & Indices = m_PrimitivesVector.back().m_Indices;
for (size_t i = 0; i < m_Triangles.size(); ++i)
if (! m_Triangles[i].marked()) {
Indices.push_back(m_Triangles[i]->A());
Indices.push_back(m_Triangles[i]->B());
Indices.push_back(m_Triangles[i]->C());
}
// Undo if useless
if (Indices.size() == 0)
m_PrimitivesVector.pop_back();
}
} // namespace triangle_stripper

View File

@@ -1,401 +0,0 @@
// tri_stripper.h: interface for the tri_stripper class.
//
//////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2002 Tanguy Fautr<74>.
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.eap_array.h TriStrip_tri_stripper.cpp TriStrip_tri_stripper.h
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//
// Tanguy Fautr<74>
// softdev@pandora.be
//
//////////////////////////////////////////////////////////////////////
//
// Tri Stripper
// ************
//
// Current version: 1.00 BETA 5 (10/12/2002)
//
// Comment: Triangle stripper in O(n.log(n)).
//
// Currently there are no protection against crazy values
// given via SetMinStripSize() and SetCacheSize().
// So be careful. (Min. strip size should be equal or greater
// than 2, cache size should be about 10 for GeForce 256/2
// and about 16-18 for GeForce 3/4.)
//
// History: - 1.00 BETA 5 (10/12/2002) - Fixed a bug in Stripify() that could sometimes
// cause it to go into an infinite loop.
// (thanks to Remy for the bug report)
// - 1.00 BETA 4 (18/11/2002) - Removed the dependency on OpenGL:
// modified gl_primitives to primitives,
// and gl_primitives_vector to primitives_vector;
// and added primitive_type.
// (thanks to Patrik for noticing this useless dependency)
// - 1.00 BETA 3 (18/11/2002) - Fixed a bug in LinkNeightboursTri() that could cause a crash
// (thanks to Nicolas for finding it)
// - 1.00 BETA 2 (16/11/2002) - Improved portability
// - 1.00 BETA 1 (27/10/2002) - First public release
//
//////////////////////////////////////////////////////////////////////
#ifndef TRISTRIP_TRI_STRIPPER_H
#define TRISTRIP_TRI_STRIPPER_H
// include this to supress daft VisualStudio warnings.
#include <osg/Export>
#include <algorithm>
#include <deque>
#include <list>
#include <map>
#include <string>
#include <vector>
#include <stdlib.h>
// namespace triangle_stripper
namespace triangle_stripper {
#include "TriStrip_graph_array.h"
#include "TriStrip_heap_array.h"
typedef unsigned int indice;
class triangle
{
public:
triangle();
triangle(const triangle& tri):
m_A(tri.m_A),
m_B(tri.m_B),
m_C(tri.m_C),
m_StripID(tri.m_StripID)
{
}
triangle(const indice A, const indice B, const indice C);
triangle& operator = (const triangle& tri)
{
if (&tri==this) return *this;
m_A = tri.m_A;
m_B = tri.m_B;
m_C = tri.m_C;
m_StripID = tri.m_StripID;
return *this;
}
void SetStripID(const size_t StripID);
indice A() const;
indice B() const;
indice C() const;
size_t StripID() const;
private:
indice m_A;
indice m_B;
indice m_C;
size_t m_StripID;
};
class triangle_edge
{
public:
triangle_edge(const indice A, const indice B, const size_t TriPos);
indice A() const;
indice B() const;
size_t TriPos() const;
private:
indice m_A;
indice m_B;
size_t m_TriPos;
};
class triangle_degree
{
public:
triangle_degree();
triangle_degree(const size_t TriPos, const size_t Degree);
size_t Degree() const;
size_t TriPos() const;
void SetDegree(const size_t Degree);
private:
size_t m_TriPos;
size_t m_Degree;
};
class triangle_strip
{
public:
enum start_order { ABC = 0, BCA = 1, CAB = 2 };
triangle_strip();
triangle_strip(size_t StartTriPos, start_order StartOrder, size_t Size);
size_t StartTriPos() const;
start_order StartOrder() const;
size_t Size() const;
private:
size_t m_StartTriPos;
start_order m_StartOrder;
size_t m_Size;
};
struct _cmp_tri_interface_lt
{
bool operator() (const triangle_edge & a, const triangle_edge & b) const;
};
struct _cmp_tri_degree_gt
{
bool operator () (const triangle_degree & a, const triangle_degree & b) const;
};
class tri_stripper
{
public:
// New Public types
typedef std::vector<indice> indices;
enum primitive_type {
PT_Triangles = 0x0004, // = GL_TRIANGLES
PT_Triangle_Strip = 0x0005 // = GL_TRIANGLE_STRIP
};
struct primitives
{
indices m_Indices;
primitive_type m_Type;
};
typedef std::vector<primitives> primitives_vector;
// constructor/initializer
inline tri_stripper(const indices & TriIndices);
// Settings functions
inline void SetCacheSize(const size_t CacheSize = 16); // = 0 will disable the cache optimizer
inline void SetMinStripSize(const size_t MinStripSize = 2);
// Stripper
bool Strip(primitives_vector * out_pPrimitivesVector);
private:
friend struct _cmp_tri_interface_lt;
tri_stripper& operator = (const tri_stripper&) { return *this; }
typedef common_structures::graph_array<triangle, char> triangles_graph;
typedef common_structures::heap_array<triangle_degree, _cmp_tri_degree_gt> triangles_heap;
typedef std::vector<triangle_edge> triangle_edges;
typedef std::vector<size_t> triangle_indices;
typedef std::deque<indice> indices_cache;
void InitCache();
void InitTriGraph();
void InitTriHeap();
bool Stripify();
void AddLeftTriangles();
void LinkNeighboursTri(const triangle_edges & TriInterface, const triangle_edge Edge);
void MarkTriAsTaken(const size_t i);
triangle_edge GetLatestEdge(const triangle & Triangle, const triangle_strip::start_order Order) const;
triangle_strip FindBestStrip();
triangle_strip ExtendTriToStrip(const size_t StartTriPos, const triangle_strip::start_order StartOrder);
bool BuildStrip(const triangle_strip TriStrip);
void AddIndice(const indice i);
void AddIndiceToCache(const indice i, bool CacheHitCount = false);
void AddTriToCache(const triangle & Tri, const triangle_strip::start_order Order);
void AddTriToIndices(const triangle & Tri, const triangle_strip::start_order Order);
const indices & m_TriIndices;
size_t m_MinStripSize;
size_t m_CacheSize;
primitives_vector m_PrimitivesVector;
triangles_graph m_Triangles;
triangles_heap m_TriHeap;
triangle_indices m_NextCandidates;
indices_cache m_IndicesCache;
size_t m_StripID;
size_t m_CacheHits;
};
//////////////////////////////////////////////////////////////////////////
// tri_stripper Inline functions
//////////////////////////////////////////////////////////////////////////
inline tri_stripper::tri_stripper(const indices & TriIndices) : m_TriIndices(TriIndices) {
SetCacheSize();
SetMinStripSize();
}
inline void tri_stripper::SetCacheSize(const size_t CacheSize) {
m_CacheSize = CacheSize;
}
inline void tri_stripper::SetMinStripSize(const size_t MinStripSize) {
m_MinStripSize = MinStripSize;
}
inline triangle::triangle() { }
inline triangle::triangle(const indice A, const indice B, const indice C) : m_A(A), m_B(B), m_C(C), m_StripID(0) { }
inline void triangle::SetStripID(const size_t StripID) {
m_StripID = StripID;
}
inline indice triangle::A() const {
return m_A;
}
inline indice triangle::B() const {
return m_B;
}
inline indice triangle::C() const {
return m_C;
}
inline size_t triangle::StripID() const {
return m_StripID;
}
inline triangle_edge::triangle_edge(const indice A, const indice B, const size_t TriPos) : m_A(A), m_B(B), m_TriPos(TriPos) { }
inline indice triangle_edge::A() const {
return m_A;
}
inline indice triangle_edge::B() const {
return m_B;
}
inline size_t triangle_edge::TriPos() const {
return m_TriPos;
}
inline triangle_degree::triangle_degree() { }
inline triangle_degree::triangle_degree(const size_t TriPos, const size_t Degree) : m_TriPos(TriPos), m_Degree(Degree) { }
inline size_t triangle_degree::Degree() const {
return m_Degree;
}
inline size_t triangle_degree::TriPos() const {
return m_TriPos;
}
inline void triangle_degree::SetDegree(const size_t Degree) {
m_Degree = Degree;
}
inline triangle_strip::triangle_strip() : m_StartTriPos(0), m_StartOrder(ABC), m_Size(0) { }
inline triangle_strip::triangle_strip(const size_t StartTriPos, const start_order StartOrder, const size_t Size)
: m_StartTriPos(StartTriPos), m_StartOrder(StartOrder), m_Size(Size) { }
inline size_t triangle_strip::StartTriPos() const {
return m_StartTriPos;
}
inline triangle_strip::start_order triangle_strip::StartOrder() const {
return m_StartOrder;
}
inline size_t triangle_strip::Size() const {
return m_Size;
}
inline bool _cmp_tri_interface_lt::operator() (const triangle_edge & a, const triangle_edge & b) const {
const indice A1 = a.A();
const indice B1 = a.B();
const indice A2 = b.A();
const indice B2 = b.B();
if ((A1 < A2) || ((A1 == A2) && (B1 < B2)))
return true;
else
return false;
}
inline bool _cmp_tri_degree_gt::operator () (const triangle_degree & a, const triangle_degree & b) const {
// the triangle with a smaller degree has more priority
return a.Degree() > b.Degree();
}
} // namespace triangle_stripper
#endif

View File

@@ -0,0 +1,154 @@
//
// Copyright (C) 2004 Tanguy Fautr<74>.
// For conditions of distribution and use,
// see copyright notice in tri_stripper.h
//
//////////////////////////////////////////////////////////////////////
// SVN: $Id: cache_simulator.h 93 2009-11-24 20:01:19Z gpsnoopy $
//////////////////////////////////////////////////////////////////////
#ifndef TRI_STRIPPER_HEADER_GUARD_CACHE_SIMULATOR_H
#define TRI_STRIPPER_HEADER_GUARD_CACHE_SIMULATOR_H
#include <algorithm>
#include <limits>
#include <deque>
namespace triangle_stripper {
namespace detail {
class cache_simulator
{
public:
cache_simulator();
void clear();
void resize(size_t Size);
void reset();
void push_cache_hits(bool Enabled = true);
size_t size() const;
void push(index i, bool CountCacheHit = false);
void merge(const cache_simulator & Backward, size_t PossibleOverlap);
void reset_hitcount();
size_t hitcount() const;
protected:
typedef std::deque<index> indices_deque;
indices_deque m_Cache;
size_t m_NbHits;
bool m_PushHits;
};
//////////////////////////////////////////////////////////////////////////
// cache_simulator inline functions
//////////////////////////////////////////////////////////////////////////
inline cache_simulator::cache_simulator()
: m_NbHits(0),
m_PushHits(true)
{
}
inline void cache_simulator::clear()
{
reset_hitcount();
m_Cache.clear();
}
inline void cache_simulator::resize(const size_t Size)
{
m_Cache.resize(Size, (std::numeric_limits<index>::max)());
}
inline void cache_simulator::reset()
{
std::fill(m_Cache.begin(), m_Cache.end(), (std::numeric_limits<index>::max)());
reset_hitcount();
}
inline void cache_simulator::push_cache_hits(bool Enabled)
{
m_PushHits = Enabled;
}
inline size_t cache_simulator::size() const
{
return m_Cache.size();
}
inline void cache_simulator::push(const index i, const bool CountCacheHit)
{
if (CountCacheHit || m_PushHits) {
if (std::find(m_Cache.begin(), m_Cache.end(), i) != m_Cache.end()) {
// Should we count the cache hits?
if (CountCacheHit)
++m_NbHits;
// Should we not push the index into the cache if it's a cache hit?
if (! m_PushHits)
return;
}
}
// Manage the indices cache as a FIFO structure
m_Cache.push_front(i);
m_Cache.pop_back();
}
inline void cache_simulator::merge(const cache_simulator & Backward, const size_t PossibleOverlap)
{
const size_t Overlap = (std::min)(PossibleOverlap, size());
for (size_t i = 0; i < Overlap; ++i)
push(Backward.m_Cache[i], true);
m_NbHits += Backward.m_NbHits;
}
inline void cache_simulator::reset_hitcount()
{
m_NbHits = 0;
}
inline size_t cache_simulator::hitcount() const
{
return m_NbHits;
}
} // namespace detail
} // namespace triangle_stripper
#endif // TRI_STRIPPER_HEADER_GUARD_CACHE_SIMULATOR_H

View File

@@ -0,0 +1,36 @@
//
// Copyright (C) 2004 Tanguy Fautr<74>.
// For conditions of distribution and use,
// see copyright notice in tri_stripper.h
//
//////////////////////////////////////////////////////////////////////
// SVN: $Id: connectivity_graph.h 86 2005-06-08 17:47:27Z gpsnoopy $
//////////////////////////////////////////////////////////////////////
#ifndef TRI_STRIPPER_HEADER_GUARD_CONNECTIVITY_GRAPH_H
#define TRI_STRIPPER_HEADER_GUARD_CONNECTIVITY_GRAPH_H
#include "public_types.h"
#include "graph_array.h"
#include "types.h"
namespace triangle_stripper
{
namespace detail
{
void make_connectivity_graph(graph_array<triangle> & Triangles, const indices & Indices);
}
}
#endif // TRI_STRIPPER_HEADER_GUARD_CONNECTIVITY_GRAPH_H

View File

@@ -0,0 +1,460 @@
//
// Copyright (C) 2004 Tanguy Fautr<74>.
// For conditions of distribution and use,
// see copyright notice in tri_stripper.h
//
//////////////////////////////////////////////////////////////////////
// SVN: $Id: graph_array.h 93 2009-11-24 20:01:19Z gpsnoopy $
//////////////////////////////////////////////////////////////////////
#ifndef TRI_STRIPPER_HEADER_GUARD_GRAPH_ARRAY_H
#define TRI_STRIPPER_HEADER_GUARD_GRAPH_ARRAY_H
#include <cassert>
#include <algorithm>
#include <functional>
#include <limits>
#include <vector>
namespace triangle_stripper {
namespace detail {
// graph_array main class
template <class nodetype>
class graph_array
{
public:
class arc;
class node;
// New types
typedef size_t nodeid;
typedef nodetype value_type;
typedef std::vector<node> node_vector;
typedef typename node_vector::iterator node_iterator;
typedef typename node_vector::const_iterator const_node_iterator;
typedef typename node_vector::reverse_iterator node_reverse_iterator;
typedef typename node_vector::const_reverse_iterator const_node_reverse_iterator;
typedef graph_array<nodetype> graph_type;
// graph_array::arc class
class arc
{
public:
node_iterator terminal() const;
protected:
friend class graph_array<nodetype>;
arc(node_iterator Terminal);
node_iterator m_Terminal;
};
// New types
typedef std::vector<arc> arc_list;
typedef typename arc_list::iterator out_arc_iterator;
typedef typename arc_list::const_iterator const_out_arc_iterator;
// graph_array::node class
class node
{
public:
void mark();
void unmark();
bool marked() const;
bool out_empty() const;
size_t out_size() const;
out_arc_iterator out_begin();
out_arc_iterator out_end();
const_out_arc_iterator out_begin() const;
const_out_arc_iterator out_end() const;
value_type & operator * ();
value_type * operator -> ();
const value_type & operator * () const;
const value_type * operator -> () const;
value_type & operator = (const value_type & Elem);
protected:
friend class graph_array<nodetype>;
friend class std::vector<node>;
node(arc_list & Arcs);
arc_list & m_Arcs;
size_t m_Begin;
size_t m_End;
value_type m_Elem;
bool m_Marker;
};
graph_array();
explicit graph_array(size_t NbNodes);
// Node related member functions
bool empty() const;
size_t size() const;
node & operator [] (nodeid i);
const node & operator [] (nodeid i) const;
node_iterator begin();
node_iterator end();
const_node_iterator begin() const;
const_node_iterator end() const;
node_reverse_iterator rbegin();
node_reverse_iterator rend();
const_node_reverse_iterator rbegin() const;
const_node_reverse_iterator rend() const;
// Arc related member functions
out_arc_iterator insert_arc(nodeid Initial, nodeid Terminal);
out_arc_iterator insert_arc(node_iterator Initial, node_iterator Terminal);
// Optimized (overloaded) functions
void swap(graph_type & Right);
friend void swap(graph_type & Left, graph_type & Right) { Left.swap(Right); }
protected:
graph_array(const graph_type &);
graph_type & operator = (const graph_type &);
node_vector m_Nodes;
arc_list m_Arcs;
};
// Additional "low level", graph related, functions
template <class nodetype>
void unmark_nodes(graph_array<nodetype> & G);
//////////////////////////////////////////////////////////////////////////
// graph_array::arc inline functions
//////////////////////////////////////////////////////////////////////////
template <class N>
inline graph_array<N>::arc::arc(node_iterator Terminal)
: m_Terminal(Terminal) { }
template <class N>
inline typename graph_array<N>::node_iterator graph_array<N>::arc::terminal() const
{
return m_Terminal;
}
//////////////////////////////////////////////////////////////////////////
// graph_array::node inline functions
//////////////////////////////////////////////////////////////////////////
template <class N>
inline graph_array<N>::node::node(arc_list & Arcs)
: m_Arcs(Arcs),
m_Begin((std::numeric_limits<size_t>::max)()),
m_End((std::numeric_limits<size_t>::max)()),
m_Marker(false)
{
}
template <class N>
inline void graph_array<N>::node::mark()
{
m_Marker = true;
}
template <class N>
inline void graph_array<N>::node::unmark()
{
m_Marker = false;
}
template <class N>
inline bool graph_array<N>::node::marked() const
{
return m_Marker;
}
template <class N>
inline bool graph_array<N>::node::out_empty() const
{
return (m_Begin == m_End);
}
template <class N>
inline size_t graph_array<N>::node::out_size() const
{
return (m_End - m_Begin);
}
template <class N>
inline typename graph_array<N>::out_arc_iterator graph_array<N>::node::out_begin()
{
return (m_Arcs.begin() + m_Begin);
}
template <class N>
inline typename graph_array<N>::out_arc_iterator graph_array<N>::node::out_end()
{
return (m_Arcs.begin() + m_End);
}
template <class N>
inline typename graph_array<N>::const_out_arc_iterator graph_array<N>::node::out_begin() const
{
return (m_Arcs.begin() + m_Begin);
}
template <class N>
inline typename graph_array<N>::const_out_arc_iterator graph_array<N>::node::out_end() const
{
return (m_Arcs.begin() + m_End);
}
template <class N>
inline N & graph_array<N>::node::operator * ()
{
return m_Elem;
}
template <class N>
inline N * graph_array<N>::node::operator -> ()
{
return &m_Elem;
}
template <class N>
inline const N & graph_array<N>::node::operator * () const
{
return m_Elem;
}
template <class N>
inline const N * graph_array<N>::node::operator -> () const
{
return &m_Elem;
}
template <class N>
inline N & graph_array<N>::node::operator = (const N & Elem)
{
return (m_Elem = Elem);
}
//////////////////////////////////////////////////////////////////////////
// graph_array inline functions
//////////////////////////////////////////////////////////////////////////
template <class N>
inline graph_array<N>::graph_array() { }
template <class N>
inline graph_array<N>::graph_array(const size_t NbNodes)
: m_Nodes(NbNodes, node(m_Arcs))
{
// optimisation: we consider that, averagely, a triangle may have at least 2 neighbours
// otherwise we are just wasting a bit of memory, but not that much
m_Arcs.reserve(NbNodes * 2);
}
template <class N>
inline bool graph_array<N>::empty() const
{
return m_Nodes.empty();
}
template <class N>
inline size_t graph_array<N>::size() const
{
return m_Nodes.size();
}
template <class N>
inline typename graph_array<N>::node & graph_array<N>::operator [] (const nodeid i)
{
assert(i < size());
return m_Nodes[i];
}
template <class N>
inline const typename graph_array<N>::node & graph_array<N>::operator [] (const nodeid i) const
{
assert(i < size());
return m_Nodes[i];
}
template <class N>
inline typename graph_array<N>::node_iterator graph_array<N>::begin()
{
return m_Nodes.begin();
}
template <class N>
inline typename graph_array<N>::node_iterator graph_array<N>::end()
{
return m_Nodes.end();
}
template <class N>
inline typename graph_array<N>::const_node_iterator graph_array<N>::begin() const
{
return m_Nodes.begin();
}
template <class N>
inline typename graph_array<N>::const_node_iterator graph_array<N>::end() const
{
return m_Nodes.end();
}
template <class N>
inline typename graph_array<N>::node_reverse_iterator graph_array<N>::rbegin()
{
return m_Nodes.rbegin();
}
template <class N>
inline typename graph_array<N>::node_reverse_iterator graph_array<N>::rend()
{
return m_Nodes.rend();
}
template <class N>
inline typename graph_array<N>::const_node_reverse_iterator graph_array<N>::rbegin() const
{
return m_Nodes.rbegin();
}
template <class N>
inline typename graph_array<N>::const_node_reverse_iterator graph_array<N>::rend() const
{
return m_Nodes.rend();
}
template <class N>
inline typename graph_array<N>::out_arc_iterator graph_array<N>::insert_arc(const nodeid Initial, const nodeid Terminal)
{
assert(Initial < size());
assert(Terminal < size());
return insert_arc(m_Nodes.begin() + Initial, m_Nodes.begin() + Terminal);
}
template <class N>
inline typename graph_array<N>::out_arc_iterator graph_array<N>::insert_arc(const node_iterator Initial, const node_iterator Terminal)
{
assert((Initial >= begin()) && (Initial < end()));
assert((Terminal >= begin()) && (Terminal < end()));
node & Node = * Initial;
if (Node.out_empty()) {
Node.m_Begin = m_Arcs.size();
Node.m_End = m_Arcs.size() + 1;
} else {
// we optimise here for make_connectivity_graph()
// we know all the arcs for a given node are successively and sequentially added
assert(Node.m_End == m_Arcs.size());
++(Node.m_End);
}
m_Arcs.push_back(arc(Terminal));
out_arc_iterator it = m_Arcs.end();
return (--it);
}
template <class N>
inline void graph_array<N>::swap(graph_type & Right)
{
std::swap(m_Nodes, Right.m_Nodes);
std::swap(m_Arcs, Right.m_Arcs);
}
//////////////////////////////////////////////////////////////////////////
// additional functions
//////////////////////////////////////////////////////////////////////////
template <class N>
inline void unmark_nodes(graph_array<N> & G)
{
std::for_each(G.begin(), G.end(), std::mem_fun_ref(&graph_array<N>::node::unmark));
}
} // namespace detail
} // namespace triangle_stripper
#endif // TRI_STRIPPER_HEADER_GUARD_GRAPH_ARRAY_H

View File

@@ -0,0 +1,297 @@
//
// Copyright (C) 2004 Tanguy Fautr<74>.
// For conditions of distribution and use,
// see copyright notice in tri_stripper.h
//
//////////////////////////////////////////////////////////////////////
// SVN: $Id: heap_array.h 86 2005-06-08 17:47:27Z gpsnoopy $
//////////////////////////////////////////////////////////////////////
#ifndef TRI_STRIPPER_HEADER_GUARD_HEAP_ARRAY_H
#define TRI_STRIPPER_HEADER_GUARD_HEAP_ARRAY_H
#include <vector>
namespace triangle_stripper {
namespace detail {
// mutable heap
// can be interfaced pretty muck like an array
template <class T, class CmpT = std::less<T> >
class heap_array
{
public:
// Pre = PreCondition, Post = PostCondition
heap_array() : m_Locked(false) { } // Post: ((size() == 0) && ! locked())
void clear(); // Post: ((size() == 0) && ! locked())
void reserve(size_t Size);
size_t size() const;
bool empty() const;
bool locked() const;
bool removed(size_t i) const; // Pre: (valid(i))
bool valid(size_t i) const;
size_t position(size_t i) const; // Pre: (valid(i))
const T & top() const; // Pre: (! empty())
const T & peek(size_t i) const; // Pre: (! removed(i))
const T & operator [] (size_t i) const; // Pre: (! removed(i))
void lock(); // Pre: (! locked()) Post: (locked())
size_t push(const T & Elem); // Pre: (! locked())
void pop(); // Pre: (locked() && ! empty())
void erase(size_t i); // Pre: (locked() && ! removed(i))
void update(size_t i, const T & Elem); // Pre: (locked() && ! removed(i))
protected:
heap_array(const heap_array &);
heap_array & operator = (const heap_array &);
class linker
{
public:
linker(const T & Elem, size_t i)
: m_Elem(Elem), m_Index(i) { }
T m_Elem;
size_t m_Index;
};
typedef std::vector<linker> linked_heap;
typedef std::vector<size_t> finder;
void Adjust(size_t i);
void Swap(size_t a, size_t b);
bool Less(const linker & a, const linker & b) const;
linked_heap m_Heap;
finder m_Finder;
CmpT m_Compare;
bool m_Locked;
};
//////////////////////////////////////////////////////////////////////////
// heap_indexed inline functions
//////////////////////////////////////////////////////////////////////////
template <class T, class CmpT>
inline void heap_array<T, CmpT>::clear()
{
m_Heap.clear();
m_Finder.clear();
m_Locked = false;
}
template <class T, class CmpT>
inline bool heap_array<T, CmpT>::empty() const
{
return m_Heap.empty();
}
template <class T, class CmpT>
inline bool heap_array<T, CmpT>::locked() const
{
return m_Locked;
}
template <class T, class CmpT>
inline void heap_array<T, CmpT>::reserve(const size_t Size)
{
m_Heap.reserve(Size);
m_Finder.reserve(Size);
}
template <class T, class CmpT>
inline size_t heap_array<T, CmpT>::size() const
{
return m_Heap.size();
}
template <class T, class CmpT>
inline const T & heap_array<T, CmpT>::top() const
{
assert(! empty());
return m_Heap.front().m_Elem;
}
template <class T, class CmpT>
inline const T & heap_array<T, CmpT>::peek(const size_t i) const
{
assert(! removed(i));
return (m_Heap[m_Finder[i]].m_Elem);
}
template <class T, class CmpT>
inline const T & heap_array<T, CmpT>::operator [] (const size_t i) const
{
return peek(i);
}
template <class T, class CmpT>
inline void heap_array<T, CmpT>::pop()
{
assert(locked());
assert(! empty());
Swap(0, size() - 1);
m_Heap.pop_back();
if (! empty())
Adjust(0);
}
template <class T, class CmpT>
inline void heap_array<T, CmpT>::lock()
{
assert(! locked());
m_Locked =true;
}
template <class T, class CmpT>
inline size_t heap_array<T, CmpT>::push(const T & Elem)
{
assert(! locked());
const size_t Id = size();
m_Finder.push_back(Id);
m_Heap.push_back(linker(Elem, Id));
Adjust(Id);
return Id;
}
template <class T, class CmpT>
inline void heap_array<T, CmpT>::erase(const size_t i)
{
assert(locked());
assert(! removed(i));
const size_t j = m_Finder[i];
Swap(j, size() - 1);
m_Heap.pop_back();
if (j != size())
Adjust(j);
}
template <class T, class CmpT>
inline bool heap_array<T, CmpT>::removed(const size_t i) const
{
assert(valid(i));
return (m_Finder[i] >= m_Heap.size());
}
template <class T, class CmpT>
inline bool heap_array<T, CmpT>::valid(const size_t i) const
{
return (i < m_Finder.size());
}
template <class T, class CmpT>
inline size_t heap_array<T, CmpT>::position(const size_t i) const
{
assert(valid(i));
return (m_Heap[i].m_Index);
}
template <class T, class CmpT>
inline void heap_array<T, CmpT>::update(const size_t i, const T & Elem)
{
assert(locked());
assert(! removed(i));
const size_t j = m_Finder[i];
m_Heap[j].m_Elem = Elem;
Adjust(j);
}
template <class T, class CmpT>
inline void heap_array<T, CmpT>::Adjust(size_t i)
{
assert(i < m_Heap.size());
size_t j;
// Check the upper part of the heap
for (j = i; (j > 0) && (Less(m_Heap[(j - 1) / 2], m_Heap[j])); j = ((j - 1) / 2))
Swap(j, (j - 1) / 2);
// Check the lower part of the heap
for (i = j; (j = 2 * i + 1) < size(); i = j) {
if ((j + 1 < size()) && (Less(m_Heap[j], m_Heap[j + 1])))
++j;
if (Less(m_Heap[j], m_Heap[i]))
return;
Swap(i, j);
}
}
template <class T, class CmpT>
inline void heap_array<T, CmpT>::Swap(const size_t a, const size_t b)
{
std::swap(m_Heap[a], m_Heap[b]);
m_Finder[(m_Heap[a].m_Index)] = a;
m_Finder[(m_Heap[b].m_Index)] = b;
}
template <class T, class CmpT>
inline bool heap_array<T, CmpT>::Less(const linker & a, const linker & b) const
{
return m_Compare(a.m_Elem, b.m_Elem);
}
} // namespace detail
} // namespace triangle_stripper
#endif // TRI_STRIPPER_HEADER_GUARD_HEAP_ARRAY_H

View File

@@ -0,0 +1,66 @@
//
// Copyright (C) 2004 Tanguy Fautr<74>.
// For conditions of distribution and use,
// see copyright notice in tri_stripper.h
//
//////////////////////////////////////////////////////////////////////
// SVN: $Id: policy.h 86 2005-06-08 17:47:27Z gpsnoopy $
//////////////////////////////////////////////////////////////////////
#ifndef TRI_STRIPPER_HEADER_GUARD_POLICY_H
#define TRI_STRIPPER_HEADER_GUARD_POLICY_H
#include "public_types.h"
#include "types.h"
namespace triangle_stripper {
namespace detail {
class policy
{
public:
policy(size_t MinStripSize, bool Cache);
strip BestStrip() const;
void Challenge(strip Strip, size_t Degree, size_t CacheHits);
private:
strip m_Strip;
size_t m_Degree;
size_t m_CacheHits;
const size_t m_MinStripSize;
const bool m_Cache;
};
inline policy::policy(size_t MinStripSize, bool Cache)
: m_Degree(0), m_CacheHits(0), m_MinStripSize(MinStripSize), m_Cache(Cache) { }
inline strip policy::BestStrip() const
{
return m_Strip;
}
} // namespace detail
} // namespace triangle_stripper
#endif // TRI_STRIPPER_HEADER_GUARD_POLICY_H

View File

@@ -0,0 +1,101 @@
//
// Copyright (C) 2004 Tanguy Fautr<74>.
// For conditions of distribution and use,
// see copyright notice in tri_stripper.h
//
//////////////////////////////////////////////////////////////////////
// SVN: $Id: types.h 86 2005-06-08 17:47:27Z gpsnoopy $
//////////////////////////////////////////////////////////////////////
#ifndef TRI_STRIPPER_HEADER_GUARD_TYPES_H
#define TRI_STRIPPER_HEADER_GUARD_TYPES_H
namespace triangle_stripper {
namespace detail {
class triangle
{
public:
triangle() { }
triangle(index A, index B, index C)
: m_A(A), m_B(B), m_C(C), m_StripID(0) { }
void ResetStripID() { m_StripID = 0; }
void SetStripID(size_t StripID) { m_StripID = StripID; }
size_t StripID() const { return m_StripID; }
index A() const { return m_A; }
index B() const { return m_B; }
index C() const { return m_C; }
private:
index m_A;
index m_B;
index m_C;
size_t m_StripID;
};
class triangle_edge
{
public:
triangle_edge(index A, index B)
: m_A(A), m_B(B) { }
index A() const { return m_A; }
index B() const { return m_B; }
bool operator == (const triangle_edge & Right) const {
return ((A() == Right.A()) && (B() == Right.B()));
}
private:
index m_A;
index m_B;
};
enum triangle_order { ABC, BCA, CAB };
class strip
{
public:
strip()
: m_Start(0), m_Order(ABC), m_Size(0) { }
strip(size_t Start, triangle_order Order, size_t Size)
: m_Start(Start), m_Order(Order), m_Size(Size) { }
size_t Start() const { return m_Start; }
triangle_order Order() const { return m_Order; }
size_t Size() const { return m_Size; }
private:
size_t m_Start;
triangle_order m_Order;
size_t m_Size;
};
} // namespace detail
} // namespace triangle_stripper
#endif // TRI_STRIPPER_HEADER_GUARD_TYPES_H

View File

@@ -0,0 +1,43 @@
//
// Copyright (C) 2004 Tanguy Fautr<74>.
// For conditions of distribution and use,
// see copyright notice in tri_stripper.h
//
//////////////////////////////////////////////////////////////////////
// SVN: $Id: public_types.h 86 2005-06-08 17:47:27Z gpsnoopy $
//////////////////////////////////////////////////////////////////////
#ifndef TRI_STRIPPER_HEADER_GUARD_PUBLIC_TYPES_H
#define TRI_STRIPPER_HEADER_GUARD_PUBLIC_TYPES_H
#include <vector>
namespace triangle_stripper
{
typedef size_t index;
typedef std::vector<index> indices;
enum primitive_type
{
TRIANGLES = 0x0004, // = GL_TRIANGLES
TRIANGLE_STRIP = 0x0005 // = GL_TRIANGLE_STRIP
};
struct primitive_group
{
indices Indices;
primitive_type Type;
};
typedef std::vector<primitive_group> primitive_vector;
}
#endif // TRI_STRIPPER_HEADER_GUARD_PUBLIC_TYPES_H

View File

@@ -0,0 +1,178 @@
//////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2004 Tanguy Fautr<74>.
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//
// Tanguy Fautr<74>
// softdev@telenet.be
//
//////////////////////////////////////////////////////////////////////
//
// Tri Stripper
// ************
//
// Post TnL cache aware triangle stripifier in O(n.log(n)).
//
// History: see ChangeLog
//
//////////////////////////////////////////////////////////////////////
// SVN: $Id: tri_stripper.h 94 2009-11-24 20:08:20Z gpsnoopy $
//////////////////////////////////////////////////////////////////////
#ifndef TRI_STRIPPER_HEADER_GUARD_TRI_STRIPPER_H
#define TRI_STRIPPER_HEADER_GUARD_TRI_STRIPPER_H
#include "public_types.h"
#include "detail/cache_simulator.h"
#include "detail/graph_array.h"
#include "detail/heap_array.h"
#include "detail/types.h"
namespace triangle_stripper {
class tri_stripper
{
public:
explicit tri_stripper(const indices & TriIndices);
void Strip(primitive_vector * out_pPrimitivesVector);
/* Stripifier Algorithm Settings */
// Set the post-T&L cache size (0 disables the cache optimizer).
void SetCacheSize(size_t CacheSize = 10);
// Set the minimum size of a triangle strip (should be at least 2 triangles).
// The stripifier discard any candidate strips that does not satisfy the minimum size condition.
void SetMinStripSize(size_t MinStripSize = 2);
// Set the backward search mode in addition to the forward search mode.
// In forward mode, the candidate strips are build with the current candidate triangle being the first
// triangle of the strip. When the backward mode is enabled, the stripifier also tests candidate strips
// where the current candidate triangle is the last triangle of the strip.
// Enable this if you want better results at the expense of being slightly slower.
// Note: Do *NOT* use this when the cache optimizer is enabled; it only gives worse results.
void SetBackwardSearch(bool Enabled = false);
// Set the cache simulator FIFO behavior (does nothing if the cache optimizer is disabled).
// When enabled, the cache is simulated as a simple FIFO structure. However, when
// disabled, indices that trigger cache hits are not pushed into the FIFO structure.
// This allows simulating some GPUs that do not duplicate cache entries (e.g. NV25 or greater).
void SetPushCacheHits(bool Enabled = true);
/* End Settings */
private:
typedef detail::graph_array<detail::triangle> triangle_graph;
typedef detail::heap_array<size_t, std::greater<size_t> > triangle_heap;
typedef std::vector<size_t> candidates;
typedef triangle_graph::node_iterator tri_iterator;
typedef triangle_graph::const_node_iterator const_tri_iterator;
typedef triangle_graph::out_arc_iterator link_iterator;
typedef triangle_graph::const_out_arc_iterator const_link_iterator;
void InitTriHeap();
void Stripify();
void AddLeftTriangles();
void ResetStripIDs();
detail::strip FindBestStrip();
detail::strip ExtendToStrip(size_t Start, detail::triangle_order Order);
detail::strip BackExtendToStrip(size_t Start, detail::triangle_order Order, bool ClockWise);
const_link_iterator LinkToNeighbour(const_tri_iterator Node, bool ClockWise, detail::triangle_order & Order, bool NotSimulation);
const_link_iterator BackLinkToNeighbour(const_tri_iterator Node, bool ClockWise, detail::triangle_order & Order);
void BuildStrip(const detail::strip Strip);
void MarkTriAsTaken(size_t i);
void AddIndex(index i, bool NotSimulation);
void BackAddIndex(index i);
void AddTriangle(const detail::triangle & Tri, detail::triangle_order Order, bool NotSimulation);
void BackAddTriangle(const detail::triangle & Tri, detail::triangle_order Order);
bool Cache() const;
size_t CacheSize() const;
static detail::triangle_edge FirstEdge(const detail::triangle & Triangle, detail::triangle_order Order);
static detail::triangle_edge LastEdge(const detail::triangle & Triangle, detail::triangle_order Order);
primitive_vector m_PrimitivesVector;
triangle_graph m_Triangles;
triangle_heap m_TriHeap;
candidates m_Candidates;
detail::cache_simulator m_Cache;
detail::cache_simulator m_BackCache;
size_t m_StripID;
size_t m_MinStripSize;
bool m_BackwardSearch;
bool m_FirstRun;
};
//////////////////////////////////////////////////////////////////////////
// tri_stripper inline functions
//////////////////////////////////////////////////////////////////////////
inline void tri_stripper::SetCacheSize(const size_t CacheSize)
{
m_Cache.resize(CacheSize);
m_BackCache.resize(CacheSize);
}
inline void tri_stripper::SetMinStripSize(const size_t MinStripSize)
{
if (MinStripSize < 2)
m_MinStripSize = 2;
else
m_MinStripSize = MinStripSize;
}
inline void tri_stripper::SetBackwardSearch(const bool Enabled)
{
m_BackwardSearch = Enabled;
}
inline void tri_stripper::SetPushCacheHits(bool Enabled)
{
m_Cache.push_cache_hits(Enabled);
}
} // namespace triangle_stripper
#endif // TRI_STRIPPER_HEADER_GUARD_TRI_STRIPPER_H

View File

@@ -0,0 +1,132 @@
//
// Copyright (C) 2004 Tanguy Fautr<74>.
// For conditions of distribution and use,
// see copyright notice in tri_stripper.h
//
//////////////////////////////////////////////////////////////////////
// SVN: $Id: connectivity_graph.cpp 86 2005-06-08 17:47:27Z gpsnoopy $
//////////////////////////////////////////////////////////////////////
#include "detail/connectivity_graph.h"
#include <algorithm>
namespace triangle_stripper {
namespace detail {
namespace
{
class tri_edge : public triangle_edge
{
public:
tri_edge(index A, index B, size_t TriPos)
: triangle_edge(A, B), m_TriPos(TriPos) { }
size_t TriPos() const { return m_TriPos; }
private:
size_t m_TriPos;
};
class cmp_tri_edge_lt
{
public:
bool operator() (const tri_edge & a, const tri_edge & b) const;
};
typedef std::vector<tri_edge> edge_map;
void LinkNeighbours(graph_array<triangle> & Triangles, const edge_map & EdgeMap, const tri_edge Edge);
}
void make_connectivity_graph(graph_array<triangle> & Triangles, const indices & Indices)
{
assert(Triangles.size() == (Indices.size() / 3));
// Fill the triangle data
for (size_t i = 0; i < Triangles.size(); ++i)
Triangles[i] = triangle(Indices[i * 3 + 0], Indices[i * 3 + 1], Indices[i * 3 + 2]);
// Build an edge lookup table
edge_map EdgeMap;
EdgeMap.reserve(Triangles.size() * 3);
for (size_t i = 0; i < Triangles.size(); ++i) {
const triangle & Tri = * Triangles[i];
EdgeMap.push_back(tri_edge(Tri.A(), Tri.B(), i));
EdgeMap.push_back(tri_edge(Tri.B(), Tri.C(), i));
EdgeMap.push_back(tri_edge(Tri.C(), Tri.A(), i));
}
std::sort(EdgeMap.begin(), EdgeMap.end(), cmp_tri_edge_lt());
// Link neighbour triangles together using the lookup table
for (size_t i = 0; i < Triangles.size(); ++i) {
const triangle & Tri = * Triangles[i];
LinkNeighbours(Triangles, EdgeMap, tri_edge(Tri.B(), Tri.A(), i));
LinkNeighbours(Triangles, EdgeMap, tri_edge(Tri.C(), Tri.B(), i));
LinkNeighbours(Triangles, EdgeMap, tri_edge(Tri.A(), Tri.C(), i));
}
}
namespace
{
inline bool cmp_tri_edge_lt::operator() (const tri_edge & a, const tri_edge & b) const
{
const index A1 = a.A();
const index B1 = a.B();
const index A2 = b.A();
const index B2 = b.B();
if ((A1 < A2) || ((A1 == A2) && (B1 < B2)))
return true;
else
return false;
}
void LinkNeighbours(graph_array<triangle> & Triangles, const edge_map & EdgeMap, const tri_edge Edge)
{
// Find the first edge equal to Edge
edge_map::const_iterator it = std::lower_bound(EdgeMap.begin(), EdgeMap.end(), Edge, cmp_tri_edge_lt());
// See if there are any other edges that are equal
// (if so, it means that more than 2 triangles are sharing the same edge,
// which is unlikely but not impossible)
for (; (it != EdgeMap.end()) && (Edge == (* it)); ++it)
Triangles.insert_arc(Edge.TriPos(), it->TriPos());
// Note: degenerated triangles will also point themselves as neighbour triangles
}
}
} // namespace detail
} // namespace detail

View File

@@ -0,0 +1,63 @@
//
// Copyright (C) 2004 Tanguy Fautr<74>.
// For conditions of distribution and use,
// see copyright notice in tri_stripper.h
//
//////////////////////////////////////////////////////////////////////
// SVN: $Id: policy.cpp 86 2005-06-08 17:47:27Z gpsnoopy $
//////////////////////////////////////////////////////////////////////
#include "detail/policy.h"
namespace triangle_stripper {
namespace detail {
void policy::Challenge(strip Strip, size_t Degree, size_t CacheHits)
{
if (Strip.Size() < m_MinStripSize)
return;
// Cache is disabled, take the longest strip
if (! m_Cache) {
if (Strip.Size() > m_Strip.Size())
m_Strip = Strip;
// Cache simulator enabled
} else {
// Priority 1: Keep the strip with the best cache hit count
if (CacheHits > m_CacheHits) {
m_Strip = Strip;
m_Degree = Degree;
m_CacheHits = CacheHits;
} else if (CacheHits == m_CacheHits) {
// Priority 2: Keep the strip with the loneliest start triangle
if ((m_Strip.Size() != 0) && (Degree < m_Degree)) {
m_Strip = Strip;
m_Degree = Degree;
// Priority 3: Keep the longest strip
} else if (Strip.Size() > m_Strip.Size()) {
m_Strip = Strip;
m_Degree = Degree;
}
}
}
}
} // namespace detail
} // namespace triangle_stripper

View File

@@ -0,0 +1,554 @@
//
// Copyright (C) 2004 Tanguy Fautr<74>.
// For conditions of distribution and use,
// see copyright notice in tri_stripper.h
//
//////////////////////////////////////////////////////////////////////
// SVN: $Id: tri_stripper.cpp 86 2005-06-08 17:47:27Z gpsnoopy $
//////////////////////////////////////////////////////////////////////
#include "tri_stripper.h"
#include "detail/connectivity_graph.h"
#include "detail/policy.h"
#include <cassert>
namespace triangle_stripper {
using namespace detail;
tri_stripper::tri_stripper(const indices & TriIndices)
: m_Triangles(TriIndices.size() / 3), // Silently ignore extra indices if (Indices.size() % 3 != 0)
m_StripID(0),
m_FirstRun(true)
{
SetCacheSize();
SetMinStripSize();
SetBackwardSearch();
SetPushCacheHits();
make_connectivity_graph(m_Triangles, TriIndices);
}
void tri_stripper::Strip(primitive_vector * out_pPrimitivesVector)
{
assert(out_pPrimitivesVector);
if (! m_FirstRun) {
unmark_nodes(m_Triangles);
ResetStripIDs();
m_Cache.reset();
m_TriHeap.clear();
m_Candidates.clear();
m_StripID = 0;
m_FirstRun = false;
}
out_pPrimitivesVector->clear();
InitTriHeap();
Stripify();
AddLeftTriangles();
std::swap(m_PrimitivesVector, (* out_pPrimitivesVector));
}
void tri_stripper::InitTriHeap()
{
m_TriHeap.reserve(m_Triangles.size());
// Set up the triangles priority queue
// The lower the number of available neighbour triangles, the higher the priority.
for (size_t i = 0; i < m_Triangles.size(); ++i)
m_TriHeap.push(m_Triangles[i].out_size());
// We're not going to add new elements anymore
m_TriHeap.lock();
// Remove useless triangles
// Note: we had to put all of them into the heap before to ensure coherency of the heap_array object
while ((! m_TriHeap.empty()) && (m_TriHeap.top() == 0))
m_TriHeap.pop();
}
void tri_stripper::ResetStripIDs()
{
for (triangle_graph::node_iterator it = m_Triangles.begin(); it != m_Triangles.end(); ++it)
(**it).ResetStripID();
}
void tri_stripper::Stripify()
{
while (! m_TriHeap.empty()) {
// There is no triangle in the candidates list, refill it with the loneliest triangle
const size_t HeapTop = m_TriHeap.position(0);
m_Candidates.push_back(HeapTop);
while (! m_Candidates.empty()) {
// Note: FindBestStrip empties the candidate list, while BuildStrip refills it
const strip TriStrip = FindBestStrip();
if (TriStrip.Size() >= m_MinStripSize)
BuildStrip(TriStrip);
}
if (! m_TriHeap.removed(HeapTop))
m_TriHeap.erase(HeapTop);
// Eliminate all the triangles that have now become useless
while ((! m_TriHeap.empty()) && (m_TriHeap.top() == 0))
m_TriHeap.pop();
}
}
inline strip tri_stripper::FindBestStrip()
{
// Allow to restore the cache (modified by ExtendTriToStrip) and implicitly reset the cache hit count
const cache_simulator CacheBackup = m_Cache;
policy Policy(m_MinStripSize, Cache());
while (! m_Candidates.empty()) {
const size_t Candidate = m_Candidates.back();
m_Candidates.pop_back();
// Discard useless triangles from the candidate list
if ((m_Triangles[Candidate].marked()) || (m_TriHeap[Candidate] == 0))
continue;
// Try to extend the triangle in the 3 possible forward directions
for (size_t i = 0; i < 3; ++i) {
const strip Strip = ExtendToStrip(Candidate, triangle_order(i));
Policy.Challenge(Strip, m_TriHeap[Strip.Start()], m_Cache.hitcount());
m_Cache = CacheBackup;
}
// Try to extend the triangle in the 6 possible backward directions
if (m_BackwardSearch) {
for (size_t i = 0; i < 3; ++i) {
const strip Strip = BackExtendToStrip(Candidate, triangle_order(i), false);
Policy.Challenge(Strip, m_TriHeap[Strip.Start()], m_Cache.hitcount());
m_Cache = CacheBackup;
}
for (size_t i = 0; i < 3; ++i) {
const strip Strip = BackExtendToStrip(Candidate, triangle_order(i), true);
Policy.Challenge(Strip, m_TriHeap[Strip.Start()], m_Cache.hitcount());
m_Cache = CacheBackup;
}
}
}
return Policy.BestStrip();
}
strip tri_stripper::ExtendToStrip(const size_t Start, triangle_order Order)
{
const triangle_order StartOrder = Order;
// Begin a new strip
m_Triangles[Start]->SetStripID(++m_StripID);
AddTriangle(* m_Triangles[Start], Order, false);
size_t Size = 1;
bool ClockWise = false;
// Loop while we can further extend the strip
for (tri_iterator Node = (m_Triangles.begin() + Start);
(Node != m_Triangles.end()) && (!Cache() || ((Size + 2) < CacheSize()));
++Size) {
const const_link_iterator Link = LinkToNeighbour(Node, ClockWise, Order, false);
// Is it the end of the strip?
if (Link == Node->out_end()) {
Node = m_Triangles.end();
--Size;
} else {
Node = Link->terminal();
(* Node)->SetStripID(m_StripID);
ClockWise = ! ClockWise;
}
}
return strip(Start, StartOrder, Size);
}
strip tri_stripper::BackExtendToStrip(size_t Start, triangle_order Order, bool ClockWise)
{
// Begin a new strip
m_Triangles[Start]->SetStripID(++m_StripID);
BackAddIndex(LastEdge(* m_Triangles[Start], Order).B());
size_t Size = 1;
tri_iterator Node;
// Loop while we can further extend the strip
for (Node = (m_Triangles.begin() + Start);
!Cache() || ((Size + 2) < CacheSize());
++Size) {
const const_link_iterator Link = BackLinkToNeighbour(Node, ClockWise, Order);
// Is it the end of the strip?
if (Link == Node->out_end())
break;
else {
Node = Link->terminal();
(* Node)->SetStripID(m_StripID);
ClockWise = ! ClockWise;
}
}
// We have to start from a counterclockwise triangle.
// Simply return an empty strip in the case where the first triangle is clockwise.
// Even though we could discard the first triangle and start from the next counterclockwise triangle,
// this often leads to more lonely triangles afterward.
if (ClockWise)
return strip();
if (Cache()) {
m_Cache.merge(m_BackCache, Size);
m_BackCache.reset();
}
return strip(Node - m_Triangles.begin(), Order, Size);
}
void tri_stripper::BuildStrip(const strip Strip)
{
const size_t Start = Strip.Start();
bool ClockWise = false;
triangle_order Order = Strip.Order();
// Create a new strip
m_PrimitivesVector.push_back(primitive_group());
m_PrimitivesVector.back().Type = TRIANGLE_STRIP;
AddTriangle(* m_Triangles[Start], Order, true);
MarkTriAsTaken(Start);
// Loop while we can further extend the strip
tri_iterator Node = (m_Triangles.begin() + Start);
for (size_t Size = 1; Size < Strip.Size(); ++Size) {
const const_link_iterator Link = LinkToNeighbour(Node, ClockWise, Order, true);
assert(Link != Node->out_end());
// Go to the next triangle
Node = Link->terminal();
MarkTriAsTaken(Node - m_Triangles.begin());
ClockWise = ! ClockWise;
}
}
inline tri_stripper::const_link_iterator tri_stripper::LinkToNeighbour(const const_tri_iterator Node, const bool ClockWise, triangle_order & Order, const bool NotSimulation)
{
const triangle_edge Edge = LastEdge(** Node, Order);
for (const_link_iterator Link = Node->out_begin(); Link != Node->out_end(); ++Link) {
// Get the reference to the possible next triangle
const triangle & Tri = ** Link->terminal();
// Check whether it's already been used
if (NotSimulation || (Tri.StripID() != m_StripID)) {
if (! Link->terminal()->marked()) {
// Does the current candidate triangle match the required position for the strip?
if ((Edge.B() == Tri.A()) && (Edge.A() == Tri.B())) {
Order = (ClockWise) ? ABC : BCA;
AddIndex(Tri.C(), NotSimulation);
return Link;
}
else if ((Edge.B() == Tri.B()) && (Edge.A() == Tri.C())) {
Order = (ClockWise) ? BCA : CAB;
AddIndex(Tri.A(), NotSimulation);
return Link;
}
else if ((Edge.B() == Tri.C()) && (Edge.A() == Tri.A())) {
Order = (ClockWise) ? CAB : ABC;
AddIndex(Tri.B(), NotSimulation);
return Link;
}
}
}
}
return Node->out_end();
}
inline tri_stripper::const_link_iterator tri_stripper::BackLinkToNeighbour(const_tri_iterator Node, bool ClockWise, triangle_order & Order)
{
const triangle_edge Edge = FirstEdge(** Node, Order);
for (const_link_iterator Link = Node->out_begin(); Link != Node->out_end(); ++Link) {
// Get the reference to the possible previous triangle
const triangle & Tri = ** Link->terminal();
// Check whether it's already been used
if ((Tri.StripID() != m_StripID) && ! Link->terminal()->marked()) {
// Does the current candidate triangle match the required position for the strip?
if ((Edge.B() == Tri.A()) && (Edge.A() == Tri.B())) {
Order = (ClockWise) ? CAB : BCA;
BackAddIndex(Tri.C());
return Link;
}
else if ((Edge.B() == Tri.B()) && (Edge.A() == Tri.C())) {
Order = (ClockWise) ? ABC : CAB;
BackAddIndex(Tri.A());
return Link;
}
else if ((Edge.B() == Tri.C()) && (Edge.A() == Tri.A())) {
Order = (ClockWise) ? BCA : ABC;
BackAddIndex(Tri.B());
return Link;
}
}
}
return Node->out_end();
}
void tri_stripper::MarkTriAsTaken(const size_t i)
{
typedef triangle_graph::node_iterator tri_node_iter;
typedef triangle_graph::out_arc_iterator tri_link_iter;
// Mark the triangle node
m_Triangles[i].mark();
// Remove triangle from priority queue if it isn't yet
if (! m_TriHeap.removed(i))
m_TriHeap.erase(i);
// Adjust the degree of available neighbour triangles
for (tri_link_iter Link = m_Triangles[i].out_begin(); Link != m_Triangles[i].out_end(); ++Link) {
const size_t j = Link->terminal() - m_Triangles.begin();
if ((! m_Triangles[j].marked()) && (! m_TriHeap.removed(j))) {
size_t NewDegree = m_TriHeap.peek(j);
NewDegree = NewDegree - 1;
m_TriHeap.update(j, NewDegree);
// Update the candidate list if cache is enabled
if (Cache() && (NewDegree > 0))
m_Candidates.push_back(j);
}
}
}
inline triangle_edge tri_stripper::FirstEdge(const triangle & Triangle, const triangle_order Order)
{
switch (Order)
{
case ABC:
return triangle_edge(Triangle.A(), Triangle.B());
case BCA:
return triangle_edge(Triangle.B(), Triangle.C());
case CAB:
return triangle_edge(Triangle.C(), Triangle.A());
default:
assert(false);
return triangle_edge(0, 0);
}
}
inline triangle_edge tri_stripper::LastEdge(const triangle & Triangle, const triangle_order Order)
{
switch (Order)
{
case ABC:
return triangle_edge(Triangle.B(), Triangle.C());
case BCA:
return triangle_edge(Triangle.C(), Triangle.A());
case CAB:
return triangle_edge(Triangle.A(), Triangle.B());
default:
assert(false);
return triangle_edge(0, 0);
}
}
inline void tri_stripper::AddIndex(const index i, const bool NotSimulation)
{
if (Cache())
m_Cache.push(i, ! NotSimulation);
if (NotSimulation)
m_PrimitivesVector.back().Indices.push_back(i);
}
inline void tri_stripper::BackAddIndex(const index i)
{
if (Cache())
m_BackCache.push(i, true);
}
inline void tri_stripper::AddTriangle(const triangle & Tri, const triangle_order Order, const bool NotSimulation)
{
switch (Order)
{
case ABC:
AddIndex(Tri.A(), NotSimulation);
AddIndex(Tri.B(), NotSimulation);
AddIndex(Tri.C(), NotSimulation);
break;
case BCA:
AddIndex(Tri.B(), NotSimulation);
AddIndex(Tri.C(), NotSimulation);
AddIndex(Tri.A(), NotSimulation);
break;
case CAB:
AddIndex(Tri.C(), NotSimulation);
AddIndex(Tri.A(), NotSimulation);
AddIndex(Tri.B(), NotSimulation);
break;
}
}
inline void tri_stripper::BackAddTriangle(const triangle & Tri, const triangle_order Order)
{
switch (Order)
{
case ABC:
BackAddIndex(Tri.C());
BackAddIndex(Tri.B());
BackAddIndex(Tri.A());
break;
case BCA:
BackAddIndex(Tri.A());
BackAddIndex(Tri.C());
BackAddIndex(Tri.B());
break;
case CAB:
BackAddIndex(Tri.B());
BackAddIndex(Tri.A());
BackAddIndex(Tri.C());
break;
}
}
void tri_stripper::AddLeftTriangles()
{
// Create the last indices array and fill it with all the triangles that couldn't be stripped
primitive_group Primitives;
Primitives.Type = TRIANGLES;
m_PrimitivesVector.push_back(Primitives);
indices & Indices = m_PrimitivesVector.back().Indices;
for (size_t i = 0; i < m_Triangles.size(); ++i)
if (! m_Triangles[i].marked()) {
Indices.push_back(m_Triangles[i]->A());
Indices.push_back(m_Triangles[i]->B());
Indices.push_back(m_Triangles[i]->C());
}
// Undo if useless
if (Indices.size() == 0)
m_PrimitivesVector.pop_back();
}
inline bool tri_stripper::Cache() const
{
return (m_Cache.size() != 0);
}
inline size_t tri_stripper::CacheSize() const
{
return m_Cache.size();
}
} // namespace triangle_stripper