From 1977338cce8900dcea7579b4e59de6fb29047037 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Tue, 15 Dec 2009 12:37:49 +0000 Subject: [PATCH] From Tanguy Fautre and Robert Osfield, updated tristripper code to use the latest tristripper_r94 code. --- src/osgUtil/CMakeLists.txt | 19 +- src/osgUtil/TriStripVisitor.cpp | 55 +- src/osgUtil/TriStrip_graph_array.h | 423 ------------ src/osgUtil/TriStrip_heap_array.h | 312 --------- src/osgUtil/TriStrip_tri_stripper.cpp | 607 ------------------ src/osgUtil/TriStrip_tri_stripper.h | 401 ------------ .../include/detail/cache_simulator.h | 154 +++++ .../include/detail/connectivity_graph.h | 36 ++ .../tristripper/include/detail/graph_array.h | 460 +++++++++++++ .../tristripper/include/detail/heap_array.h | 297 +++++++++ .../tristripper/include/detail/policy.h | 66 ++ .../tristripper/include/detail/types.h | 101 +++ .../tristripper/include/public_types.h | 43 ++ .../tristripper/include/tri_stripper.h | 178 +++++ .../tristripper/src/connectivity_graph.cpp | 132 ++++ src/osgUtil/tristripper/src/policy.cpp | 63 ++ src/osgUtil/tristripper/src/tri_stripper.cpp | 554 ++++++++++++++++ 17 files changed, 2127 insertions(+), 1774 deletions(-) delete mode 100644 src/osgUtil/TriStrip_graph_array.h delete mode 100644 src/osgUtil/TriStrip_heap_array.h delete mode 100644 src/osgUtil/TriStrip_tri_stripper.cpp delete mode 100644 src/osgUtil/TriStrip_tri_stripper.h create mode 100644 src/osgUtil/tristripper/include/detail/cache_simulator.h create mode 100644 src/osgUtil/tristripper/include/detail/connectivity_graph.h create mode 100644 src/osgUtil/tristripper/include/detail/graph_array.h create mode 100644 src/osgUtil/tristripper/include/detail/heap_array.h create mode 100644 src/osgUtil/tristripper/include/detail/policy.h create mode 100644 src/osgUtil/tristripper/include/detail/types.h create mode 100644 src/osgUtil/tristripper/include/public_types.h create mode 100644 src/osgUtil/tristripper/include/tri_stripper.h create mode 100644 src/osgUtil/tristripper/src/connectivity_graph.cpp create mode 100644 src/osgUtil/tristripper/src/policy.cpp create mode 100644 src/osgUtil/tristripper/src/tri_stripper.cpp diff --git a/src/osgUtil/CMakeLists.txt b/src/osgUtil/CMakeLists.txt index c1d1aecd9..19f2d0b7a 100644 --- a/src/osgUtil/CMakeLists.txt +++ b/src/osgUtil/CMakeLists.txt @@ -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 diff --git a/src/osgUtil/TriStripVisitor.cpp b/src/osgUtil/TriStripVisitor.cpp index 758122156..c68e9c5f1 100644 --- a/src/osgUtil/TriStripVisitor.cpp +++ b/src/osgUtil/TriStripVisitor.cpp @@ -22,7 +22,7 @@ #include #include -#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."< 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); } } diff --git a/src/osgUtil/TriStrip_graph_array.h b/src/osgUtil/TriStrip_graph_array.h deleted file mode 100644 index 0ec8fb9d7..000000000 --- a/src/osgUtil/TriStrip_graph_array.h +++ /dev/null @@ -1,423 +0,0 @@ -// graph_array.h: interface for the graph_array class. -// -////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2002 Tanguy Fautr�. -// -// 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� -// 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 - -// namespace common_structures -namespace common_structures { - - - - -// graph_array main class -template -class graph_array -{ -public: - - class arc; - class node; - - // New types - typedef size_t nodeid; - typedef typename std::vector::iterator node_iterator; - typedef typename std::vector::const_iterator const_node_iterator; - typedef typename std::vector::reverse_iterator node_reverse_iterator; - typedef typename std::vector::const_reverse_iterator const_node_reverse_iterator; - - typedef graph_array _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; - - 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::iterator out_arc_iterator; - typedef typename std::list::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; - friend class std::vector; - - - std::list 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 m_Nodes; -}; - - - -// Additional "low level", graph related, functions -template -void unmark_nodes(graph_array & G); - -template -void unmark_arcs_from_node(typename graph_array::node & N); - -template -void unmark_arcs(graph_array & G); - - - - -////////////////////////////////////////////////////////////////////////// -// graph_array Inline functions -////////////////////////////////////////////////////////////////////////// - -template -inline graph_array::graph_array() : m_NbArcs(0) { } - - -template -inline graph_array::graph_array(const size_t NbNodes) : m_NbArcs(0), m_Nodes(NbNodes) { } - - -template -inline void graph_array::clear() { - m_NbArcs = 0; - m_Nodes.clear(); -} - - - -template -inline bool graph_array::empty() const { - return m_Nodes.empty(); -} - - -template -inline size_t graph_array::size() const { - return m_Nodes.size(); -} - - -template -inline void graph_array::setsize(const size_t NbNodes) { - clear(); - m_Nodes.resize(NbNodes); -} - - -template -inline typename graph_array::node & graph_array::operator [] (const nodeid & i) { - return m_Nodes[i]; -} - - -template -inline const typename graph_array::node & graph_array::operator [] (const nodeid & i) const { - return m_Nodes[i]; -} - - -template -inline typename graph_array::node_iterator graph_array::begin() { - return m_Nodes.begin(); -} - - -template -inline typename graph_array::node_iterator graph_array::end() { - return m_Nodes.end(); -} - - -template -inline typename graph_array::const_node_iterator graph_array::begin() const { - return m_Nodes.begin(); -} - - -template -inline typename graph_array::const_node_iterator graph_array::end() const { - return m_Nodes.end(); -} - - -template -inline typename graph_array::node_reverse_iterator graph_array::rbegin() { - return m_Nodes.rbegin(); -} - - -template -inline typename graph_array::node_reverse_iterator graph_array::rend() { - return m_Nodes.rend(); -} - - -template -inline typename graph_array::const_node_reverse_iterator graph_array::rbegin() const { - return m_Nodes.rbegin(); -} - - -template -inline typename graph_array::const_node_reverse_iterator graph_array::rend() const { - return m_Nodes.rend(); -} - - -template -inline size_t graph_array::number_of_arcs() const { - return m_NbArcs; -} - - -template -inline typename graph_array::out_arc_iterator graph_array::insert_arc(const nodeid & Initial, const nodeid & Terminal) { - return (insert(begin() + Initial, begin() + Terminal)); -} - - -template -inline typename graph_array::out_arc_iterator graph_array::insert_arc(const nodeid & Initial, const nodeid & Terminal, const arctype & Elem) { - return (insert(begin() + Initial, begin() + Terminal, Elem)); -} - - -template -inline typename graph_array::out_arc_iterator graph_array::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 -inline typename graph_array::out_arc_iterator graph_array::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 -inline typename graph_array::out_arc_iterator graph_array::erase_arc(const out_arc_iterator & Pos) { - --m_NbArcs; - return (Pos->initial()->m_OutArcs.erase(Pos)); -} - - -template -inline void graph_array::erase_arcs(const node_iterator & Initial) { - m_NbArcs -= (Initial->m_OutArcs.size()); - Initial->m_OutArcs.clear(); -} - - -template -inline void graph_array::erase_arcs() { - m_NbArcs = 0; - for (nodeid i = 0; i < this->Size(); ++i) - m_Nodes[i].m_OutArcs.clear(); -} - - -template -inline void graph_array::swap(_mytype & Right) { - std::swap(m_NbArcs, Right.m_NbArcs); - std::swap(m_Nodes, Right.m_Nodes); -} - - - -////////////////////////////////////////////////////////////////////////// -// additional functions -////////////////////////////////////////////////////////////////////////// - -template -void unmark_nodes(graph_array & G) -{ - typedef typename graph_array::node_iterator node_it; - - for (node_it NodeIt = G.begin(); NodeIt != G.end(); ++NodeIt) - NodeIt->unmark(); -} - - -template -void unmark_arcs_from_node(typename graph_array::node & N) -{ - typedef typename graph_array::out_arc_iterator arc_it; - - for (arc_it ArcIt = N.out_begin(); ArcIt != N.out_end(); ++ArcIt) - ArcIt->unmark(); -} - - -template -void unmark_arcs(graph_array & G) -{ - typedef typename graph_array::node_iterator node_it; - - for (node_it NodeIt = G.begin(); NodeIt != G.end(); ++NodeIt) - unmark_arcs_from_node(* NodeIt); -} - - - - -} // namespace common_structures - -#endif diff --git a/src/osgUtil/TriStrip_heap_array.h b/src/osgUtil/TriStrip_heap_array.h deleted file mode 100644 index e2b664951..000000000 --- a/src/osgUtil/TriStrip_heap_array.h +++ /dev/null @@ -1,312 +0,0 @@ -// heap_array.h: interface for the heap_array class. -// -////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2002 Tanguy Fautr�. -// -// 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� -// 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 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 linked_heap; - typedef std::vector 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 -inline void heap_array::clear() { - m_Heap.clear(); - m_Finder.clear(); - m_Locked = false; -} - - -template -inline bool heap_array::empty() const { - return m_Heap.empty(); -} - - -template -inline bool heap_array::locked() const { - return m_Locked; -} - - -template -inline void heap_array::reserve(size_t Size) { - m_Heap.reserve(Size); - m_Finder.reserve(Size); -} - - -template -inline size_t heap_array::size() const { - return m_Heap.size(); -} - - -template -inline const T & heap_array::top() const { - // Debug check to ensure heap is not empty - if (empty()) - { - osg::notify(osg::NOTICE)<<"TriStripVisitor:: heap_array::top() error, heap empty."< -inline const T & heap_array::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::peek(size_t i) error."< -inline const T & heap_array::operator [] (size_t i) const { - return peek(i); -} - - -template -inline void heap_array::pop() { - m_Locked = true; - - // Debug check to ensure heap is not empty - if (empty()) - { - osg::notify(osg::NOTICE)<<"TriStripVisitor:: heap_array::pop() error, heap empty."< -inline size_t heap_array::push(const T & Elem) { - if (m_Locked) - { - osg::notify(osg::NOTICE)<<"TriStripVisitor:: heap_array::push() heap_is_locked."< -inline void heap_array::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::erase(size_t i) error."< -inline bool heap_array::removed(size_t i) const { - return (m_Finder[i] >= m_Heap.size()); -} - - -template -inline bool heap_array::valid(size_t i) const { - return (i < m_Finder.size()); -} - - -template -inline void heap_array::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::update(size_t i, const T & Elem) error."< -inline void heap_array::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 -inline void heap_array::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 -inline bool heap_array::Less(const linker & a, const linker & b) const { - return m_Compare(a.m_Elem, b.m_Elem); -} - - - - -} // namespace common_structures - -#endif diff --git a/src/osgUtil/TriStrip_tri_stripper.cpp b/src/osgUtil/TriStrip_tri_stripper.cpp deleted file mode 100644 index a84d1cd9b..000000000 --- a/src/osgUtil/TriStrip_tri_stripper.cpp +++ /dev/null @@ -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�. -// For conditions of distribution and use, -// see copyright notice in tri_stripper.h -// -////////////////////////////////////////////////////////////////////// - -#include -#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."<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(-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."<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 diff --git a/src/osgUtil/TriStrip_tri_stripper.h b/src/osgUtil/TriStrip_tri_stripper.h deleted file mode 100644 index 4c89a5f20..000000000 --- a/src/osgUtil/TriStrip_tri_stripper.h +++ /dev/null @@ -1,401 +0,0 @@ -// tri_stripper.h: interface for the tri_stripper class. -// -////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2002 Tanguy Fautr�. -// -// 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� -// 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 - -#include -#include -#include -#include -#include - -#include -#include - -// 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 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_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 triangles_graph; - typedef common_structures::heap_array triangles_heap; - typedef std::vector triangle_edges; - typedef std::vector triangle_indices; - typedef std::deque 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 diff --git a/src/osgUtil/tristripper/include/detail/cache_simulator.h b/src/osgUtil/tristripper/include/detail/cache_simulator.h new file mode 100644 index 000000000..5cd161193 --- /dev/null +++ b/src/osgUtil/tristripper/include/detail/cache_simulator.h @@ -0,0 +1,154 @@ +// +// Copyright (C) 2004 Tanguy Fautré. +// 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 +#include +#include + + + + +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 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::max)()); +} + + +inline void cache_simulator::reset() +{ + std::fill(m_Cache.begin(), m_Cache.end(), (std::numeric_limits::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 diff --git a/src/osgUtil/tristripper/include/detail/connectivity_graph.h b/src/osgUtil/tristripper/include/detail/connectivity_graph.h new file mode 100644 index 000000000..e4c6c3abe --- /dev/null +++ b/src/osgUtil/tristripper/include/detail/connectivity_graph.h @@ -0,0 +1,36 @@ +// +// Copyright (C) 2004 Tanguy Fautré. +// 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 & Triangles, const indices & Indices); + + } + +} + + + + +#endif // TRI_STRIPPER_HEADER_GUARD_CONNECTIVITY_GRAPH_H diff --git a/src/osgUtil/tristripper/include/detail/graph_array.h b/src/osgUtil/tristripper/include/detail/graph_array.h new file mode 100644 index 000000000..51b66c3e3 --- /dev/null +++ b/src/osgUtil/tristripper/include/detail/graph_array.h @@ -0,0 +1,460 @@ +// +// Copyright (C) 2004 Tanguy Fautré. +// 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 +#include +#include +#include +#include + + + + +namespace triangle_stripper { + + namespace detail { + + + + +// graph_array main class +template +class graph_array +{ +public: + + class arc; + class node; + + // New types + typedef size_t nodeid; + typedef nodetype value_type; + typedef std::vector 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 graph_type; + + + // graph_array::arc class + class arc + { + public: + node_iterator terminal() const; + + protected: + friend class graph_array; + + arc(node_iterator Terminal); + + node_iterator m_Terminal; + }; + + + // New types + typedef std::vector 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; + friend class std::vector; + + 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 +void unmark_nodes(graph_array & G); + + + + + +////////////////////////////////////////////////////////////////////////// +// graph_array::arc inline functions +////////////////////////////////////////////////////////////////////////// + +template +inline graph_array::arc::arc(node_iterator Terminal) + : m_Terminal(Terminal) { } + + +template +inline typename graph_array::node_iterator graph_array::arc::terminal() const +{ + return m_Terminal; +} + + + +////////////////////////////////////////////////////////////////////////// +// graph_array::node inline functions +////////////////////////////////////////////////////////////////////////// + +template +inline graph_array::node::node(arc_list & Arcs) + : m_Arcs(Arcs), + m_Begin((std::numeric_limits::max)()), + m_End((std::numeric_limits::max)()), + m_Marker(false) +{ + +} + + +template +inline void graph_array::node::mark() +{ + m_Marker = true; +} + + +template +inline void graph_array::node::unmark() +{ + m_Marker = false; +} + + +template +inline bool graph_array::node::marked() const +{ + return m_Marker; +} + + +template +inline bool graph_array::node::out_empty() const +{ + return (m_Begin == m_End); +} + + +template +inline size_t graph_array::node::out_size() const +{ + return (m_End - m_Begin); +} + + +template +inline typename graph_array::out_arc_iterator graph_array::node::out_begin() +{ + return (m_Arcs.begin() + m_Begin); +} + + +template +inline typename graph_array::out_arc_iterator graph_array::node::out_end() +{ + return (m_Arcs.begin() + m_End); +} + + +template +inline typename graph_array::const_out_arc_iterator graph_array::node::out_begin() const +{ + return (m_Arcs.begin() + m_Begin); +} + + +template +inline typename graph_array::const_out_arc_iterator graph_array::node::out_end() const +{ + return (m_Arcs.begin() + m_End); +} + + +template +inline N & graph_array::node::operator * () +{ + return m_Elem; +} + + +template +inline N * graph_array::node::operator -> () +{ + return &m_Elem; +} + + +template +inline const N & graph_array::node::operator * () const +{ + return m_Elem; +} + + +template +inline const N * graph_array::node::operator -> () const +{ + return &m_Elem; +} + + +template +inline N & graph_array::node::operator = (const N & Elem) +{ + return (m_Elem = Elem); +} + + + +////////////////////////////////////////////////////////////////////////// +// graph_array inline functions +////////////////////////////////////////////////////////////////////////// + +template +inline graph_array::graph_array() { } + + +template +inline graph_array::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 +inline bool graph_array::empty() const +{ + return m_Nodes.empty(); +} + + +template +inline size_t graph_array::size() const +{ + return m_Nodes.size(); +} + + +template +inline typename graph_array::node & graph_array::operator [] (const nodeid i) +{ + assert(i < size()); + + return m_Nodes[i]; +} + + +template +inline const typename graph_array::node & graph_array::operator [] (const nodeid i) const +{ + assert(i < size()); + + return m_Nodes[i]; +} + + +template +inline typename graph_array::node_iterator graph_array::begin() +{ + return m_Nodes.begin(); +} + + +template +inline typename graph_array::node_iterator graph_array::end() +{ + return m_Nodes.end(); +} + + +template +inline typename graph_array::const_node_iterator graph_array::begin() const +{ + return m_Nodes.begin(); +} + + +template +inline typename graph_array::const_node_iterator graph_array::end() const +{ + return m_Nodes.end(); +} + + +template +inline typename graph_array::node_reverse_iterator graph_array::rbegin() +{ + return m_Nodes.rbegin(); +} + + +template +inline typename graph_array::node_reverse_iterator graph_array::rend() +{ + return m_Nodes.rend(); +} + + +template +inline typename graph_array::const_node_reverse_iterator graph_array::rbegin() const +{ + return m_Nodes.rbegin(); +} + + +template +inline typename graph_array::const_node_reverse_iterator graph_array::rend() const +{ + return m_Nodes.rend(); +} + + +template +inline typename graph_array::out_arc_iterator graph_array::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 +inline typename graph_array::out_arc_iterator graph_array::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 +inline void graph_array::swap(graph_type & Right) +{ + std::swap(m_Nodes, Right.m_Nodes); + std::swap(m_Arcs, Right.m_Arcs); +} + + + +////////////////////////////////////////////////////////////////////////// +// additional functions +////////////////////////////////////////////////////////////////////////// + +template +inline void unmark_nodes(graph_array & G) +{ + std::for_each(G.begin(), G.end(), std::mem_fun_ref(&graph_array::node::unmark)); +} + + + + + } // namespace detail + +} // namespace triangle_stripper + + + + +#endif // TRI_STRIPPER_HEADER_GUARD_GRAPH_ARRAY_H diff --git a/src/osgUtil/tristripper/include/detail/heap_array.h b/src/osgUtil/tristripper/include/detail/heap_array.h new file mode 100644 index 000000000..971b805bd --- /dev/null +++ b/src/osgUtil/tristripper/include/detail/heap_array.h @@ -0,0 +1,297 @@ +// +// Copyright (C) 2004 Tanguy Fautré. +// 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 + + + + +namespace triangle_stripper { + + namespace detail { + + + + +// mutable heap +// can be interfaced pretty muck like an array +template > +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 linked_heap; + typedef std::vector 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 +inline void heap_array::clear() +{ + m_Heap.clear(); + m_Finder.clear(); + m_Locked = false; +} + + +template +inline bool heap_array::empty() const +{ + return m_Heap.empty(); +} + + +template +inline bool heap_array::locked() const +{ + return m_Locked; +} + + +template +inline void heap_array::reserve(const size_t Size) +{ + m_Heap.reserve(Size); + m_Finder.reserve(Size); +} + + +template +inline size_t heap_array::size() const +{ + return m_Heap.size(); +} + + +template +inline const T & heap_array::top() const +{ + assert(! empty()); + + return m_Heap.front().m_Elem; +} + + +template +inline const T & heap_array::peek(const size_t i) const +{ + assert(! removed(i)); + + return (m_Heap[m_Finder[i]].m_Elem); +} + + +template +inline const T & heap_array::operator [] (const size_t i) const +{ + return peek(i); +} + + +template +inline void heap_array::pop() +{ + assert(locked()); + assert(! empty()); + + Swap(0, size() - 1); + m_Heap.pop_back(); + + if (! empty()) + Adjust(0); +} + + +template +inline void heap_array::lock() +{ + assert(! locked()); + + m_Locked =true; +} + + +template +inline size_t heap_array::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 +inline void heap_array::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 +inline bool heap_array::removed(const size_t i) const +{ + assert(valid(i)); + + return (m_Finder[i] >= m_Heap.size()); +} + + +template +inline bool heap_array::valid(const size_t i) const +{ + return (i < m_Finder.size()); +} + + +template +inline size_t heap_array::position(const size_t i) const +{ + assert(valid(i)); + + return (m_Heap[i].m_Index); +} + + +template +inline void heap_array::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 +inline void heap_array::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 +inline void heap_array::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 +inline bool heap_array::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 diff --git a/src/osgUtil/tristripper/include/detail/policy.h b/src/osgUtil/tristripper/include/detail/policy.h new file mode 100644 index 000000000..4c126c598 --- /dev/null +++ b/src/osgUtil/tristripper/include/detail/policy.h @@ -0,0 +1,66 @@ +// +// Copyright (C) 2004 Tanguy Fautré. +// 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 diff --git a/src/osgUtil/tristripper/include/detail/types.h b/src/osgUtil/tristripper/include/detail/types.h new file mode 100644 index 000000000..ff7b026a0 --- /dev/null +++ b/src/osgUtil/tristripper/include/detail/types.h @@ -0,0 +1,101 @@ +// +// Copyright (C) 2004 Tanguy Fautré. +// 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 diff --git a/src/osgUtil/tristripper/include/public_types.h b/src/osgUtil/tristripper/include/public_types.h new file mode 100644 index 000000000..66cca5cf1 --- /dev/null +++ b/src/osgUtil/tristripper/include/public_types.h @@ -0,0 +1,43 @@ +// +// Copyright (C) 2004 Tanguy Fautré. +// 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 + + + + +namespace triangle_stripper +{ + + typedef size_t index; + typedef std::vector 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_vector; + +} + + + + +#endif // TRI_STRIPPER_HEADER_GUARD_PUBLIC_TYPES_H diff --git a/src/osgUtil/tristripper/include/tri_stripper.h b/src/osgUtil/tristripper/include/tri_stripper.h new file mode 100644 index 000000000..0951711c3 --- /dev/null +++ b/src/osgUtil/tristripper/include/tri_stripper.h @@ -0,0 +1,178 @@ + +////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2004 Tanguy Fautré. +// +// 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é +// 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 triangle_graph; + typedef detail::heap_array > triangle_heap; + typedef std::vector 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 diff --git a/src/osgUtil/tristripper/src/connectivity_graph.cpp b/src/osgUtil/tristripper/src/connectivity_graph.cpp new file mode 100644 index 000000000..81def731b --- /dev/null +++ b/src/osgUtil/tristripper/src/connectivity_graph.cpp @@ -0,0 +1,132 @@ +// +// Copyright (C) 2004 Tanguy Fautré. +// 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 + + + + +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 edge_map; + + + void LinkNeighbours(graph_array & Triangles, const edge_map & EdgeMap, const tri_edge Edge); + +} + + + + +void make_connectivity_graph(graph_array & 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 & 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 + diff --git a/src/osgUtil/tristripper/src/policy.cpp b/src/osgUtil/tristripper/src/policy.cpp new file mode 100644 index 000000000..a0a8e1011 --- /dev/null +++ b/src/osgUtil/tristripper/src/policy.cpp @@ -0,0 +1,63 @@ +// +// Copyright (C) 2004 Tanguy Fautré. +// 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 diff --git a/src/osgUtil/tristripper/src/tri_stripper.cpp b/src/osgUtil/tristripper/src/tri_stripper.cpp new file mode 100644 index 000000000..2f5a7f3c3 --- /dev/null +++ b/src/osgUtil/tristripper/src/tri_stripper.cpp @@ -0,0 +1,554 @@ +// +// Copyright (C) 2004 Tanguy Fautré. +// 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 + + + + +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