From 0d056fb1720f8b1bb6ea9e7d1669b44d9c3a1e66 Mon Sep 17 00:00:00 2001
From: Gundalf <gundalf01@users.sourceforge.net>
Date: Fri, 23 Jun 2006 20:43:58 +0000
Subject: [PATCH] fixed collision generation

---
 NifExport/TriStripper/cache_simulator.h |  92 ++++
 NifExport/TriStripper/graph_array.h     | 428 ++++++++++++++++++
 NifExport/TriStripper/heap_array.h      | 276 ++++++++++++
 NifExport/TriStripper/tri_stripper.cpp  | 568 ++++++++++++++++++++++++
 NifExport/TriStripper/tri_stripper.h    | 385 ++++++++++++++++
 5 files changed, 1749 insertions(+)
 create mode 100755 NifExport/TriStripper/cache_simulator.h
 create mode 100755 NifExport/TriStripper/graph_array.h
 create mode 100755 NifExport/TriStripper/heap_array.h
 create mode 100755 NifExport/TriStripper/tri_stripper.cpp
 create mode 100755 NifExport/TriStripper/tri_stripper.h

diff --git a/NifExport/TriStripper/cache_simulator.h b/NifExport/TriStripper/cache_simulator.h
new file mode 100755
index 0000000..edad27d
--- /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 0000000..0d85c68
--- /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 0000000..1cd0ad8
--- /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 0000000..3c1d44d
--- /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 0000000..45e0f7a
--- /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
+
+
-- 
GitLab