Replaced the NVTriStrip code with tri_stripper written by Tanguy Fautré.
This commit is contained in:
3
AUTHORS
3
AUTHORS
@@ -158,3 +158,6 @@ Bryan Walsh
|
||||
|
||||
Terrex
|
||||
- the original base source for txp loader.
|
||||
|
||||
Tanguy Fautr<74> <softdev@pandora.be>
|
||||
- tri_stripper code utilized in the src/osgUtil/TriStipVisitor.cpp.
|
||||
|
||||
@@ -129,10 +129,6 @@ SOURCE=..\..\src\osgUtil\IntersectVisitor.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\osgUtil\NvTriStripObjects.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\osgUtil\Optimizer.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
@@ -181,6 +177,10 @@ SOURCE=..\..\src\osgUtil\TriStripVisitor.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\osgUtil\TriStrip_tri_stripper.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\osgUtil\Version.cpp
|
||||
# End Source File
|
||||
# End Group
|
||||
@@ -233,10 +233,6 @@ SOURCE=..\..\Include\osgUtil\IntersectVisitor
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\src\osgUtil\NvTriStripObjects.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\include\osgUtil\Optimizer
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
@@ -285,6 +281,18 @@ SOURCE=..\..\include\osgUtil\TriStripVisitor
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Src\osgUtil\TriStrip_graph_array.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Src\osgUtil\TriStrip_heap_array.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Src\osgUtil\TriStrip_tri_stripper.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\Include\osgUtil\Version
|
||||
# End Source File
|
||||
# End Group
|
||||
|
||||
@@ -9,7 +9,6 @@ CXXFILES = \
|
||||
DisplayRequirementsVisitor.cpp\
|
||||
InsertImpostorsVisitor.cpp\
|
||||
IntersectVisitor.cpp\
|
||||
NvTriStripObjects.cpp\
|
||||
Optimizer.cpp\
|
||||
RenderBin.cpp\
|
||||
RenderGraph.cpp\
|
||||
@@ -22,6 +21,7 @@ CXXFILES = \
|
||||
Tesselator.cpp\
|
||||
TransformCallback.cpp\
|
||||
TriStripVisitor.cpp\
|
||||
TriStrip_tri_stripper.cpp\
|
||||
CubeMapGenerator.cpp\
|
||||
HalfWayMapGenerator.cpp\
|
||||
HighlightMapGenerator.cpp\
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,296 +0,0 @@
|
||||
|
||||
#ifndef NV_TRISTRIP_OBJECTS_H
|
||||
#define NV_TRISTRIP_OBJECTS_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Types defined for stripification
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef int nvWORD;
|
||||
typedef unsigned int UINT;
|
||||
|
||||
struct MyVertex
|
||||
{
|
||||
float x, y, z;
|
||||
float nx, ny, nz;
|
||||
};
|
||||
|
||||
typedef MyVertex MyVector;
|
||||
|
||||
struct MyFace
|
||||
{
|
||||
int v1, v2, v3;
|
||||
float nx, ny, nz;
|
||||
};
|
||||
|
||||
class VertexCache
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
VertexCache(int size);
|
||||
VertexCache();
|
||||
~VertexCache();
|
||||
|
||||
bool InCache(int entry);
|
||||
int AddEntry(int entry);
|
||||
void Clear();
|
||||
|
||||
void Copy(VertexCache* inVcache);
|
||||
int At(int index);
|
||||
void Set(int index, int value);
|
||||
|
||||
private:
|
||||
|
||||
int *entries;
|
||||
int numEntries;
|
||||
|
||||
};
|
||||
|
||||
inline bool VertexCache::InCache(int entry)
|
||||
{
|
||||
bool returnVal = false;
|
||||
|
||||
for(int i = 0; i < numEntries; i++)
|
||||
{
|
||||
if(entries[i] == entry)
|
||||
{
|
||||
returnVal = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return returnVal;
|
||||
}
|
||||
|
||||
|
||||
inline int VertexCache::AddEntry(int entry)
|
||||
{
|
||||
int removed;
|
||||
|
||||
removed = entries[numEntries - 1];
|
||||
|
||||
//push everything right one
|
||||
for(int i = numEntries - 2; i >= 0; i--)
|
||||
{
|
||||
entries[i + 1] = entries[i];
|
||||
}
|
||||
|
||||
entries[0] = entry;
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
|
||||
class NvFaceInfo
|
||||
{
|
||||
public:
|
||||
|
||||
// vertex indices
|
||||
NvFaceInfo(int v0, int v1, int v2)
|
||||
{
|
||||
m_v0 = v0; m_v1 = v1; m_v2 = v2;
|
||||
m_stripId = -1;
|
||||
m_testStripId = -1;
|
||||
m_experimentId = -1;
|
||||
}
|
||||
|
||||
// data members are left public
|
||||
int m_v0, m_v1, m_v2;
|
||||
int m_stripId; // real strip Id
|
||||
int m_testStripId; // strip Id in an experiment
|
||||
int m_experimentId; // in what experiment was it given an experiment Id?
|
||||
};
|
||||
|
||||
// nice and dumb edge class that points knows its
|
||||
// indices, the two faces, and the next edge using
|
||||
// the lesser of the indices
|
||||
class NvEdgeInfo
|
||||
{
|
||||
public:
|
||||
|
||||
// constructor puts 1 ref on us
|
||||
NvEdgeInfo (int v0, int v1)
|
||||
{
|
||||
m_v0 = v0;
|
||||
m_v1 = v1;
|
||||
m_face0 = NULL;
|
||||
m_face1 = NULL;
|
||||
m_nextV0 = NULL;
|
||||
m_nextV1 = NULL;
|
||||
|
||||
// we will appear in 2 lists. this is a good
|
||||
// way to make sure we delete it the second time
|
||||
// we hit it in the edge infos
|
||||
m_refCount = 2;
|
||||
|
||||
}
|
||||
|
||||
// ref and unref
|
||||
void Unref () { if (--m_refCount == 0) delete this; }
|
||||
|
||||
// data members are left public
|
||||
UINT m_refCount;
|
||||
NvFaceInfo *m_face0, *m_face1;
|
||||
int m_v0, m_v1;
|
||||
NvEdgeInfo *m_nextV0, *m_nextV1;
|
||||
};
|
||||
|
||||
// This class is a quick summary of parameters used
|
||||
// to begin a triangle strip. Some operations may
|
||||
// want to create lists of such items, so they were
|
||||
// pulled out into a class
|
||||
class NvStripStartInfo
|
||||
{
|
||||
public:
|
||||
NvStripStartInfo(NvFaceInfo *startFace, NvEdgeInfo *startEdge, bool toV1)
|
||||
{
|
||||
m_startFace = startFace;
|
||||
m_startEdge = startEdge;
|
||||
m_toV1 = toV1;
|
||||
}
|
||||
NvFaceInfo *m_startFace;
|
||||
NvEdgeInfo *m_startEdge;
|
||||
bool m_toV1;
|
||||
};
|
||||
|
||||
typedef std::vector<NvFaceInfo*> NvFaceInfoVec;
|
||||
typedef std::list <NvFaceInfo*> NvFaceInfoList;
|
||||
typedef std::list <NvFaceInfoVec*> NvStripList;
|
||||
typedef std::vector<NvEdgeInfo*> NvEdgeInfoVec;
|
||||
|
||||
typedef std::vector<nvWORD> WordVec;
|
||||
typedef std::vector<MyVertex> MyVertexVec;
|
||||
typedef std::vector<MyFace> MyFaceVec;
|
||||
|
||||
// This is a summary of a strip that has been built
|
||||
class NvStripInfo
|
||||
{
|
||||
public:
|
||||
|
||||
// A little information about the creation of the triangle strips
|
||||
NvStripInfo(const NvStripStartInfo &startInfo, int stripId, int experimentId = -1) :
|
||||
m_startInfo(startInfo)
|
||||
{
|
||||
m_stripId = stripId;
|
||||
m_experimentId = experimentId;
|
||||
visited = false;
|
||||
}
|
||||
|
||||
// This is an experiment if the experiment id is >= 0
|
||||
inline bool IsExperiment () const { return m_experimentId >= 0; }
|
||||
|
||||
inline bool IsInStrip (const NvFaceInfo *faceInfo) const
|
||||
{
|
||||
if(faceInfo == NULL)
|
||||
return false;
|
||||
|
||||
return (m_experimentId >= 0 ? faceInfo->m_testStripId == m_stripId : faceInfo->m_stripId == m_stripId);
|
||||
}
|
||||
|
||||
bool SharesEdge(const NvFaceInfo* faceInfo, NvEdgeInfoVec &edgeInfos);
|
||||
|
||||
// take the given forward and backward strips and combine them together
|
||||
void Combine(const NvFaceInfoVec &forward, const NvFaceInfoVec &backward);
|
||||
|
||||
//returns true if the face is "unique", i.e. has a vertex which doesn't exist in the faceVec
|
||||
bool Unique(NvFaceInfoVec& faceVec, NvFaceInfo* face);
|
||||
|
||||
// mark the triangle as taken by this strip
|
||||
bool IsMarked (NvFaceInfo *faceInfo);
|
||||
void MarkTriangle(NvFaceInfo *faceInfo);
|
||||
|
||||
// build the strip
|
||||
void Build(NvEdgeInfoVec &edgeInfos, NvFaceInfoVec &faceInfos);
|
||||
|
||||
// public data members
|
||||
NvStripStartInfo m_startInfo;
|
||||
NvFaceInfoVec m_faces;
|
||||
int m_stripId;
|
||||
int m_experimentId;
|
||||
|
||||
bool visited;
|
||||
};
|
||||
|
||||
typedef std::vector<NvStripInfo*> NvStripInfoVec;
|
||||
|
||||
//The actual stripifier
|
||||
class NvStripifier
|
||||
{
|
||||
public:
|
||||
|
||||
// Constructor
|
||||
NvStripifier();
|
||||
~NvStripifier();
|
||||
|
||||
//the target vertex cache size, the structure to place the strips in, and the input indices
|
||||
void Stripify(const WordVec &in_indices, const int in_numVertices, const int in_cacheSize, const int in_minStripLength,
|
||||
NvStripInfoVec &allStrips, NvFaceInfoVec &allFaces);
|
||||
|
||||
static int GetUniqueVertexInB(NvFaceInfo *faceA, NvFaceInfo *faceB);
|
||||
static int GetSharedVertex(NvFaceInfo *faceA, NvFaceInfo *faceB);
|
||||
|
||||
static bool NextIsCW(const int numIndices);
|
||||
static bool IsCW(NvFaceInfo *faceInfo, int v0, int v1);
|
||||
|
||||
void CreateStrips(NvStripInfoVec& strips,
|
||||
NvFaceInfoVec& leftoverFaces,
|
||||
WordVec& stripIndices);
|
||||
|
||||
void OptimizeVertices(NvStripInfoVec& strips,
|
||||
NvFaceInfoVec& leftoverFaces,
|
||||
WordVec& stripIndices,
|
||||
MyVertexVec& vertices,
|
||||
MyVertexVec& optimizedVerts);
|
||||
|
||||
protected:
|
||||
|
||||
WordVec indices;
|
||||
int cacheSize;
|
||||
unsigned int minStripLength;
|
||||
float meshJump;
|
||||
bool bFirstTimeResetPoint;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Big mess of functions called during stripification
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int GetNextIndex(const WordVec &indices, NvFaceInfo *face);
|
||||
static NvEdgeInfo *FindEdgeInfo(NvEdgeInfoVec &edgeInfos, int v0, int v1);
|
||||
static NvFaceInfo *FindOtherFace(NvEdgeInfoVec &edgeInfos, int v0, int v1, NvFaceInfo *faceInfo);
|
||||
NvFaceInfo *FindGoodResetPoint(NvFaceInfoVec &faceInfos, NvEdgeInfoVec &edgeInfos);
|
||||
|
||||
void FindAllStrips(NvStripInfoVec &allStrips, NvFaceInfoVec &allFaceInfos, NvEdgeInfoVec &allEdgeInfos, int numSamples);
|
||||
void SplitUpStripsAndOptimize(NvStripInfoVec &allStrips, NvStripInfoVec &outStrips, NvEdgeInfoVec& edgeInfos, NvFaceInfoVec& outFaceList);
|
||||
void RemoveSmallStrips(NvStripInfoVec& allStrips, NvStripInfoVec& allBigStrips, NvFaceInfoVec& faceList);
|
||||
|
||||
bool FindTraversal(NvFaceInfoVec &faceInfos, NvEdgeInfoVec &edgeInfos, NvStripInfo *strip, NvStripStartInfo &startInfo);
|
||||
int CountRemainingTris(std::list<NvStripInfo*>::iterator iter, std::list<NvStripInfo*>::iterator end);
|
||||
|
||||
void CommitStrips(NvStripInfoVec &allStrips, const NvStripInfoVec &strips);
|
||||
|
||||
float AvgStripSize(const NvStripInfoVec &strips);
|
||||
int FindStartPoint(NvFaceInfoVec &faceInfos, NvEdgeInfoVec &edgeInfos);
|
||||
|
||||
void UpdateCacheStrip(VertexCache* vcache, NvStripInfo* strip);
|
||||
void UpdateCacheFace(VertexCache* vcache, NvFaceInfo* face);
|
||||
float CalcNumHitsStrip(VertexCache* vcache, NvStripInfo* strip);
|
||||
int CalcNumHitsFace(VertexCache* vcache, NvFaceInfo* face);
|
||||
int NumNeighbors(NvFaceInfo* face, NvEdgeInfoVec& edgeInfoVec);
|
||||
|
||||
void BuildStripifyInfo(NvFaceInfoVec &faceInfos, NvEdgeInfoVec &edgeInfos, const int numVertices);
|
||||
bool AlreadyExists(NvFaceInfo* faceInfo, NvFaceInfoVec& faceInfos);
|
||||
|
||||
// let our strip info classes and the other classes get
|
||||
// to these protected stripificaton methods if they want
|
||||
friend class NvStripInfo;
|
||||
};
|
||||
#endif
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "NvTriStripObjects.h"
|
||||
#include "TriStrip_tri_stripper.h"
|
||||
|
||||
using namespace osg;
|
||||
using namespace osgUtil;
|
||||
@@ -15,7 +15,7 @@ using namespace osgUtil;
|
||||
struct TriangleAcumulatorFunctor
|
||||
{
|
||||
|
||||
WordVec in_indices;
|
||||
triangle_stripper::tri_stripper::indices in_indices;
|
||||
const Vec3* _vbase;
|
||||
|
||||
TriangleAcumulatorFunctor() : _vbase(0) {}
|
||||
@@ -94,11 +94,11 @@ void TriStripVisitor::stripify(Geometry& geom)
|
||||
if (!taf.in_indices.empty())
|
||||
{
|
||||
int in_numVertices = -1;
|
||||
for(WordVec::iterator itr=taf.in_indices.begin();
|
||||
for(triangle_stripper::tri_stripper::indices::iterator itr=taf.in_indices.begin();
|
||||
itr!=taf.in_indices.end();
|
||||
++itr)
|
||||
{
|
||||
if (*itr>in_numVertices) in_numVertices=*itr;
|
||||
if ((int)*itr>in_numVertices) in_numVertices=*itr;
|
||||
}
|
||||
// the largest indice is in_numVertices, but indices start at 0
|
||||
// so increment to give to the corrent number of verticies.
|
||||
@@ -106,99 +106,22 @@ void TriStripVisitor::stripify(Geometry& geom)
|
||||
|
||||
int in_cacheSize = 16;
|
||||
int in_minStripLength = 2;
|
||||
NvStripInfoVec strips;
|
||||
NvFaceInfoVec leftoverFaces;
|
||||
|
||||
NvStripifier stripifier;
|
||||
stripifier.Stripify(taf.in_indices,
|
||||
in_numVertices,
|
||||
in_cacheSize,
|
||||
in_minStripLength,
|
||||
strips,
|
||||
leftoverFaces);
|
||||
triangle_stripper::tri_stripper stripifier(taf.in_indices);
|
||||
stripifier.SetCacheSize(in_cacheSize);
|
||||
stripifier.SetMinStripSize(in_minStripLength);
|
||||
|
||||
unsigned int i;
|
||||
for (i = 0; i < strips.size(); ++i)
|
||||
triangle_stripper::tri_stripper::primitives_vector outPrimitives;
|
||||
stripifier.Strip(&outPrimitives);
|
||||
|
||||
for(triangle_stripper::tri_stripper::primitives_vector::iterator itr=outPrimitives.begin();
|
||||
itr!=outPrimitives.end();
|
||||
++itr)
|
||||
{
|
||||
|
||||
NvStripInfo *strip = strips[i];
|
||||
int nStripFaceCount = strip->m_faces.size();
|
||||
|
||||
osg::DrawElementsUShort* elements = new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLE_STRIP);
|
||||
elements->reserve(nStripFaceCount+2);
|
||||
osg::DrawElementsUShort* elements = new osg::DrawElementsUShort(itr->m_Type,itr->m_Indices.begin(),itr->m_Indices.end());
|
||||
new_primitives.push_back(elements);
|
||||
|
||||
NvFaceInfo tLastFace(0, 0, 0);
|
||||
|
||||
// Handle the first face in the strip
|
||||
{
|
||||
NvFaceInfo tFirstFace(strip->m_faces[0]->m_v0, strip->m_faces[0]->m_v1, strip->m_faces[0]->m_v2);
|
||||
|
||||
// If there is a second face, reorder vertices such that the
|
||||
// unique vertex is first
|
||||
if (nStripFaceCount > 1)
|
||||
{
|
||||
int nUnique = NvStripifier::GetUniqueVertexInB(strip->m_faces[1], &tFirstFace);
|
||||
if (nUnique == tFirstFace.m_v1)
|
||||
{
|
||||
std::swap(tFirstFace.m_v0, tFirstFace.m_v1);
|
||||
}
|
||||
else if (nUnique == tFirstFace.m_v2)
|
||||
{
|
||||
std::swap(tFirstFace.m_v0, tFirstFace.m_v2);
|
||||
}
|
||||
|
||||
// If there is a third face, reorder vertices such that the
|
||||
// shared vertex is last
|
||||
if (nStripFaceCount > 2)
|
||||
{
|
||||
int nShared = NvStripifier::GetSharedVertex(strip->m_faces[2], &tFirstFace);
|
||||
if (nShared == tFirstFace.m_v1)
|
||||
{
|
||||
std::swap(tFirstFace.m_v1, tFirstFace.m_v2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
elements->push_back(tFirstFace.m_v0);
|
||||
elements->push_back(tFirstFace.m_v1);
|
||||
elements->push_back(tFirstFace.m_v2);
|
||||
|
||||
// Update last face info
|
||||
tLastFace = tFirstFace;
|
||||
}
|
||||
|
||||
for (int j = 1; j < nStripFaceCount; j++)
|
||||
{
|
||||
int nUnique = NvStripifier::GetUniqueVertexInB(&tLastFace, strip->m_faces[j]);
|
||||
if (nUnique != -1)
|
||||
{
|
||||
elements->push_back(nUnique);
|
||||
|
||||
// Update last face info
|
||||
tLastFace.m_v0 = tLastFace.m_v1;
|
||||
tLastFace.m_v1 = tLastFace.m_v2;
|
||||
tLastFace.m_v2 = nUnique;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (leftoverFaces.size())
|
||||
{
|
||||
|
||||
osg::DrawElementsUShort* triangles = new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES);
|
||||
triangles->reserve(leftoverFaces.size()*3);
|
||||
new_primitives.push_back(triangles);
|
||||
|
||||
for (i = 0; i < leftoverFaces.size(); ++i)
|
||||
{
|
||||
|
||||
triangles->push_back(leftoverFaces[i]->m_v0);
|
||||
triangles->push_back(leftoverFaces[i]->m_v1);
|
||||
triangles->push_back(leftoverFaces[i]->m_v2);
|
||||
}
|
||||
}
|
||||
geom.setPrimitiveSetList(new_primitives);
|
||||
}
|
||||
}
|
||||
|
||||
425
src/osgUtil/TriStrip_graph_array.h
Normal file
425
src/osgUtil/TriStrip_graph_array.h
Normal file
@@ -0,0 +1,425 @@
|
||||
// graph_array.h: interface for the graph_array class.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2002 Tanguy Fautr<74>.
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
// Tanguy Fautr<74>
|
||||
// softdev@pandora.be
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Semi-dynamic directed graph
|
||||
// ***************************
|
||||
//
|
||||
// Current version: 3.00 BETA 3 (04/12/2002)
|
||||
//
|
||||
// Comment: graph_array is equivalent to an array of nodes linked by
|
||||
// arcs.
|
||||
// This means you can't change the size (the number of nodes)
|
||||
// of the graph once you created it (setsize() will delete
|
||||
// any previous nodes and arcs).
|
||||
// But you can add or remove arcs.
|
||||
//
|
||||
// History: - 3.00 BETA 3 (04/12/2002) - Added empty()
|
||||
// - Changed some parameters from copy to reference
|
||||
// - Fixed a bug with erase_arc
|
||||
// - Un-inlined external functions
|
||||
// - Added "insert_arc" which is equivalent to "insert"
|
||||
// - 3.00 BETA 2 (16/11/2002) - Improved portability
|
||||
// - 3.00 BETA 1 (27/08/2002) - First public release
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef TRISTRIP_GRAPH_ARRAY_H
|
||||
#define TRISTRIP_GRAPH_ARRAY_H
|
||||
|
||||
// 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 std::vector<node>::iterator node_iterator;
|
||||
typedef std::vector<node>::const_iterator const_node_iterator;
|
||||
typedef std::vector<node>::reverse_iterator node_reverse_iterator;
|
||||
typedef 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 std::list<arc>::iterator out_arc_iterator;
|
||||
typedef 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);
|
||||
// removed since it was causing g++ 2.95.3 to produce many compile errors
|
||||
// presumably due to implicit import of the std::swap implementation.
|
||||
// Robert Osfield, Jan 2002.
|
||||
// friend void swap(_mytype & Left, _mytype & Right) { Left.swap(Right); }
|
||||
|
||||
protected:
|
||||
size_t m_NbArcs;
|
||||
std::vector<node> m_Nodes;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Additional "low level", graph related, functions
|
||||
template <class nodetype, class arctype>
|
||||
void unmark_nodes(graph_array<nodetype, arctype> & G);
|
||||
|
||||
template <class nodetype, class arctype>
|
||||
void unmark_arcs_from_node(graph_array<nodetype, arctype>::node & N);
|
||||
|
||||
template <class nodetype, class arctype>
|
||||
void unmark_arcs(graph_array<nodetype, arctype> & G);
|
||||
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// graph_array Inline functions
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <class nodetype, class arctype>
|
||||
inline graph_array<nodetype, arctype>::graph_array() : m_NbArcs(0) { }
|
||||
|
||||
|
||||
template <class nodetype, class arctype>
|
||||
inline graph_array<nodetype, arctype>::graph_array(const size_t NbNodes) : m_NbArcs(0), m_Nodes(NbNodes) { }
|
||||
|
||||
|
||||
template <class nodetype, class arctype>
|
||||
inline void graph_array<nodetype, arctype>::clear() {
|
||||
m_NbArcs = 0;
|
||||
m_Nodes.clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <class nodetype, class arctype>
|
||||
inline bool graph_array<nodetype, arctype>::empty() const {
|
||||
return m_Nodes.empty();
|
||||
}
|
||||
|
||||
|
||||
template <class nodetype, class arctype>
|
||||
inline size_t graph_array<nodetype, arctype>::size() const {
|
||||
return m_Nodes.size();
|
||||
}
|
||||
|
||||
|
||||
template <class nodetype, class arctype>
|
||||
inline void graph_array<nodetype, arctype>::setsize(const size_t NbNodes) {
|
||||
clear();
|
||||
m_Nodes.resize(NbNodes);
|
||||
}
|
||||
|
||||
|
||||
template <class nodetype, class arctype>
|
||||
inline 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 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 graph_array<nodetype, arctype>::node_iterator graph_array<nodetype, arctype>::begin() {
|
||||
return m_Nodes.begin();
|
||||
}
|
||||
|
||||
|
||||
template <class nodetype, class arctype>
|
||||
inline graph_array<nodetype, arctype>::node_iterator graph_array<nodetype, arctype>::end() {
|
||||
return m_Nodes.end();
|
||||
}
|
||||
|
||||
|
||||
template <class nodetype, class arctype>
|
||||
inline graph_array<nodetype, arctype>::const_node_iterator graph_array<nodetype, arctype>::begin() const {
|
||||
return m_Nodes.begin();
|
||||
}
|
||||
|
||||
|
||||
template <class nodetype, class arctype>
|
||||
inline graph_array<nodetype, arctype>::const_node_iterator graph_array<nodetype, arctype>::end() const {
|
||||
return m_Nodes.end();
|
||||
}
|
||||
|
||||
|
||||
template <class nodetype, class arctype>
|
||||
inline graph_array<nodetype, arctype>::node_reverse_iterator graph_array<nodetype, arctype>::rbegin() {
|
||||
return m_Nodes.rbegin();
|
||||
}
|
||||
|
||||
|
||||
template <class nodetype, class arctype>
|
||||
inline graph_array<nodetype, arctype>::node_reverse_iterator graph_array<nodetype, arctype>::rend() {
|
||||
return m_Nodes.rend();
|
||||
}
|
||||
|
||||
|
||||
template <class nodetype, class arctype>
|
||||
inline graph_array<nodetype, arctype>::const_node_reverse_iterator graph_array<nodetype, arctype>::rbegin() const {
|
||||
return m_Nodes.rbegin();
|
||||
}
|
||||
|
||||
|
||||
template <class nodetype, class arctype>
|
||||
inline 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 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 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 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 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 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 graph_array<nodetype, arctype>::node_iterator node_it;
|
||||
|
||||
for (node_it NodeIt = G.begin(); NodeIt != G.end(); ++NodeIt)
|
||||
NodeIt->unmark();
|
||||
}
|
||||
|
||||
|
||||
template <class nodetype, class arctype>
|
||||
void unmark_arcs_from_node(graph_array<nodetype, arctype>::node & N)
|
||||
{
|
||||
typedef graph_array<nodetype, arctype>::out_arc_iterator arc_it;
|
||||
|
||||
for (arc_it ArcIt = N.out_begin(); ArcIt != N.out_end(); ++ArcIt)
|
||||
ArcIt->unmark();
|
||||
}
|
||||
|
||||
|
||||
template <class nodetype, class arctype>
|
||||
void unmark_arcs(graph_array<nodetype, arctype> & G)
|
||||
{
|
||||
typedef graph_array<nodetype, arctype>::node_iterator node_it;
|
||||
|
||||
for (node_it NodeIt = G.begin(); NodeIt != G.end(); ++NodeIt)
|
||||
unmark_arcs_from_node(* NodeIt);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}; // namespace common_structures
|
||||
|
||||
#endif
|
||||
277
src/osgUtil/TriStrip_heap_array.h
Normal file
277
src/osgUtil/TriStrip_heap_array.h
Normal file
@@ -0,0 +1,277 @@
|
||||
// heap_array.h: interface for the heap_array class.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2002 Tanguy Fautr<74>.
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
// Tanguy Fautr<74>
|
||||
// softdev@pandora.be
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Semi-dynamic indexed heap
|
||||
// *************************
|
||||
//
|
||||
// Current version: 1.00 BETA 1 (24/10/2002)
|
||||
//
|
||||
// Comment: heap_array acts like a normal heap, you can push elements
|
||||
// and then get the greatest one.
|
||||
// However you cannot push any more element once an element
|
||||
// has been removed (pop, erase, etc...).
|
||||
// Elements can be modified after they've been pushed into
|
||||
// the heap via their indice.
|
||||
//
|
||||
// History: -
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef TRISTRIP_HEAP_ARRAY_H
|
||||
#define TRISTRIP_HEAP_ARRAY_H
|
||||
|
||||
|
||||
// namespace common_structures
|
||||
namespace common_structures {
|
||||
|
||||
|
||||
|
||||
|
||||
template <class T, class CmpT = std::less<T> >
|
||||
class heap_array
|
||||
{
|
||||
public:
|
||||
|
||||
struct heap_is_locked { };
|
||||
|
||||
|
||||
// heap_array main interface. Pre = PreCondition, Post = PostCondition
|
||||
|
||||
heap_array() : m_Locked(false) { } // Post: ((size() == 0) && ! locked())
|
||||
|
||||
void clear(); // Post: ((size() == 0) && ! locked())
|
||||
|
||||
void reserve(size_t Size);
|
||||
size_t size() const;
|
||||
|
||||
bool empty() const;
|
||||
bool locked() const;
|
||||
bool removed(size_t i) const; // Pre: (valid(i))
|
||||
bool valid(size_t i) const;
|
||||
|
||||
const T & top() const; // Pre: (! empty())
|
||||
const T & peek(size_t i) const; // Pre: (valid(i) && ! removed(i))
|
||||
const T & operator [] (size_t i) const; // Pre: (valid(i) && ! removed(i))
|
||||
|
||||
size_t push(const T & Elem); // Pre: (! locked()) else throw (heap_is_locked)
|
||||
|
||||
void pop(); // Pre: (! empty()) Post: (locked())
|
||||
void erase(size_t i); // Pre: (valid(i) && ! removed(i)) Post: (locked())
|
||||
void update(size_t i, const T & Elem); // Pre: (valid(i) && ! removed(i)) Post: (locked())
|
||||
|
||||
protected:
|
||||
|
||||
struct linker {
|
||||
linker(const T & Elem, size_t i) : m_Elem(Elem), m_Indice(i) { }
|
||||
|
||||
T m_Elem;
|
||||
size_t m_Indice;
|
||||
};
|
||||
|
||||
typedef std::vector<linker> linked_heap;
|
||||
typedef std::vector<size_t> finder;
|
||||
|
||||
void Adjust(size_t i);
|
||||
void Swap(size_t a, size_t b);
|
||||
bool Less(const linker & a, const linker & b) const;
|
||||
|
||||
linked_heap m_Heap;
|
||||
finder m_Finder;
|
||||
CmpT m_Compare;
|
||||
bool m_Locked;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// heap_indexed Inline functions
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <class T, class CmpT>
|
||||
inline void heap_array<T, CmpT>::clear() {
|
||||
m_Heap.clear();
|
||||
m_Finder.clear();
|
||||
m_Locked = false;
|
||||
}
|
||||
|
||||
|
||||
template <class T, class CmpT>
|
||||
inline bool heap_array<T, CmpT>::empty() const {
|
||||
return m_Heap.empty();
|
||||
}
|
||||
|
||||
|
||||
template <class T, class CmpT>
|
||||
inline bool heap_array<T, CmpT>::locked() const {
|
||||
return m_Locked;
|
||||
}
|
||||
|
||||
|
||||
template <class T, class CmpT>
|
||||
inline void heap_array<T, CmpT>::reserve(size_t Size) {
|
||||
m_Heap.reserve(Size);
|
||||
m_Finder.reserve(Size);
|
||||
}
|
||||
|
||||
|
||||
template <class T, class CmpT>
|
||||
inline size_t heap_array<T, CmpT>::size() const {
|
||||
return m_Heap.size();
|
||||
}
|
||||
|
||||
|
||||
template <class T, class CmpT>
|
||||
inline const T & heap_array<T, CmpT>::top() const {
|
||||
// Debug check to ensure heap is not empty
|
||||
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_Indice)]) = a;
|
||||
(size_t &) (m_Finder[(m_Heap[b].m_Indice)]) = b;
|
||||
}
|
||||
|
||||
|
||||
template <class T, class CmpT>
|
||||
inline bool heap_array<T, CmpT>::Less(const linker & a, const linker & b) const {
|
||||
return m_Compare(a.m_Elem, b.m_Elem);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}; // namespace common_structures
|
||||
|
||||
#endif
|
||||
575
src/osgUtil/TriStrip_tri_stripper.cpp
Normal file
575
src/osgUtil/TriStrip_tri_stripper.cpp
Normal file
@@ -0,0 +1,575 @@
|
||||
// tri_stripper.cpp: implementation of the Tri Stripper class.
|
||||
//
|
||||
// Copyright (C) 2002 Tanguy Fautr<74>.
|
||||
// For conditions of distribution and use,
|
||||
// see copyright notice in tri_stripper.h
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "TriStrip_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();
|
||||
|
||||
// Initialize 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));
|
||||
// m_PrimitivesVector.swap(* 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_IndicesCache.clear();
|
||||
|
||||
if (m_CacheSize > 0)
|
||||
m_IndicesCache.resize(m_CacheSize, static_cast<size_t>(-1));
|
||||
}
|
||||
|
||||
|
||||
|
||||
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
|
||||
indices_cache CacheBackup = m_IndicesCache;
|
||||
|
||||
while (! m_NextCandidates.empty()) {
|
||||
|
||||
// Discard useless triangles from the candidates list
|
||||
if ((m_Triangles[m_NextCandidates.back()].marked()) || (m_TriHeap[m_NextCandidates.back()].Degree() == 0)) {
|
||||
m_NextCandidates.pop_back();
|
||||
|
||||
// "continue" is evil! But it really makes things easier here.
|
||||
// The useless triangle is discarded, and the "while" just rebegins again
|
||||
continue;
|
||||
}
|
||||
|
||||
// Invariant: (CandidateTri's Degree() >= 1) && (CandidateTri is not marked).
|
||||
// So it can directly be used.
|
||||
const size_t CandidateTri = m_NextCandidates.back();
|
||||
m_NextCandidates.pop_back();
|
||||
|
||||
// Try to extend the triangle in the 3 possible directions
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
|
||||
// Reset the cache hit count
|
||||
m_CacheHits = 0;
|
||||
|
||||
// Try a new strip with that triangle in a particular direction
|
||||
const triangle_strip TempStrip = ExtendTriToStrip(CandidateTri, triangle_strip::start_order(i));
|
||||
|
||||
// Restore the cache (modified by ExtendTriToStrip)
|
||||
m_IndicesCache = CacheBackup;
|
||||
|
||||
// We want to keep the best strip
|
||||
// Discard strips that don't match the minimum required size
|
||||
if (TempStrip.Size() >= m_MinStripSize) {
|
||||
|
||||
// Cache simulator disabled?
|
||||
if (m_CacheSize == 0) {
|
||||
|
||||
// Cache is disabled, take the longest strip
|
||||
if (TempStrip.Size() > BestStrip.Size())
|
||||
BestStrip = TempStrip;
|
||||
|
||||
// Cache simulator enabled
|
||||
// Use other criteria to find the "best" strip
|
||||
} else {
|
||||
|
||||
// Priority 1: Keep the strip with the best cache hit count
|
||||
if (m_CacheHits > BestStripCacheHits) {
|
||||
BestStrip = TempStrip;
|
||||
BestStripDegree = m_TriHeap[TempStrip.StartTriPos()].Degree();
|
||||
BestStripCacheHits = m_CacheHits;
|
||||
|
||||
} else if (m_CacheHits == BestStripCacheHits) {
|
||||
|
||||
// Priority 2: Keep the strip with the loneliest start triangle
|
||||
if ((BestStrip.Size() != 0) && (m_TriHeap[TempStrip.StartTriPos()].Degree() < BestStripDegree)) {
|
||||
BestStrip = TempStrip;
|
||||
BestStripDegree = m_TriHeap[TempStrip.StartTriPos()].Degree();
|
||||
|
||||
// Priority 3: Keep the longest strip
|
||||
} else if (TempStrip.Size() > BestStrip.Size()) {
|
||||
BestStrip = TempStrip;
|
||||
BestStripDegree = m_TriHeap[TempStrip.StartTriPos()].Degree();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return BestStrip;
|
||||
}
|
||||
|
||||
|
||||
|
||||
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 indice cache
|
||||
AddTriToCache((* m_Triangles[StartTriPos]), Order);
|
||||
|
||||
|
||||
// Loop while we can further extend the strip
|
||||
for (tri_node_iter TriNodeIt = (m_Triangles.begin() + StartTriPos);
|
||||
(TriNodeIt != m_Triangles.end()) && ((m_CacheSize <= 0) || ((Size + 2) < m_CacheSize));
|
||||
++Size) {
|
||||
|
||||
// Get the triangle edge that would lead to the next triangle
|
||||
const triangle_edge Edge = GetLatestEdge(** TriNodeIt, Order);
|
||||
|
||||
// Link to a neighbour triangle
|
||||
const_tri_link_iter LinkIt;
|
||||
for (LinkIt = TriNodeIt->out_begin(); LinkIt != TriNodeIt->out_end(); ++LinkIt) {
|
||||
|
||||
// Get the reference to the possible next triangle
|
||||
const triangle & Tri = (** (LinkIt->terminal()));
|
||||
|
||||
// Check whether it's already been used
|
||||
if ((Tri.StripID() != m_StripID) && (! (LinkIt->terminal()->marked()))) {
|
||||
|
||||
// Does the current candidate triangle match the required for the strip?
|
||||
|
||||
if ((Edge.B() == Tri.A()) && (Edge.A() == Tri.B())) {
|
||||
Order = (ClockWise) ? triangle_strip::ABC : triangle_strip::BCA;
|
||||
AddIndiceToCache(Tri.C(), true);
|
||||
break;
|
||||
}
|
||||
|
||||
else if ((Edge.B() == Tri.B()) && (Edge.A() == Tri.C())) {
|
||||
Order = (ClockWise) ? triangle_strip::BCA : triangle_strip::CAB;
|
||||
AddIndiceToCache(Tri.A(), true);
|
||||
break;
|
||||
}
|
||||
|
||||
else if ((Edge.B() == Tri.C()) && (Edge.A() == Tri.A())) {
|
||||
Order = (ClockWise) ? triangle_strip::CAB : triangle_strip::ABC;
|
||||
AddIndiceToCache(Tri.B(), true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Is it the end of the strip?
|
||||
if (LinkIt == TriNodeIt->out_end()) {
|
||||
TriNodeIt = m_Triangles.end();
|
||||
--Size;
|
||||
} else {
|
||||
TriNodeIt = LinkIt->terminal();
|
||||
|
||||
// Setup for the next triangle
|
||||
(* TriNodeIt)->SetStripID(m_StripID);
|
||||
ClockWise = ! ClockWise;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return triangle_strip(StartTriPos, StartOrder, Size);
|
||||
}
|
||||
|
||||
|
||||
|
||||
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;
|
||||
AddIndice(Tri.C());
|
||||
break;
|
||||
}
|
||||
|
||||
else if ((Edge.B() == Tri.B()) && (Edge.A() == Tri.C())) {
|
||||
Order = (ClockWise) ? triangle_strip::BCA : triangle_strip::CAB;
|
||||
AddIndice(Tri.A());
|
||||
break;
|
||||
}
|
||||
|
||||
else if ((Edge.B() == Tri.C()) && (Edge.A() == Tri.A())) {
|
||||
Order = (ClockWise) ? triangle_strip::CAB : triangle_strip::ABC;
|
||||
AddIndice(Tri.B());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Debug check: we must have found the next triangle
|
||||
assert(LinkIt != TriNodeIt->out_end());
|
||||
|
||||
// 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_CacheSize > 0) && (NewDegree.Degree() > 0))
|
||||
m_NextCandidates.push_back(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline void tri_stripper::AddIndiceToCache(const indice i, bool CacheHitCount)
|
||||
{
|
||||
// Cache simulator enabled?
|
||||
if (m_CacheSize > 0) {
|
||||
|
||||
// Should we simulate the cache hits and count them?
|
||||
if (CacheHitCount) {
|
||||
if (std::find(m_IndicesCache.begin(), m_IndicesCache.end(), i) != m_IndicesCache.end())
|
||||
++m_CacheHits;
|
||||
}
|
||||
|
||||
// Manage the indices cache as a FIFO structure
|
||||
m_IndicesCache.pop_back();
|
||||
m_IndicesCache.push_front(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline void tri_stripper::AddIndice(const indice i)
|
||||
{
|
||||
// Add the indice to the current indices array
|
||||
m_PrimitivesVector.back().m_Indices.push_back(i);
|
||||
|
||||
// Run cache simulator
|
||||
AddIndiceToCache(i);
|
||||
}
|
||||
|
||||
|
||||
|
||||
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:
|
||||
AddIndiceToCache(Tri.A(), true);
|
||||
AddIndiceToCache(Tri.B(), true);
|
||||
AddIndiceToCache(Tri.C(), true);
|
||||
return;
|
||||
case triangle_strip::BCA:
|
||||
AddIndiceToCache(Tri.B(), true);
|
||||
AddIndiceToCache(Tri.C(), true);
|
||||
AddIndiceToCache(Tri.A(), true);
|
||||
return;
|
||||
case triangle_strip::CAB:
|
||||
AddIndiceToCache(Tri.C(), true);
|
||||
AddIndiceToCache(Tri.A(), true);
|
||||
AddIndiceToCache(Tri.B(), true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
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:
|
||||
AddIndice(Tri.A());
|
||||
AddIndice(Tri.B());
|
||||
AddIndice(Tri.C());
|
||||
return;
|
||||
case triangle_strip::BCA:
|
||||
AddIndice(Tri.B());
|
||||
AddIndice(Tri.C());
|
||||
AddIndice(Tri.A());
|
||||
return;
|
||||
case triangle_strip::CAB:
|
||||
AddIndice(Tri.C());
|
||||
AddIndice(Tri.A());
|
||||
AddIndice(Tri.B());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void tri_stripper::AddLeftTriangles()
|
||||
{
|
||||
// Create the latest indices array
|
||||
// and fill it with all the triangles that couldn't be stripped
|
||||
primitives Primitives;
|
||||
Primitives.m_Type = PT_Triangles;
|
||||
m_PrimitivesVector.push_back(Primitives);
|
||||
indices & Indices = m_PrimitivesVector.back().m_Indices;
|
||||
|
||||
for (size_t i = 0; i < m_Triangles.size(); ++i)
|
||||
if (! m_Triangles[i].marked()) {
|
||||
Indices.push_back(m_Triangles[i]->A());
|
||||
Indices.push_back(m_Triangles[i]->B());
|
||||
Indices.push_back(m_Triangles[i]->C());
|
||||
}
|
||||
|
||||
// Undo if useless
|
||||
if (Indices.size() == 0)
|
||||
m_PrimitivesVector.pop_back();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}; // namespace triangle_stripper
|
||||
380
src/osgUtil/TriStrip_tri_stripper.h
Normal file
380
src/osgUtil/TriStrip_tri_stripper.h
Normal file
@@ -0,0 +1,380 @@
|
||||
// tri_stripper.h: interface for the tri_stripper class.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2002 Tanguy Fautr<74>.
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.eap_array.h TriStrip_tri_stripper.cpp TriStrip_tri_stripper.h
|
||||
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
// Tanguy Fautr<74>
|
||||
// softdev@pandora.be
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Tri Stripper
|
||||
// ************
|
||||
//
|
||||
// Current version: 1.00 BETA 5 (10/12/2002)
|
||||
//
|
||||
// Comment: Triangle stripper in O(n.log(n)).
|
||||
//
|
||||
// Currently there are no protection against crazy values
|
||||
// given via SetMinStripSize() and SetCacheSize().
|
||||
// So be careful. (Min. strip size should be equal or greater
|
||||
// than 2, cache size should be about 10 for GeForce 256/2
|
||||
// and about 16-18 for GeForce 3/4.)
|
||||
//
|
||||
// History: - 1.00 BETA 5 (10/12/2002) - Fixed a bug in Stripify() that could sometimes
|
||||
// cause it to go into an infinite loop.
|
||||
// (thanks to Remy for the bug report)
|
||||
// - 1.00 BETA 4 (18/11/2002) - Removed the dependency on OpenGL:
|
||||
// modified gl_primitives to primitives,
|
||||
// and gl_primitives_vector to primitives_vector;
|
||||
// and added primitive_type.
|
||||
// (thanks to Patrik for noticing this useless dependency)
|
||||
// - 1.00 BETA 3 (18/11/2002) - Fixed a bug in LinkNeightboursTri() that could cause a crash
|
||||
// (thanks to Nicolas for finding it)
|
||||
// - 1.00 BETA 2 (16/11/2002) - Improved portability
|
||||
// - 1.00 BETA 1 (27/10/2002) - First public release
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef TRISTRIP_TRI_STRIPPER_H
|
||||
#define TRISTRIP_TRI_STRIPPER_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <deque>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <string>eap_array.h TriStrip_tri_stripper.cpp TriStrip_tri_stripper.h
|
||||
|
||||
#include <vector>
|
||||
|
||||
// namespace triangle_stripper
|
||||
namespace triangle_stripper {
|
||||
|
||||
|
||||
|
||||
#include "TriStrip_graph_array.h"
|
||||
#include "TriStrip_heap_array.h"
|
||||
|
||||
|
||||
|
||||
class tri_stripper
|
||||
{
|
||||
public:
|
||||
|
||||
// New Public types
|
||||
typedef unsigned int indice;
|
||||
typedef std::vector<indice> indices;
|
||||
|
||||
enum primitive_type {
|
||||
PT_Triangles = 0x0004, // = GL_TRIANGLES
|
||||
PT_Triangle_Strip = 0x0005 // = GL_TRIANGLE_STRIP
|
||||
};
|
||||
|
||||
struct primitives
|
||||
{
|
||||
indices m_Indices;
|
||||
primitive_type m_Type;
|
||||
};
|
||||
|
||||
typedef std::vector<primitives> primitives_vector;
|
||||
|
||||
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 indice A, const indice B, const indice C);
|
||||
|
||||
void SetStripID(const size_t StripID);
|
||||
|
||||
indice A() const;
|
||||
indice B() const;
|
||||
indice C() const;
|
||||
size_t StripID() const;
|
||||
|
||||
private:
|
||||
indice m_A;
|
||||
indice m_B;
|
||||
indice m_C;
|
||||
size_t m_StripID;
|
||||
};
|
||||
|
||||
|
||||
class triangle_edge
|
||||
{
|
||||
public:
|
||||
triangle_edge(const indice A, const indice B, const size_t TriPos);
|
||||
|
||||
indice A() const;
|
||||
indice B() const;
|
||||
size_t TriPos() const;
|
||||
|
||||
private:
|
||||
indice m_A;
|
||||
indice m_B;
|
||||
size_t m_TriPos;
|
||||
};
|
||||
|
||||
|
||||
class triangle_degree
|
||||
{
|
||||
public:
|
||||
triangle_degree();
|
||||
triangle_degree(const size_t TriPos, const size_t Degree);
|
||||
|
||||
size_t Degree() const;
|
||||
size_t TriPos() const;
|
||||
|
||||
void SetDegree(const size_t Degree);
|
||||
|
||||
private:
|
||||
size_t m_TriPos;
|
||||
size_t m_Degree;
|
||||
};
|
||||
|
||||
|
||||
class triangle_strip
|
||||
{
|
||||
public:
|
||||
enum start_order { ABC = 0, BCA = 1, CAB = 2 };
|
||||
|
||||
triangle_strip();
|
||||
triangle_strip(size_t StartTriPos, start_order StartOrder, size_t Size);
|
||||
|
||||
size_t StartTriPos() const;
|
||||
start_order StartOrder() const;
|
||||
size_t Size() const;
|
||||
|
||||
private:
|
||||
size_t m_StartTriPos;
|
||||
start_order m_StartOrder;
|
||||
size_t m_Size;
|
||||
};
|
||||
|
||||
|
||||
struct _cmp_tri_interface_lt
|
||||
{
|
||||
bool operator() (const triangle_edge & a, const triangle_edge & b) const;
|
||||
};
|
||||
|
||||
|
||||
struct _cmp_tri_degree_gt
|
||||
{
|
||||
bool operator () (const triangle_degree & a, const triangle_degree & b) const;
|
||||
};
|
||||
|
||||
|
||||
typedef common_structures::graph_array<triangle, char> triangles_graph;
|
||||
typedef common_structures::heap_array<triangle_degree, _cmp_tri_degree_gt> triangles_heap;
|
||||
typedef std::vector<triangle_edge> triangle_edges;
|
||||
typedef std::vector<size_t> triangle_indices;
|
||||
typedef std::deque<indice> indices_cache;
|
||||
|
||||
|
||||
void InitCache();
|
||||
void InitTriGraph();
|
||||
void InitTriHeap();
|
||||
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 AddIndice(const indice i);
|
||||
void AddIndiceToCache(const indice i, bool CacheHitCount = false);
|
||||
void AddTriToCache(const triangle & Tri, const triangle_strip::start_order Order);
|
||||
void AddTriToIndices(const triangle & Tri, const triangle_strip::start_order Order);
|
||||
|
||||
const indices & m_TriIndices;
|
||||
|
||||
size_t m_MinStripSize;
|
||||
size_t m_CacheSize;
|
||||
|
||||
primitives_vector m_PrimitivesVector;
|
||||
triangles_graph m_Triangles;
|
||||
triangles_heap m_TriHeap;
|
||||
triangle_indices m_NextCandidates;
|
||||
indices_cache m_IndicesCache;
|
||||
size_t m_StripID;
|
||||
size_t m_CacheHits;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// tri_stripper Inline functions
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline tri_stripper::tri_stripper(const indices & TriIndices) : m_TriIndices(TriIndices) {
|
||||
SetCacheSize();
|
||||
SetMinStripSize();
|
||||
}
|
||||
|
||||
|
||||
inline void tri_stripper::SetCacheSize(const size_t CacheSize) {
|
||||
m_CacheSize = CacheSize;
|
||||
}
|
||||
|
||||
|
||||
inline void tri_stripper::SetMinStripSize(const size_t MinStripSize) {
|
||||
m_MinStripSize = MinStripSize;
|
||||
}
|
||||
|
||||
|
||||
inline tri_stripper::triangle::triangle() { }
|
||||
|
||||
|
||||
inline tri_stripper::triangle::triangle(const indice A, const indice B, const indice C) : m_A(A), m_B(B), m_C(C), m_StripID(0) { }
|
||||
|
||||
|
||||
inline void tri_stripper::triangle::SetStripID(const size_t StripID) {
|
||||
m_StripID = StripID;
|
||||
}
|
||||
|
||||
|
||||
inline tri_stripper::indice tri_stripper::triangle::A() const {
|
||||
return m_A;
|
||||
}
|
||||
|
||||
|
||||
inline tri_stripper::indice tri_stripper::triangle::B() const {
|
||||
return m_B;
|
||||
}
|
||||
|
||||
|
||||
inline tri_stripper::indice 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 indice A, const indice B, const size_t TriPos) : m_A(A), m_B(B), m_TriPos(TriPos) { }
|
||||
|
||||
|
||||
inline tri_stripper::indice tri_stripper::triangle_edge::A() const {
|
||||
return m_A;
|
||||
}
|
||||
|
||||
|
||||
inline tri_stripper::indice 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::indice A1 = a.A();
|
||||
const tri_stripper::indice B1 = a.B();
|
||||
const tri_stripper::indice A2 = b.A();
|
||||
const tri_stripper::indice 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
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user