diff --git a/NifExport/TriStripper/cache_simulator.h b/NifExport/TriStripper/cache_simulator.h new file mode 100755 index 0000000000000000000000000000000000000000..edad27da2a52f84212b7a3cc6f2e866bc6899992 --- /dev/null +++ b/NifExport/TriStripper/cache_simulator.h @@ -0,0 +1,92 @@ + +#pragma once + + + +// namespace triangle_stripper +namespace triangle_stripper { + + + + +// FIFO Cache simulator +class cache_simulator +{ +public: + + typedef unsigned int index; + + cache_simulator(); + + void clear(); + void resize(const size_t Size); + void reset(); + size_t size() const; + + void push(const index i, const bool CountCacheHit = false); + + void ResetHitCount(); + size_t HitCount() const; + +protected: + typedef std::deque<index> indices_deque; + + indices_deque m_Cache; + size_t m_NbHits; +}; + + + + +inline cache_simulator::cache_simulator() : m_NbHits(0) { } + + +inline void cache_simulator::clear() { + m_Cache.clear(); +} + + +inline void cache_simulator::resize(const size_t Size) { + m_Cache.resize(Size, static_cast<index>(-1)); +} + + +inline void cache_simulator::reset() { + std::fill(m_Cache.begin(), m_Cache.end(), static_cast<index>(-1)); + ResetHitCount(); +} + + +inline size_t cache_simulator::size() const { + return m_Cache.size(); +} + + +inline void cache_simulator::push(const index i, const bool CountCacheHit) { + + // Should we count the cache hits? + if (CountCacheHit) { + if (std::find(m_Cache.begin(), m_Cache.end(), i) != m_Cache.end()) + ++m_NbHits; + } + + // Manage the indices cache as a FIFO structure + m_Cache.push_front(i); + m_Cache.pop_back(); +} + + +inline void cache_simulator::ResetHitCount() { + m_NbHits = 0; +} + + +inline size_t cache_simulator::HitCount() const { + return m_NbHits; +} + + + +} // namespace triangle_stripper + + diff --git a/NifExport/TriStripper/graph_array.h b/NifExport/TriStripper/graph_array.h new file mode 100755 index 0000000000000000000000000000000000000000..0d85c687a41966a88a18ca05c42cac0ff52abb96 --- /dev/null +++ b/NifExport/TriStripper/graph_array.h @@ -0,0 +1,428 @@ +// 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 5 (17/04/2003) +// +// 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 6 (22/09/2003) - Improved std C++ compliance +// - 3.00 BETA 5 (17/04/2003) - Fixed template graph related functions +// - 3.00 BETA 4 (11/12/2002) - Fixed a typo in erase_arcs +// - 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 +// +////////////////////////////////////////////////////////////////////// + +#pragma once + + + +// namespace common_structures +namespace common_structures { + + + + +// graph_array main class +template <class nodetype, class arctype> +class graph_array +{ +public: + + class arc; + class node; + + // New types + typedef size_t nodeid; + typedef typename std::vector<node>::iterator node_iterator; + typedef typename std::vector<node>::const_iterator const_node_iterator; + typedef typename std::vector<node>::reverse_iterator node_reverse_iterator; + typedef typename std::vector<node>::const_reverse_iterator const_node_reverse_iterator; + + typedef graph_array<nodetype, arctype> _mytype; + + + // graph_array::arc class + class arc + { + public: + arc & 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; } + arctype * operator -> () { return &m_Elem; } + const arctype & operator * () const { return m_Elem; } + const arctype * operator -> () const { return &m_Elem; } + + protected: + friend class graph_array<nodetype, arctype>; + + arc(const node_iterator & Initial, const node_iterator & Terminal) + : m_Initial(Initial), m_Terminal(Terminal), m_Marker(false) { } + + arc(const node_iterator & Initial, const node_iterator & Terminal, const arctype & Elem) + : m_Initial(Initial), m_Terminal(Terminal), m_Elem(Elem), m_Marker(false) { } + + node_iterator m_Initial; + node_iterator m_Terminal; + arctype m_Elem; + bool m_Marker; + }; + + + // New types + typedef typename std::list<arc>::iterator out_arc_iterator; + typedef typename std::list<arc>::const_iterator const_out_arc_iterator; + + + // graph_array::node class + class node + { + public: + node & mark() { m_Marker = true; return (* this); } + node & unmark() { m_Marker = false; return (* this); } + bool marked() const { return m_Marker; } + + bool out_empty() const { return m_OutArcs.empty(); } + size_t number_of_out_arcs() const { return m_OutArcs.size(); } + + out_arc_iterator out_begin() { return m_OutArcs.begin(); } + out_arc_iterator out_end() { return m_OutArcs.end(); } + const_out_arc_iterator out_begin() const { return m_OutArcs.begin(); } + const_out_arc_iterator out_end() const { return m_OutArcs.end(); } + + nodetype & operator * () { return m_Elem; } + nodetype * operator -> () { return &m_Elem; } + const nodetype & operator * () const { return m_Elem; } + const nodetype * operator -> () const { return &m_Elem; } + + nodetype & operator = (const nodetype & Elem) { return (m_Elem = Elem); } + + protected: + friend class graph_array<nodetype, arctype>; + friend class std::vector<node>; + + node() : m_Marker(false) { } + + std::list<arc> m_OutArcs; + nodetype m_Elem; + bool m_Marker; + }; + + + // Construction/Destruction + graph_array(); + explicit graph_array(const size_t NbNodes); + + // Node related member functions + void clear(); + bool empty() const; + void setsize(const size_t NbNodes); + size_t size() const; + + node & operator [] (const nodeid & i); + const node & operator [] (const nodeid & i) const; + + node_iterator begin(); + node_iterator end(); + const_node_iterator begin() const; + const_node_iterator end() const; + + node_reverse_iterator rbegin(); + node_reverse_iterator rend(); + const_node_reverse_iterator rbegin() const; + const_node_reverse_iterator rend() const; + + // Arc related member functions + size_t number_of_arcs() const; + + void erase_arcs(); + void erase_arcs(const node_iterator & Initial); + out_arc_iterator erase_arc(const out_arc_iterator & Pos); + + out_arc_iterator insert_arc(const nodeid & Initial, const nodeid & Terminal); + out_arc_iterator insert_arc(const nodeid & Initial, const nodeid & Terminal, const arctype & Elem); + out_arc_iterator insert_arc(const node_iterator & Initial, const node_iterator & Terminal); + out_arc_iterator insert_arc(const node_iterator & Initial, const node_iterator & Terminal, const arctype & Elem); + + // Another interface for insert_arc + out_arc_iterator insert(const nodeid & Initial, const nodeid & Terminal) { return insert_arc(Initial, Terminal); } + out_arc_iterator insert(const nodeid & Initial, const nodeid & Terminal, const arctype & Elem) { return insert_arc(Initial, Terminal, Elem); } + out_arc_iterator insert(const node_iterator & Initial, const node_iterator & Terminal) { return insert_arc(Initial, Terminal); } + out_arc_iterator insert(const node_iterator & Initial, const node_iterator & Terminal, const arctype & Elem) { return insert_arc(Initial, Terminal, Elem); } + + // Optimized (overloaded) functions + void swap(_mytype & Right); + friend void swap(_mytype & Left, _mytype & Right) { Left.swap(Right); } + +protected: + size_t m_NbArcs; + std::vector<node> m_Nodes; +}; + + + +// Additional "low level", graph related, functions +template <class nodetype, class arctype> +void unmark_nodes(graph_array<nodetype, arctype> & G); + +template <class graph_node> +void unmark_arcs_from_node(graph_node & N); + +template <class nodetype, class arctype> +void unmark_arcs(graph_array<nodetype, arctype> & G); + +class unmark_arc +{ +public: + template <class A> + void operator () (A & Arc) const { Arc.unmark(); } +}; + + + + +////////////////////////////////////////////////////////////////////////// +// graph_array Inline functions +////////////////////////////////////////////////////////////////////////// + +template <class nodetype, class arctype> +inline graph_array<nodetype, arctype>::graph_array() : m_NbArcs(0) { } + + +template <class nodetype, class arctype> +inline graph_array<nodetype, arctype>::graph_array(const size_t NbNodes) : m_NbArcs(0), m_Nodes(NbNodes) { } + + +template <class nodetype, class arctype> +inline void graph_array<nodetype, arctype>::clear() { + m_NbArcs = 0; + m_Nodes.clear(); +} + + + +template <class nodetype, class arctype> +inline bool graph_array<nodetype, arctype>::empty() const { + return m_Nodes.empty(); +} + + +template <class nodetype, class arctype> +inline size_t graph_array<nodetype, arctype>::size() const { + return m_Nodes.size(); +} + + +template <class nodetype, class arctype> +inline void graph_array<nodetype, arctype>::setsize(const size_t NbNodes) { + clear(); + m_Nodes.resize(NbNodes); +} + + +template <class nodetype, class arctype> +inline typename graph_array<nodetype, arctype>::node & graph_array<nodetype, arctype>::operator [] (const nodeid & i) { + // Debug check + assert(i < size()); + + return m_Nodes[i]; +} + + +template <class nodetype, class arctype> +inline const typename graph_array<nodetype, arctype>::node & graph_array<nodetype, arctype>::operator [] (const nodeid & i) const { + // Debug check + assert(i < size()); + + return m_Nodes[i]; +} + + +template <class nodetype, class arctype> +inline typename graph_array<nodetype, arctype>::node_iterator graph_array<nodetype, arctype>::begin() { + return m_Nodes.begin(); +} + + +template <class nodetype, class arctype> +inline typename graph_array<nodetype, arctype>::node_iterator graph_array<nodetype, arctype>::end() { + return m_Nodes.end(); +} + + +template <class nodetype, class arctype> +inline typename graph_array<nodetype, arctype>::const_node_iterator graph_array<nodetype, arctype>::begin() const { + return m_Nodes.begin(); +} + + +template <class nodetype, class arctype> +inline typename graph_array<nodetype, arctype>::const_node_iterator graph_array<nodetype, arctype>::end() const { + return m_Nodes.end(); +} + + +template <class nodetype, class arctype> +inline typename graph_array<nodetype, arctype>::node_reverse_iterator graph_array<nodetype, arctype>::rbegin() { + return m_Nodes.rbegin(); +} + + +template <class nodetype, class arctype> +inline typename graph_array<nodetype, arctype>::node_reverse_iterator graph_array<nodetype, arctype>::rend() { + return m_Nodes.rend(); +} + + +template <class nodetype, class arctype> +inline typename graph_array<nodetype, arctype>::const_node_reverse_iterator graph_array<nodetype, arctype>::rbegin() const { + return m_Nodes.rbegin(); +} + + +template <class nodetype, class arctype> +inline typename graph_array<nodetype, arctype>::const_node_reverse_iterator graph_array<nodetype, arctype>::rend() const { + return m_Nodes.rend(); +} + + +template <class nodetype, class arctype> +inline size_t graph_array<nodetype, arctype>::number_of_arcs() const { + return m_NbArcs; +} + + +template <class nodetype, class arctype> +inline typename graph_array<nodetype, arctype>::out_arc_iterator graph_array<nodetype, arctype>::insert_arc(const nodeid & Initial, const nodeid & Terminal) { + return (insert(begin() + Initial, begin() + Terminal)); +} + + +template <class nodetype, class arctype> +inline typename graph_array<nodetype, arctype>::out_arc_iterator graph_array<nodetype, arctype>::insert_arc(const nodeid & Initial, const nodeid & Terminal, const arctype & Elem) { + return (insert(begin() + Initial, begin() + Terminal, Elem)); +} + + +template <class nodetype, class arctype> +inline typename graph_array<nodetype, arctype>::out_arc_iterator graph_array<nodetype, arctype>::insert_arc(const node_iterator & Initial, const node_iterator & Terminal) { + ++m_NbArcs; + Initial->m_OutArcs.push_back(arc(Initial, Terminal)); + return (--(Initial->m_OutArcs.end())); +} + + +template <class nodetype, class arctype> +inline typename graph_array<nodetype, arctype>::out_arc_iterator graph_array<nodetype, arctype>::insert_arc(const node_iterator & Initial, const node_iterator & Terminal, const arctype & Elem) { + ++m_NbArcs; + Initial->m_OutArcs.push_back(arc(Initial, Terminal, Elem)); + return (--(Initial->m_OutArcs.end())); +} + + +template <class nodetype, class arctype> +inline typename graph_array<nodetype, arctype>::out_arc_iterator graph_array<nodetype, arctype>::erase_arc(const out_arc_iterator & Pos) { + --m_NbArcs; + return (Pos->initial()->m_OutArcs.erase(Pos)); +} + + +template <class nodetype, class arctype> +inline void graph_array<nodetype, arctype>::erase_arcs(const node_iterator & Initial) { + m_NbArcs -= (Initial->m_OutArcs.size()); + Initial->m_OutArcs.clear(); +} + + +template <class nodetype, class arctype> +inline void graph_array<nodetype, arctype>::erase_arcs() { + m_NbArcs = 0; + for (nodeid i = 0; i < size(); ++i) + m_Nodes[i].m_OutArcs.clear(); +} + + +template <class nodetype, class arctype> +inline void graph_array<nodetype, arctype>::swap(_mytype & Right) { + std::swap(m_NbArcs, Right.m_NbArcs); + std::swap(m_Nodes, Right.m_Nodes); +} + + + +////////////////////////////////////////////////////////////////////////// +// additional functions +////////////////////////////////////////////////////////////////////////// + +template <class nodetype, class arctype> +void unmark_nodes(graph_array<nodetype, arctype> & G) +{ + typedef typename graph_array<nodetype, arctype>::node_iterator node_it; + + for (node_it NodeIt = G.begin(); NodeIt != G.end(); ++NodeIt) + NodeIt->unmark(); +} + + +template <class graph_node> +void unmark_arcs_from_node(graph_node & N) +{ + std::for_each(N.out_begin(), N.out_end(), unmark_arc()); +} + + +template <class nodetype, class arctype> +void unmark_arcs(graph_array<nodetype, arctype> & G) +{ + typedef typename graph_array<nodetype, arctype>::node_iterator node_it; + + for (node_it NodeIt = G.begin(); NodeIt != G.end(); ++NodeIt) + unmark_arcs_from_node(* NodeIt); +} + + + + +} // namespace common_structures diff --git a/NifExport/TriStripper/heap_array.h b/NifExport/TriStripper/heap_array.h new file mode 100755 index 0000000000000000000000000000000000000000..1cd0ad8c0dc51e82dafd037460f80e8ed07e8273 --- /dev/null +++ b/NifExport/TriStripper/heap_array.h @@ -0,0 +1,276 @@ +// 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 index. +// +// History: - +// +////////////////////////////////////////////////////////////////////// + +#pragma once + + + +// namespace common_structures +namespace common_structures { + + + + +template <class T, class CmpT = std::less<T> > +class heap_array +{ +public: + + struct heap_is_locked { }; + + + // heap_array main interface. Pre = PreCondition, Post = PostCondition + + heap_array() : m_Locked(false) { } // Post: ((size() == 0) && ! locked()) + + void clear(); // Post: ((size() == 0) && ! locked()) + + void reserve(size_t Size); + size_t size() const; + + bool empty() const; + bool locked() const; + bool removed(size_t i) const; // Pre: (valid(i)) + bool valid(size_t i) const; + + const T & top() const; // Pre: (! empty()) + const T & peek(size_t i) const; // Pre: (valid(i) && ! removed(i)) + const T & operator [] (size_t i) const; // Pre: (valid(i) && ! removed(i)) + + size_t push(const T & Elem); // Pre: (! locked()) else throw (heap_is_locked) + + void pop(); // Pre: (! empty()) Post: (locked()) + void erase(size_t i); // Pre: (valid(i) && ! removed(i)) Post: (locked()) + void update(size_t i, const T & Elem); // Pre: (valid(i) && ! removed(i)) Post: (locked()) + +protected: + + struct linker { + linker(const T & Elem, size_t i) : m_Elem(Elem), m_Index(i) { } + + T m_Elem; + size_t m_Index; + }; + + typedef std::vector<linker> linked_heap; + typedef std::vector<size_t> finder; + + void Adjust(size_t i); + void Swap(size_t a, size_t b); + bool Less(const linker & a, const linker & b) const; + + linked_heap m_Heap; + finder m_Finder; + CmpT m_Compare; + bool m_Locked; +}; + + + + +////////////////////////////////////////////////////////////////////////// +// heap_indexed Inline functions +////////////////////////////////////////////////////////////////////////// + +template <class T, class CmpT> +inline void heap_array<T, CmpT>::clear() { + m_Heap.clear(); + m_Finder.clear(); + m_Locked = false; +} + + +template <class T, class CmpT> +inline bool heap_array<T, CmpT>::empty() const { + return m_Heap.empty(); +} + + +template <class T, class CmpT> +inline bool heap_array<T, CmpT>::locked() const { + return m_Locked; +} + + +template <class T, class CmpT> +inline void heap_array<T, CmpT>::reserve(size_t Size) { + m_Heap.reserve(Size); + m_Finder.reserve(Size); +} + + +template <class T, class CmpT> +inline size_t heap_array<T, CmpT>::size() const { + return m_Heap.size(); +} + + +template <class T, class CmpT> +inline const T & heap_array<T, CmpT>::top() const { + // Debug check to ensure heap is not empty + assert(! empty()); + + return m_Heap.front().m_Elem; +} + + +template <class T, class CmpT> +inline const T & heap_array<T, CmpT>::peek(size_t i) const { + // Debug check to ensure element is still present + assert(! removed(i)); + + return (m_Heap[m_Finder[i]].m_Elem); +} + + +template <class T, class CmpT> +inline const T & heap_array<T, CmpT>::operator [] (size_t i) const { + return peek(i); +} + + +template <class T, class CmpT> +inline void heap_array<T, CmpT>::pop() { + m_Locked = true; + + // Debug check to ensure heap is not empty + assert(! empty()); + + Swap(0, size() - 1); + m_Heap.pop_back(); + Adjust(0); +} + + +template <class T, class CmpT> +inline size_t heap_array<T, CmpT>::push(const T & Elem) { + if (m_Locked) + throw heap_is_locked(); + + size_t Id = size(); + m_Finder.push_back(Id); + m_Heap.push_back(linker(Elem, Id)); + Adjust(Id); + + return Id; +} + + +template <class T, class CmpT> +inline void heap_array<T, CmpT>::erase(size_t i) { + m_Locked = true; + + // Debug check to ensure element is still present + assert(! removed(i)); + + size_t j = m_Finder[i]; + Swap(j, size() - 1); + m_Heap.pop_back(); + Adjust(j); +} + + +template <class T, class CmpT> +inline bool heap_array<T, CmpT>::removed(size_t i) const { + return (m_Finder[i] >= m_Heap.size()); +} + + +template <class T, class CmpT> +inline bool heap_array<T, CmpT>::valid(size_t i) const { + return (i < m_Finder.size()); +} + + +template <class T, class CmpT> +inline void heap_array<T, CmpT>::update(size_t i, const T & Elem) { + // Debug check to ensure element is still present + assert(! removed(i)); + + size_t j = m_Finder[i]; + m_Heap[j].m_Elem = Elem; + Adjust(j); +} + + +template <class T, class CmpT> +inline void heap_array<T, CmpT>::Adjust(size_t i) { + size_t j; + + // Check the upper part of the heap + for (j = i; (j > 0) && (Less(m_Heap[(j - 1) / 2], m_Heap[j])); j = ((j - 1) / 2)) + Swap(j, (j - 1) / 2); + + // Check the lower part of the heap + for (i = j; (j = 2 * i + 1) < size(); i = j) { + if ((j + 1 < size()) && (Less(m_Heap[j], m_Heap[j + 1]))) + ++j; + + if (Less(m_Heap[j], m_Heap[i])) + return; + + Swap(i, j); + } +} + + +template <class T, class CmpT> +inline void heap_array<T, CmpT>::Swap(size_t a, size_t b) { + std::swap(m_Heap[a], m_Heap[b]); + + // use (size_t &) to get rid of a bogus compile warning + (size_t &) (m_Finder[(m_Heap[a].m_Index)]) = a; + (size_t &) (m_Finder[(m_Heap[b].m_Index)]) = b; +} + + +template <class T, class CmpT> +inline bool heap_array<T, CmpT>::Less(const linker & a, const linker & b) const { + return m_Compare(a.m_Elem, b.m_Elem); +} + + + + +} // namespace common_structures + diff --git a/NifExport/TriStripper/tri_stripper.cpp b/NifExport/TriStripper/tri_stripper.cpp new file mode 100755 index 0000000000000000000000000000000000000000..3c1d44d3eee2f6f6f0021b171d8661bc5de6d5a7 --- /dev/null +++ b/NifExport/TriStripper/tri_stripper.cpp @@ -0,0 +1,568 @@ +// 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 <assert.h> +#include <deque> +#include <algorithm> +#include <fstream> +#include <iostream> +#include <list> +#include <map> +#include <string> +#include <vector> + +#include "tri_stripper.h" + + + + +// namespace triangle_stripper +namespace triangle_stripper { + + + + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + + + +////////////////////////////////////////////////////////////////////// +// Members Functions +////////////////////////////////////////////////////////////////////// + +void tri_stripper::Strip(primitives_vector * out_pPrimitivesVector) +{ + // verify that the number of indices is correct + if (m_TriIndices.size() % 3 != 0) + throw triangles_indices_error(); + + // clear possible garbage + m_PrimitivesVector.clear(); + out_pPrimitivesVector->clear(); + + // Initialize the triangle graph + InitTriGraph(); + + // Initialize the triangle priority queue + InitTriHeap(); + + // Reset the cache simulator + InitCache(); + + // Launch the triangle strip generator + Stripify(); + + // 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)); +} + + + +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); + + for (size_t 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 (size_t 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 (size_t 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_Cache.reset(); +} + + + +void 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) + BuildStrip(TriStrip); + } + + // 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(); + } +} + + + +inline tri_stripper::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 + const cache_simulator CacheBackup = m_Cache; + + 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) { + + // Try a new strip with that triangle in a particular direction + const triangle_strip TempStrip = ExtendTriToStrip(CandidateTri, triangle_strip::start_order(i)); + + // 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_Cache.size() == 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_Cache.HitCount() > BestStripCacheHits) { + BestStrip = TempStrip; + BestStripDegree = m_TriHeap[TempStrip.StartTriPos()].Degree(); + BestStripCacheHits = m_Cache.HitCount(); + + } else if (m_Cache.HitCount() == 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(); + } + } + } + } + + // Restore the cache (modified by ExtendTriToStrip) and implicitly reset the cache hit count + m_Cache = CacheBackup; + } + + } + + return BestStrip; +} + + + +tri_stripper::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 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_Cache.size() == 0) || ((Size + 2) < m_Cache.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 ((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; + AddIndexToCache(Tri.C(), true); + break; + } + + else if ((Edge.B() == Tri.B()) && (Edge.A() == Tri.C())) { + Order = (ClockWise) ? triangle_strip::BCA : triangle_strip::CAB; + AddIndexToCache(Tri.A(), true); + break; + } + + else if ((Edge.B() == Tri.C()) && (Edge.A() == Tri.A())) { + Order = (ClockWise) ? triangle_strip::CAB : triangle_strip::ABC; + AddIndexToCache(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); +} + + + +inline tri_stripper::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); + } +} + + + +void 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; + AddIndex(Tri.C()); + break; + } + + else if ((Edge.B() == Tri.B()) && (Edge.A() == Tri.C())) { + Order = (ClockWise) ? triangle_strip::BCA : triangle_strip::CAB; + AddIndex(Tri.A()); + break; + } + + else if ((Edge.B() == Tri.C()) && (Edge.A() == Tri.A())) { + Order = (ClockWise) ? triangle_strip::CAB : triangle_strip::ABC; + AddIndex(Tri.B()); + break; + } + } + } + + // Debug check: we must have found the next triangle + assert(LinkIt != TriNodeIt->out_end()); + + // Go to the next triangle + TriNodeIt = LinkIt->terminal(); + MarkTriAsTaken(TriNodeIt - m_Triangles.begin()); + + // Setup for the next triangle + ClockWise = ! ClockWise; + } +} + + + +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_Cache.size() > 0) && (NewDegree.Degree() > 0)) + m_NextCandidates.push_back(j); + } + } +} + + + +inline void tri_stripper::AddIndexToCache(const index i, bool CacheHitCount) +{ + // Cache simulator enabled? + if (m_Cache.size() > 0) + m_Cache.push(i, CacheHitCount); +} + + + +inline void tri_stripper::AddIndex(const index i) +{ + // Add the index to the current indices array + m_PrimitivesVector.back().m_Indices.push_back(i); + + // Run cache simulator + AddIndexToCache(i); +} + + + +inline 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: + AddIndexToCache(Tri.A(), true); + AddIndexToCache(Tri.B(), true); + AddIndexToCache(Tri.C(), true); + return; + case triangle_strip::BCA: + AddIndexToCache(Tri.B(), true); + AddIndexToCache(Tri.C(), true); + AddIndexToCache(Tri.A(), true); + return; + case triangle_strip::CAB: + AddIndexToCache(Tri.C(), true); + AddIndexToCache(Tri.A(), true); + AddIndexToCache(Tri.B(), true); + return; + } +} + + + +inline 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: + AddIndex(Tri.A()); + AddIndex(Tri.B()); + AddIndex(Tri.C()); + return; + case triangle_strip::BCA: + AddIndex(Tri.B()); + AddIndex(Tri.C()); + AddIndex(Tri.A()); + return; + case triangle_strip::CAB: + AddIndex(Tri.C()); + AddIndex(Tri.A()); + AddIndex(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/NifExport/TriStripper/tri_stripper.h b/NifExport/TriStripper/tri_stripper.h new file mode 100755 index 0000000000000000000000000000000000000000..45e0f7a61802adee8a76621ab65b7add4a6ef8a5 --- /dev/null +++ b/NifExport/TriStripper/tri_stripper.h @@ -0,0 +1,385 @@ +// 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. +// 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 Final (23/04/2003) +// +// 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 10-16 for GeForce 3/4.) +// +// History: - 1.00 FINAL (23/04/2003) - Separated cache simulator into another class +// - Fixed English: "indice" -> "index" +// - Fixed one or two points for better compatibility +// with newer compilers (VC++ .NET 2003) +// - 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 +// +////////////////////////////////////////////////////////////////////// + +#pragma once + + + + +#include "cache_simulator.h" + + + + +// namespace triangle_stripper +namespace triangle_stripper { + + + + +#include "graph_array.h" +#include "heap_array.h" + + + +class tri_stripper +{ +public: + + // New Public types + typedef unsigned int index; + typedef std::vector<index> indices; + + enum primitive_type { + PT_Triangles = 0x0004, // = GL_TRIANGLES + PT_Triangle_Strip = 0x0005 // = GL_TRIANGLE_STRIP + }; + + struct primitives + { + indices m_Indices; + primitive_type m_Type; + }; + + typedef std::vector<primitives> primitives_vector; + + struct triangles_indices_error { }; + + + // constructor/initializer + tri_stripper(const indices & TriIndices); + + // Settings functions + void SetCacheSize(const size_t CacheSize = 16); // = 0 will disable the cache optimizer + void SetMinStripSize(const size_t MinStripSize = 2); + + // Stripper + void Strip(primitives_vector * out_pPrimitivesVector); // throw triangles_indices_error(); + +private: + + friend struct _cmp_tri_interface_lt; + + + class triangle + { + public: + triangle(); + triangle(const index A, const index B, const index C); + + void SetStripID(const size_t StripID); + + index A() const; + index B() const; + index C() const; + size_t StripID() const; + + private: + index m_A; + index m_B; + index m_C; + size_t m_StripID; + }; + + + class triangle_edge + { + public: + triangle_edge(const index A, const index B, const size_t TriPos); + + index A() const; + index B() const; + size_t TriPos() const; + + private: + index m_A; + index 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; + }; + + + typedef common_structures::graph_array<triangle, char> triangles_graph; + typedef common_structures::heap_array<triangle_degree, _cmp_tri_degree_gt> triangles_heap; + typedef std::vector<triangle_edge> triangle_edges; + typedef std::vector<size_t> triangle_indices; + typedef std::deque<index> indices_cache; + + + void InitCache(); + void InitTriGraph(); + void InitTriHeap(); + void 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); + void BuildStrip(const triangle_strip TriStrip); + void AddIndex(const index i); + void AddIndexToCache(const index 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; + cache_simulator m_Cache; +// 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; + m_Cache.resize(CacheSize); +} + + +inline void tri_stripper::SetMinStripSize(const size_t MinStripSize) { + m_MinStripSize = MinStripSize; +} + + +inline tri_stripper::triangle::triangle() { } + + +inline tri_stripper::triangle::triangle(const index A, const index B, const index C) : m_A(A), m_B(B), m_C(C), m_StripID(0) { } + + +inline void tri_stripper::triangle::SetStripID(const size_t StripID) { + m_StripID = StripID; +} + + +inline tri_stripper::index tri_stripper::triangle::A() const { + return m_A; +} + + +inline tri_stripper::index tri_stripper::triangle::B() const { + return m_B; +} + + +inline tri_stripper::index tri_stripper::triangle::C() const { + return m_C; +} + + +inline size_t tri_stripper::triangle::StripID() const { + return m_StripID; +} + + +inline tri_stripper::triangle_edge::triangle_edge(const index A, const index B, const size_t TriPos) : m_A(A), m_B(B), m_TriPos(TriPos) { } + + +inline tri_stripper::index tri_stripper::triangle_edge::A() const { + return m_A; +} + + +inline tri_stripper::index tri_stripper::triangle_edge::B() const { + return m_B; +} + + +inline size_t tri_stripper::triangle_edge::TriPos() const { + return m_TriPos; +} + + +inline tri_stripper::triangle_degree::triangle_degree() { } + + +inline tri_stripper::triangle_degree::triangle_degree(const size_t TriPos, const size_t Degree) : m_TriPos(TriPos), m_Degree(Degree) { } + + +inline size_t tri_stripper::triangle_degree::Degree() const { + return m_Degree; +} + + +inline size_t tri_stripper::triangle_degree::TriPos() const { + return m_TriPos; +} + + +inline void tri_stripper::triangle_degree::SetDegree(const size_t Degree) { + m_Degree = Degree; +} + + +inline tri_stripper::triangle_strip::triangle_strip() : m_StartTriPos(0), m_StartOrder(ABC), m_Size(0) { } + + +inline tri_stripper::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 tri_stripper::triangle_strip::StartTriPos() const { + return m_StartTriPos; +} + + +inline tri_stripper::triangle_strip::start_order tri_stripper::triangle_strip::StartOrder() const { + return m_StartOrder; +} + + +inline size_t tri_stripper::triangle_strip::Size() const { + return m_Size; +} + + +inline bool tri_stripper::_cmp_tri_interface_lt::operator() (const triangle_edge & a, const triangle_edge & b) const { + const tri_stripper::index A1 = a.A(); + const tri_stripper::index B1 = a.B(); + const tri_stripper::index A2 = b.A(); + const tri_stripper::index B2 = b.B(); + + if ((A1 < A2) || ((A1 == A2) && (B1 < B2))) + return true; + else + return false; +} + + +inline bool tri_stripper::_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 + +