Skip to content
Snippets Groups Projects
Commit 0d056fb1 authored by Gundalf's avatar Gundalf
Browse files

fixed collision generation

parent 7adbe608
No related branches found
No related tags found
No related merge requests found
#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
// 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
// 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
// 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
// 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
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment