diff --git a/AUTHORS b/AUTHORS index 57a130d16..d8edb5ff5 100644 --- a/AUTHORS +++ b/AUTHORS @@ -158,3 +158,6 @@ Bryan Walsh Terrex - the original base source for txp loader. + +Tanguy Fautré + - tri_stripper code utilized in the src/osgUtil/TriStipVisitor.cpp. diff --git a/VisualStudio/osgUtil/osgUtil.dsp b/VisualStudio/osgUtil/osgUtil.dsp index 0865e4ed6..9a7c0171b 100755 --- a/VisualStudio/osgUtil/osgUtil.dsp +++ b/VisualStudio/osgUtil/osgUtil.dsp @@ -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 diff --git a/src/osgUtil/Makefile b/src/osgUtil/Makefile index 037a3585e..346c429fc 100644 --- a/src/osgUtil/Makefile +++ b/src/osgUtil/Makefile @@ -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\ diff --git a/src/osgUtil/NvTriStripObjects.cpp b/src/osgUtil/NvTriStripObjects.cpp deleted file mode 100644 index aba7e1a13..000000000 --- a/src/osgUtil/NvTriStripObjects.cpp +++ /dev/null @@ -1,1640 +0,0 @@ - -#if defined(_MSC_VER) - #pragma warning( disable : 4786 ) -#endif - -#include -#include -#include "NvTriStripObjects.h" - -#include - -#include - -VertexCache::VertexCache() -{ - VertexCache(16); -} - - -VertexCache::VertexCache(int size) -{ - numEntries = size; - - entries = new int[numEntries]; - - for(int i = 0; i < numEntries; i++) - entries[i] = -1; -} - - -VertexCache::~VertexCache() -{ - delete [] entries; -} - - -int VertexCache::At(int index) -{ - return entries[index]; -} - - -void VertexCache::Set(int index, int value) -{ - entries[index] = value; -} - - -void VertexCache::Clear() -{ - for(int i = 0; i < numEntries; i++) - entries[i] = -1; -} - - -void VertexCache::Copy(VertexCache* inVcache) -{ - for(int i = 0; i < numEntries; i++) - { - inVcache->Set(i, entries[i]); - } -} - - -NvStripifier::NvStripifier() -{ - -} - - -NvStripifier::~NvStripifier() -{ - -} - - -/////////////////////////////////////////////////////////////////////////////////////////// -// FindEdgeInfo() -// -// find the edge info for these two indices -// -NvEdgeInfo * NvStripifier::FindEdgeInfo(NvEdgeInfoVec &edgeInfos, int v0, int v1) -{ - - // we can get to it through either array - // because the edge infos have a v0 and v1 - // and there is no order except how it was - // first created. - NvEdgeInfo *infoIter = edgeInfos[v0]; - while (infoIter != NULL) - { - if (infoIter->m_v0 == v0) - { - if (infoIter->m_v1 == v1) - return infoIter; - else - infoIter = infoIter->m_nextV0; - } - else - { - assert(infoIter->m_v1 == v0); - if (infoIter->m_v0 == v1) - return infoIter; - else - infoIter = infoIter->m_nextV1; - } - } - return NULL; -} - - -/////////////////////////////////////////////////////////////////////////////////////////// -// FindOtherFace -// -// find the other face sharing these vertices -// exactly like the edge info above -// -NvFaceInfo * NvStripifier::FindOtherFace(NvEdgeInfoVec &edgeInfos, int v0, int v1, NvFaceInfo *faceInfo) -{ - NvEdgeInfo *edgeInfo = FindEdgeInfo(edgeInfos, v0, v1); - assert(edgeInfo != NULL); - return (edgeInfo->m_face0 == faceInfo ? edgeInfo->m_face1 : edgeInfo->m_face0); -} - - -bool NvStripifier::AlreadyExists(NvFaceInfo* faceInfo, NvFaceInfoVec& faceInfos) -{ - for(unsigned int i = 0; i < faceInfos.size(); i++) - { - if( (faceInfos[i]->m_v0 == faceInfo->m_v0) && - (faceInfos[i]->m_v1 == faceInfo->m_v1) && - (faceInfos[i]->m_v2 == faceInfo->m_v2) ) - return true; - } - - return false; -} - - -/////////////////////////////////////////////////////////////////////////////////////////// -// BuildStripifyInfo() -// -// Builds the list of all face and edge infos -// -void NvStripifier::BuildStripifyInfo(NvFaceInfoVec &faceInfos, NvEdgeInfoVec &edgeInfos, const int numVertices) -{ - - // reserve space for the face infos, but do not resize them. - int numIndices = indices.size(); - int numTriangles = numIndices / 3; - - faceInfos.reserve(numTriangles); - - // we actually resize the edge infos, so we must initialize to NULL - edgeInfos.resize (numVertices); - int i; - for (i = 0; i < numVertices; i++) - edgeInfos[i] = NULL; - - - // iterate through the triangles of the triangle list - int index = 0; - for (i = 0; i < numTriangles; i++) - { - // grab the indices - int v0 = indices[index++]; - int v1 = indices[index++]; - int v2 = indices[index++]; - - // create the face info and add it to the list of faces, but only if this exact face doesn't already - // exist in the list - NvFaceInfo *faceInfo = new NvFaceInfo(v0, v1, v2); - if(!AlreadyExists(faceInfo, faceInfos)) - { - faceInfos.push_back(faceInfo); - - // grab the edge infos, creating them if they do not already exist - NvEdgeInfo *edgeInfo01 = FindEdgeInfo(edgeInfos, v0, v1); - if (edgeInfo01 == NULL) - { - - // create the info - edgeInfo01 = new NvEdgeInfo(v0, v1); - - // update the linked list on both - edgeInfo01->m_nextV0 = edgeInfos[v0]; - edgeInfo01->m_nextV1 = edgeInfos[v1]; - edgeInfos[v0] = edgeInfo01; - edgeInfos[v1] = edgeInfo01; - - // set face 0 - edgeInfo01->m_face0 = faceInfo; - } - else - { - if (edgeInfo01->m_face1 != NULL) - osg::notify(osg::WARN)<<"BuildStripifyInfo: > 2 triangles on an edge... uncertain consequences\n"<< std::endl; - else - edgeInfo01->m_face1 = faceInfo; - } - - // grab the edge infos, creating them if they do not already exist - NvEdgeInfo *edgeInfo12 = FindEdgeInfo(edgeInfos, v1, v2); - if (edgeInfo12 == NULL) - { - - // create the info - edgeInfo12 = new NvEdgeInfo(v1, v2); - - // update the linked list on both - edgeInfo12->m_nextV0 = edgeInfos[v1]; - edgeInfo12->m_nextV1 = edgeInfos[v2]; - edgeInfos[v1] = edgeInfo12; - edgeInfos[v2] = edgeInfo12; - - // set face 0 - edgeInfo12->m_face0 = faceInfo; - } - else - { - if (edgeInfo12->m_face1 != NULL) - osg::notify(osg::WARN)<<"BuildStripifyInfo: > 2 triangles on an edge... uncertain consequences\n"<< std::endl; - else - edgeInfo12->m_face1 = faceInfo; - } - - // grab the edge infos, creating them if they do not already exist - NvEdgeInfo *edgeInfo20 = FindEdgeInfo(edgeInfos, v2, v0); - if (edgeInfo20 == NULL) - { - - // create the info - edgeInfo20 = new NvEdgeInfo(v2, v0); - - // update the linked list on both - edgeInfo20->m_nextV0 = edgeInfos[v2]; - edgeInfo20->m_nextV1 = edgeInfos[v0]; - edgeInfos[v2] = edgeInfo20; - edgeInfos[v0] = edgeInfo20; - - // set face 0 - edgeInfo20->m_face0 = faceInfo; - } - else - { - if (edgeInfo20->m_face1 != NULL) - osg::notify(osg::WARN)<<"BuildStripifyInfo: > 2 triangles on an edge... uncertain consequences\n"<< std::endl; - else - edgeInfo20->m_face1 = faceInfo; - } - - } - } -} - - -/////////////////////////////////////////////////////////////////////////////////////////// -// FindStartPoint() -// -// Finds a good starting point, namely one which has only one neighbor -// -int NvStripifier::FindStartPoint(NvFaceInfoVec &faceInfos, NvEdgeInfoVec &edgeInfos) -{ - for(unsigned int i = 0; i < faceInfos.size(); i++) - { - int ctr = 0; - - if(FindOtherFace(edgeInfos, faceInfos[i]->m_v0, faceInfos[i]->m_v1, faceInfos[i]) == NULL) - ctr++; - if(FindOtherFace(edgeInfos, faceInfos[i]->m_v1, faceInfos[i]->m_v2, faceInfos[i]) == NULL) - ctr++; - if(FindOtherFace(edgeInfos, faceInfos[i]->m_v2, faceInfos[i]->m_v0, faceInfos[i]) == NULL) - ctr++; - if(ctr > 1) - return i; - } - return -1; -} - - -/////////////////////////////////////////////////////////////////////////////////////////// -// FindGoodResetPoint() -// -// A good reset point is one near other commited areas so that -// we know that when we've made the longest strips its because -// we're stripifying in the same general orientation. -// -NvFaceInfo* NvStripifier::FindGoodResetPoint(NvFaceInfoVec &faceInfos, NvEdgeInfoVec &edgeInfos) -{ - // we hop into different areas of the mesh to try to get - // other large open spans done. Areas of small strips can - // just be left to triangle lists added at the end. - NvFaceInfo *result = NULL; - - if(result == NULL) - { - int numFaces = faceInfos.size(); - int startPoint; - if(bFirstTimeResetPoint) - { - //first time, find a face with few neighbors (look for an edge of the mesh) - startPoint = FindStartPoint(faceInfos, edgeInfos); - bFirstTimeResetPoint = false; - } - else - startPoint = (int)(((float) numFaces - 1) * meshJump); - - if(startPoint == -1) - startPoint = (int)(((float) numFaces - 1) * meshJump); - - int i = startPoint; - do - { - - // if this guy isn't visited, try him - if (faceInfos[i]->m_stripId < 0) - { - result = faceInfos[i]; - break; - } - - // update the index and clamp to 0-(numFaces-1) - if (++i >= numFaces) - i = 0; - - } while (i != startPoint); - - // update the meshJump - meshJump += 0.1f; - if (meshJump > 1.0f) - meshJump = .05f; - } - - // return the best face we found - return result; -} - - -/////////////////////////////////////////////////////////////////////////////////////////// -// GetUniqueVertexInB() -// -// Returns the vertex unique to faceB -// -int NvStripifier::GetUniqueVertexInB(NvFaceInfo *faceA, NvFaceInfo *faceB) -{ - - int facev0 = faceB->m_v0; - if (facev0 != faceA->m_v0 && - facev0 != faceA->m_v1 && - facev0 != faceA->m_v2) - return facev0; - - int facev1 = faceB->m_v1; - if (facev1 != faceA->m_v0 && - facev1 != faceA->m_v1 && - facev1 != faceA->m_v2) - return facev1; - - int facev2 = faceB->m_v2; - if (facev2 != faceA->m_v0 && - facev2 != faceA->m_v1 && - facev2 != faceA->m_v2) - return facev2; - - // nothing is different - return -1; -} - - -/////////////////////////////////////////////////////////////////////////////////////////// -// GetSharedVertex() -// -// Returns the vertex shared between the two input faces -// -int NvStripifier::GetSharedVertex(NvFaceInfo *faceA, NvFaceInfo *faceB) -{ - - int facev0 = faceB->m_v0; - if (facev0 == faceA->m_v0 || - facev0 == faceA->m_v1 || - facev0 == faceA->m_v2) - return facev0; - - int facev1 = faceB->m_v1; - if (facev1 == faceA->m_v0 || - facev1 == faceA->m_v1 || - facev1 == faceA->m_v2) - return facev1; - - int facev2 = faceB->m_v2; - if (facev2 == faceA->m_v0 || - facev2 == faceA->m_v1 || - facev2 == faceA->m_v2) - return facev2; - - // nothing is shared - return -1; -} - - -/////////////////////////////////////////////////////////////////////////////////////////// -// GetNextIndex() -// -// Returns vertex of the input face which is "next" in the input index list -// -inline int NvStripifier::GetNextIndex(const WordVec &indices, NvFaceInfo *face) -{ - - int numIndices = indices.size(); - assert(numIndices >= 2); - - int v0 = indices[numIndices-2]; - int v1 = indices[numIndices-1]; - - int fv0 = face->m_v0; - int fv1 = face->m_v1; - int fv2 = face->m_v2; - - if (fv0 != v0 && fv0 != v1) - { - if ((fv1 != v0 && fv1 != v1) || (fv2 != v0 && fv2 != v1)) - { - osg::notify(osg::WARN)<<"GetNextIndex: Triangle doesn't have all of its vertices\n"<< std::endl; - osg::notify(osg::WARN)<<"GetNextIndex: Duplicate triangle probably got us derailed\n"<< std::endl; - } - return fv0; - } - if (fv1 != v0 && fv1 != v1) - { - if ((fv0 != v0 && fv0 != v1) || (fv2 != v0 && fv2 != v1)) - { - osg::notify(osg::WARN)<<"GetNextIndex: Triangle doesn't have all of its vertices\n"<< std::endl; - osg::notify(osg::WARN)<<"GetNextIndex: Duplicate triangle probably got us derailed\n"<< std::endl; - } - return fv1; - } - if (fv2 != v0 && fv2 != v1) - { - if ((fv0 != v0 && fv0 != v1) || (fv1 != v0 && fv1 != v1)) - { - osg::notify(osg::WARN)<<"GetNextIndex: Triangle doesn't have all of its vertices\n"<< std::endl; - osg::notify(osg::WARN)<<"GetNextIndex: Duplicate triangle probably got us derailed\n"<< std::endl; - } - return fv2; - } - - // shouldn't get here - osg::notify(osg::WARN)<<"GetNextIndex: Duplicate triangle sent\n"<< std::endl; - return -1; -} - - -/////////////////////////////////////////////////////////////////////////////////////////// -// IsMarked() -// -// If either the faceInfo has a real strip index because it is -// already assign to a committed strip OR it is assigned in an -// experiment and the experiment index is the one we are building -// for, then it is marked and unavailable -inline bool NvStripInfo::IsMarked(NvFaceInfo *faceInfo) -{ - return (faceInfo->m_stripId >= 0) || (IsExperiment() && faceInfo->m_experimentId == m_experimentId); -} - - -/////////////////////////////////////////////////////////////////////////////////////////// -// MarkTriangle() -// -// Marks the face with the current strip ID -// -inline void NvStripInfo::MarkTriangle(NvFaceInfo *faceInfo) -{ - assert(!IsMarked(faceInfo)); - if (IsExperiment()) - { - faceInfo->m_experimentId = m_experimentId; - faceInfo->m_testStripId = m_stripId; - } - else - { - assert(faceInfo->m_stripId == -1); - faceInfo->m_experimentId = -1; - faceInfo->m_stripId = m_stripId; - } -} - - -bool NvStripInfo::Unique(NvFaceInfoVec& faceVec, NvFaceInfo* face) -{ - bool bv0, bv1, bv2; //bools to indicate whether a vertex is in the faceVec or not - bv0 = bv1 = bv2 = false; - - for(unsigned int i = 0; i < faceVec.size(); i++) - { - if(!bv0) - { - if( (faceVec[i]->m_v0 == face->m_v0) || - (faceVec[i]->m_v1 == face->m_v0) || - (faceVec[i]->m_v2 == face->m_v0) ) - bv0 = true; - } - - if(!bv1) - { - if( (faceVec[i]->m_v0 == face->m_v1) || - (faceVec[i]->m_v1 == face->m_v1) || - (faceVec[i]->m_v2 == face->m_v1) ) - bv1 = true; - } - - if(!bv2) - { - if( (faceVec[i]->m_v0 == face->m_v2) || - (faceVec[i]->m_v1 == face->m_v2) || - (faceVec[i]->m_v2 == face->m_v2) ) - bv2 = true; - } - - //the face is not unique, all it's vertices exist in the face vector - if(bv0 && bv1 && bv2) - return false; - } - - //if we get out here, it's unique - return true; -} - - -/////////////////////////////////////////////////////////////////////////////////////////// -// Build() -// -// Builds a strip forward as far as we can go, then builds backwards, and joins the two lists -// -void NvStripInfo::Build(NvEdgeInfoVec &edgeInfos, NvFaceInfoVec &) -{ - // parameters : void NvStripInfo::Build(NvEdgeInfoVec &edgeInfos, NvFaceInfoVec &faceInfos) - - // used in building the strips forward and backward - static WordVec scratchIndices; - scratchIndices.resize(0); - - // build forward... start with the initial face - NvFaceInfoVec forwardFaces, backwardFaces; - forwardFaces.push_back(m_startInfo.m_startFace); - - MarkTriangle(m_startInfo.m_startFace); - - int v0 = (m_startInfo.m_toV1 ? m_startInfo.m_startEdge->m_v0 : m_startInfo.m_startEdge->m_v1); - int v1 = (m_startInfo.m_toV1 ? m_startInfo.m_startEdge->m_v1 : m_startInfo.m_startEdge->m_v0); - - // easiest way to get v2 is to use this function which requires the - // other indices to already be in the list. - scratchIndices.push_back(v0); - scratchIndices.push_back(v1); - int v2 = NvStripifier::GetNextIndex(scratchIndices, m_startInfo.m_startFace); - scratchIndices.push_back(v2); - - // - // build the forward list - // - int nv0 = v1; - int nv1 = v2; - - NvFaceInfo *nextFace = NvStripifier::FindOtherFace(edgeInfos, nv0, nv1, m_startInfo.m_startFace); - while (nextFace != NULL && !IsMarked(nextFace)) - { - //this tests to see if a face is "unique", meaning that its vertices aren't already in the list - // so, strips which "wrap-around" are not allowed - if(!Unique(forwardFaces, nextFace)) - break; - - // add this to the strip - forwardFaces.push_back(nextFace); - - MarkTriangle(nextFace); - - // add the index - nv0 = nv1; - nv1 = NvStripifier::GetNextIndex(scratchIndices, nextFace); - scratchIndices.push_back(nv1); - - // and get the next face - nextFace = NvStripifier::FindOtherFace(edgeInfos, nv0, nv1, nextFace); - - } - - // tempAllFaces is going to be forwardFaces + backwardFaces - // it's used for Unique() - NvFaceInfoVec tempAllFaces; - for(unsigned int i = 0; i < forwardFaces.size(); i++) - tempAllFaces.push_back(forwardFaces[i]); - - // - // reset the indices for building the strip backwards and do so - // - scratchIndices.resize(0); - scratchIndices.push_back(v2); - scratchIndices.push_back(v1); - scratchIndices.push_back(v0); - nv0 = v1; - nv1 = v0; - nextFace = NvStripifier::FindOtherFace(edgeInfos, nv0, nv1, m_startInfo.m_startFace); - while (nextFace != NULL && !IsMarked(nextFace)) - { - //this tests to see if a face is "unique", meaning that its vertices aren't already in the list - // so, strips which "wrap-around" are not allowed - if(!Unique(tempAllFaces, nextFace)) - break; - - // add this to the strip - backwardFaces.push_back(nextFace); - - //this is just so Unique() will work - tempAllFaces.push_back(nextFace); - - MarkTriangle(nextFace); - - // add the index - nv0 = nv1; - nv1 = NvStripifier::GetNextIndex(scratchIndices, nextFace); - scratchIndices.push_back(nv1); - - // and get the next face - nextFace = NvStripifier::FindOtherFace(edgeInfos, nv0, nv1, nextFace); - } - - // Combine the forward and backwards stripification lists and put into our own face vector - Combine(forwardFaces, backwardFaces); -} - - -/////////////////////////////////////////////////////////////////////////////////////////// -// Combine() -// -// Combines the two input face vectors and puts the result into m_faces -// -void NvStripInfo::Combine(const NvFaceInfoVec &forward, const NvFaceInfoVec &backward) -{ - - // add backward faces - int numFaces = backward.size(); - int i; - for (i = numFaces - 1; i >= 0; i--) - m_faces.push_back(backward[i]); - - // add forward faces - numFaces = forward.size(); - for (i = 0; i < numFaces; i++) - m_faces.push_back(forward[i]); -} - - -/////////////////////////////////////////////////////////////////////////////////////////// -// SharesEdge() -// -// Returns true if the input face and the current strip share an edge -// -bool NvStripInfo::SharesEdge(const NvFaceInfo* faceInfo, NvEdgeInfoVec &edgeInfos) -{ - //check v0->v1 edge - NvEdgeInfo* currEdge = NvStripifier::FindEdgeInfo(edgeInfos, faceInfo->m_v0, faceInfo->m_v1); - - if(IsInStrip(currEdge->m_face0) || IsInStrip(currEdge->m_face1)) - return true; - - //check v1->v2 edge - currEdge = NvStripifier::FindEdgeInfo(edgeInfos, faceInfo->m_v1, faceInfo->m_v2); - - if(IsInStrip(currEdge->m_face0) || IsInStrip(currEdge->m_face1)) - return true; - - //check v2->v0 edge - currEdge = NvStripifier::FindEdgeInfo(edgeInfos, faceInfo->m_v2, faceInfo->m_v0); - - if(IsInStrip(currEdge->m_face0) || IsInStrip(currEdge->m_face1)) - return true; - - return false; - -} - - -/////////////////////////////////////////////////////////////////////////////////////////// -// CommitStrips() -// -// "Commits" the input strips by setting their m_experimentId to -1 and adding to the allStrips -// vector -// -void NvStripifier::CommitStrips(NvStripInfoVec &allStrips, const NvStripInfoVec &strips) -{ - // Iterate through strips - int numStrips = strips.size(); - for (int i = 0; i < numStrips; i++) - { - - // Tell the strip that it is now real - NvStripInfo *strip = strips[i]; - strip->m_experimentId = -1; - - // add to the list of real strips - allStrips.push_back(strip); - - // Iterate through the faces of the strip - // Tell the faces of the strip that they belong to a real strip now - const NvFaceInfoVec &faces = strips[i]->m_faces; - int numFaces = faces.size(); - - if( (faces[0]->m_v0 == 2302) && - (faces[0]->m_v1 == 3215) && - (faces[0]->m_v2 == 2603) ) - osg::notify(osg::WARN)<<"BLEH"<< std::endl; - - for (int j = 0; j < numFaces; j++) - { - strip->MarkTriangle(faces[j]); - } - } -} - - -/////////////////////////////////////////////////////////////////////////////////////////// -// FindTraversal() -// -// Finds the next face to start the next strip on. -// -bool NvStripifier::FindTraversal(NvFaceInfoVec &, -NvEdgeInfoVec &edgeInfos, -NvStripInfo *strip, -NvStripStartInfo &startInfo) -{ - - // if the strip was v0->v1 on the edge, then v1 will be a vertex in the next edge. - int v = (strip->m_startInfo.m_toV1 ? strip->m_startInfo.m_startEdge->m_v1 : strip->m_startInfo.m_startEdge->m_v0); - - NvFaceInfo *untouchedFace = NULL; - NvEdgeInfo *edgeIter = edgeInfos[v]; - while (edgeIter != NULL) - { - NvFaceInfo *face0 = edgeIter->m_face0; - NvFaceInfo *face1 = edgeIter->m_face1; - if ((face0 != NULL && !strip->IsInStrip(face0)) && face1 != NULL && !strip->IsMarked(face1)) - { - untouchedFace = face1; - break; - } - if ((face1 != NULL && !strip->IsInStrip(face1)) && face0 != NULL && !strip->IsMarked(face0)) - { - untouchedFace = face0; - break; - } - - // find the next edgeIter - edgeIter = (edgeIter->m_v0 == v ? edgeIter->m_nextV0 : edgeIter->m_nextV1); - } - - startInfo.m_startFace = untouchedFace; - startInfo.m_startEdge = edgeIter; - if (edgeIter != NULL) - { - if(strip->SharesEdge(startInfo.m_startFace, edgeInfos)) - //note! used to be m_v1 - startInfo.m_toV1 = (edgeIter->m_v0 == v); - else - startInfo.m_toV1 = (edgeIter->m_v1 == v); - } - return (startInfo.m_startFace != NULL); -} - - -//////////////////////////////////////////////////////////////////////////////////////// -// RemoveSmallStrips() -// -// allStrips is the whole strip vector...all small strips will be deleted from this list, to avoid leaking mem -// allBigStrips is an out parameter which will contain all strips above minStripLength -// faceList is an out parameter which will contain all faces which were removed from the striplist -// -void NvStripifier::RemoveSmallStrips(NvStripInfoVec& allStrips, NvStripInfoVec& allBigStrips, NvFaceInfoVec& faceList) -{ - faceList.clear(); - allBigStrips.clear(); //make sure these are empty - NvFaceInfoVec tempFaceList; - - for(unsigned int i = 0; i < allStrips.size(); i++) - { - if(allStrips[i]->m_faces.size() < minStripLength) - { - //strip is too small, add faces to faceList - for(unsigned int j = 0; j < allStrips[i]->m_faces.size(); j++) - tempFaceList.push_back(allStrips[i]->m_faces[j]); - - //and free memory - delete allStrips[i]; - } - else - { - allBigStrips.push_back(allStrips[i]); - } - } - - bool *bVisitedList = new bool[tempFaceList.size()]; - memset(bVisitedList, 0, tempFaceList.size()*sizeof(bool)); - - VertexCache* vcache = new VertexCache(cacheSize); - - int bestNumHits = -1; - int numHits; - int bestIndex = 0; - - while(1) - { - bestNumHits = -1; - - //find best face to add next, given the current cache - for(unsigned int i = 0; i < tempFaceList.size(); i++) - { - if(bVisitedList[i]) - continue; - - numHits = CalcNumHitsFace(vcache, tempFaceList[i]); - if(numHits > bestNumHits) - { - bestNumHits = numHits; - bestIndex = i; - } - } - - if(bestNumHits == -1.0) - break; - bVisitedList[bestIndex] = true; - UpdateCacheFace(vcache, tempFaceList[bestIndex]); - faceList.push_back(tempFaceList[bestIndex]); - } - - delete vcache; - delete [] bVisitedList; -} - - -/////////////////////////////////////////////////////////////////////////////////////////// -// Stripify() -// -// -// in_indices are the input indices of the mesh to stripify -// in_cacheSize is the target cache size -// -void NvStripifier::Stripify(const WordVec &in_indices, const int in_numVertices, const int in_cacheSize, - const int in_minStripLength, NvStripInfoVec &outStrips, NvFaceInfoVec& outFaceList) -{ - meshJump = 0.0f; - bFirstTimeResetPoint = true; //used in FindGoodResetPoint() - - //the number of times to run the experiments - int numSamples = 10; - cacheSize = in_cacheSize; - //this is the strip size threshold below which we dump the strip into a list - minStripLength = in_minStripLength; - - indices = in_indices; - - // build the stripification info - NvFaceInfoVec allFaceInfos; - NvEdgeInfoVec allEdgeInfos; - - BuildStripifyInfo(allFaceInfos, allEdgeInfos, in_numVertices); - - NvStripInfoVec allStrips; - - // stripify - FindAllStrips(allStrips, allFaceInfos, allEdgeInfos, numSamples); - - //split up the strips into cache friendly pieces, optimize them, then dump these into outStrips - SplitUpStripsAndOptimize(allStrips, outStrips, allEdgeInfos, outFaceList); - - //clean up - int i; - for(i = 0; i < (int)allStrips.size(); i++) - { - delete allStrips[i]; - } - - for (i = 0; i < (int)allEdgeInfos.size(); i++) - { - NvEdgeInfo *info = allEdgeInfos[i]; - while (info != NULL) - { - NvEdgeInfo *next = (info->m_v0 == i ? info->m_nextV0 : info->m_nextV1); - info->Unref(); - info = next; - } - } - -} - - -/////////////////////////////////////////////////////////////////////////////////////////// -// SplitUpStripsAndOptimize() -// -// Splits the input vector of strips (allBigStrips) into smaller, cache friendly pieces, then -// reorders these pieces to maximize cache hits -// The final strips are output through outStrips -// -void NvStripifier::SplitUpStripsAndOptimize(NvStripInfoVec &allStrips, NvStripInfoVec &outStrips, -NvEdgeInfoVec& edgeInfos, NvFaceInfoVec& outFaceList) -{ - int threshold = cacheSize - 4; - NvStripInfoVec tempStrips; - - //split up strips into threshold-sized pieces - unsigned int i; - for(i = 0; i < allStrips.size(); i++) - { - NvStripInfo* currentStrip; - NvStripStartInfo startInfo(NULL, NULL, false); - - if((int)(allStrips[i]->m_faces.size()) > threshold) - { - - int numTimes = allStrips[i]->m_faces.size() / threshold; - int numLeftover = allStrips[i]->m_faces.size() % threshold; - - int j; - for(j = 0; j < numTimes; j++) - { - currentStrip = new NvStripInfo(startInfo, 0, -1); - - for(int faceCtr = j*threshold; faceCtr < threshold+(j*threshold); faceCtr++) - { - currentStrip->m_faces.push_back(allStrips[i]->m_faces[faceCtr]); - } - - tempStrips.push_back(currentStrip); - } - - int leftOff = j * threshold; - - if(numLeftover != 0) - { - currentStrip = new NvStripInfo(startInfo, 0, -1); - - for(int k = 0; k < numLeftover; k++) - { - currentStrip->m_faces.push_back(allStrips[i]->m_faces[leftOff++]); - } - - tempStrips.push_back(currentStrip); - } - } - else - { - //we're not just doing a tempStrips.push_back(allBigStrips[i]) because - // this way we can delete allBigStrips later to free the memory - currentStrip = new NvStripInfo(startInfo, 0, -1); - - for(unsigned int j = 0; j < allStrips[i]->m_faces.size(); j++) - currentStrip->m_faces.push_back(allStrips[i]->m_faces[j]); - - tempStrips.push_back(currentStrip); - } - } - - //add small strips to face list - NvStripInfoVec tempStrips2; - RemoveSmallStrips(tempStrips, tempStrips2, outFaceList); - - outStrips.clear(); - if(tempStrips2.size() != 0) - { - //Optimize for the vertex cache - VertexCache* vcache = new VertexCache(cacheSize); - - float bestNumHits = -1.0f; - float numHits; - int bestIndex=0; - - int firstIndex = 0; - float minCost = 10000.0f; - - for(i = 0; i < tempStrips2.size(); i++) - { - int numNeighbors = 0; - - //find strip with least number of neighbors per face - for(unsigned int j = 0; j < tempStrips2[i]->m_faces.size(); j++) - { - numNeighbors += NumNeighbors(tempStrips2[i]->m_faces[j], edgeInfos); - } - - float currCost = (float)numNeighbors / (float)tempStrips2[i]->m_faces.size(); - if(currCost < minCost) - { - minCost = currCost; - firstIndex = i; - } - } - - UpdateCacheStrip(vcache, tempStrips2[firstIndex]); - outStrips.push_back(tempStrips2[firstIndex]); - - tempStrips2[firstIndex]->visited = true; - - //this n^2 algo is what slows down stripification so much.... - // needs to be improved - while(1) - { - bestNumHits = -1.0f; - - //find best strip to add next, given the current cache - for(unsigned int i = 0; i < tempStrips2.size(); i++) - { - if(tempStrips2[i]->visited) - continue; - - numHits = CalcNumHitsStrip(vcache, tempStrips2[i]); - if(numHits > bestNumHits) - { - bestNumHits = numHits; - bestIndex = i; - } - } - - if(bestNumHits == -1.0f) - break; - tempStrips2[bestIndex]->visited = true; - UpdateCacheStrip(vcache, tempStrips2[bestIndex]); - outStrips.push_back(tempStrips2[bestIndex]); - } - - delete vcache; - } -} - - -/////////////////////////////////////////////////////////////////////////////////////////// -// UpdateCacheStrip() -// -// Updates the input vertex cache with this strip's vertices -// -void NvStripifier::UpdateCacheStrip(VertexCache* vcache, NvStripInfo* strip) -{ - for(unsigned int i = 0; i < strip->m_faces.size(); i++) - { - if(!vcache->InCache(strip->m_faces[i]->m_v0)) - vcache->AddEntry(strip->m_faces[i]->m_v0); - - if(!vcache->InCache(strip->m_faces[i]->m_v1)) - vcache->AddEntry(strip->m_faces[i]->m_v1); - - if(!vcache->InCache(strip->m_faces[i]->m_v2)) - vcache->AddEntry(strip->m_faces[i]->m_v2); - } -} - - -/////////////////////////////////////////////////////////////////////////////////////////// -// UpdateCacheFace() -// -// Updates the input vertex cache with this face's vertices -// -void NvStripifier::UpdateCacheFace(VertexCache* vcache, NvFaceInfo* face) -{ - if(!vcache->InCache(face->m_v0)) - vcache->AddEntry(face->m_v0); - - if(!vcache->InCache(face->m_v1)) - vcache->AddEntry(face->m_v1); - - if(!vcache->InCache(face->m_v2)) - vcache->AddEntry(face->m_v2); -} - - -/////////////////////////////////////////////////////////////////////////////////////////// -// CalcNumHitsStrip() -// -// returns the number of cache hits per face in the strip -// -float NvStripifier::CalcNumHitsStrip(VertexCache* vcache, NvStripInfo* strip) -{ - int numHits = 0; - int numFaces = 0; - - for(unsigned int i = 0; i < strip->m_faces.size(); i++) - { - if(vcache->InCache(strip->m_faces[i]->m_v0)) - numHits++; - - if(vcache->InCache(strip->m_faces[i]->m_v1)) - numHits++; - - if(vcache->InCache(strip->m_faces[i]->m_v2)) - numHits++; - - numFaces++; - - } - - return ((float)numHits / (float)numFaces); -} - - -/////////////////////////////////////////////////////////////////////////////////////////// -// CalcNumHitsFace() -// -// returns the number of cache hits in the face -// -int NvStripifier::CalcNumHitsFace(VertexCache* vcache, NvFaceInfo* face) -{ - int numHits = 0; - - if(vcache->InCache(face->m_v0)) - numHits++; - - if(vcache->InCache(face->m_v1)) - numHits++; - - if(vcache->InCache(face->m_v2)) - numHits++; - - return numHits; -} - - -/////////////////////////////////////////////////////////////////////////////////////////// -// NumNeighbors() -// -// Returns the number of neighbors that this face has -// -int NvStripifier::NumNeighbors(NvFaceInfo* face, NvEdgeInfoVec& edgeInfoVec) -{ - int numNeighbors = 0; - - if(FindOtherFace(edgeInfoVec, face->m_v0, face->m_v1, face) != NULL) - { - numNeighbors++; - } - - if(FindOtherFace(edgeInfoVec, face->m_v1, face->m_v2, face) != NULL) - { - numNeighbors++; - } - - if(FindOtherFace(edgeInfoVec, face->m_v2, face->m_v0, face) != NULL) - { - numNeighbors++; - } - - return numNeighbors; -} - - -/////////////////////////////////////////////////////////////////////////////////////////// -// AvgStripSize() -// -// Finds the average strip size of the input vector of strips -// -float NvStripifier::AvgStripSize(const NvStripInfoVec &strips) -{ - int sizeAccum = 0; - int numStrips = strips.size(); - for (int i = 0; i < numStrips; i++) - { - NvStripInfo *strip = strips[i]; - sizeAccum += strip->m_faces.size(); - } - return ((float)sizeAccum) / ((float)numStrips); -} - - -/////////////////////////////////////////////////////////////////////////////////////////// -// FindAllStrips() -// -// Does the stripification, puts output strips into vector allStrips -// -// Works by setting runnning a number of experiments in different areas of the mesh, and -// accepting the one which results in the longest strips. It then accepts this, and moves -// on to a different area of the mesh. We try to jump around the mesh some, to ensure that -// large open spans of strips get generated. -// -void NvStripifier::FindAllStrips(NvStripInfoVec &allStrips, -NvFaceInfoVec &allFaceInfos, -NvEdgeInfoVec &allEdgeInfos, -int numSamples) -{ - // the experiments - int experimentId = 0; - int stripId = 0; - bool done = false; - - int loopCtr = 0; - - while (!done) - { - loopCtr++; - - // - // PHASE 1: Set up numSamples * numEdges experiments - // - NvStripInfoVec *experiments = new NvStripInfoVec [numSamples * 6]; - int experimentIndex = 0; - std::set resetPoints; - int i; - for (i = 0; i < numSamples; i++) - { - - // Try to find another good reset point. - // If there are none to be found, we are done - NvFaceInfo *nextFace = FindGoodResetPoint(allFaceInfos, allEdgeInfos); - if (nextFace == NULL) - { - done = true; - break; - } - - // If we have already evaluated starting at this face in this slew - // of experiments, then skip going any further - else if (resetPoints.find(nextFace) != resetPoints.end()) - { - continue; - } - - // trying it now... - resetPoints.insert(nextFace); - - // otherwise, we shall now try experiments for starting on the 01,12, and 20 edges - assert(nextFace->m_stripId < 0); - - // build the strip off of this face's 0-1 edge - NvEdgeInfo *edge01 = FindEdgeInfo(allEdgeInfos, nextFace->m_v0, nextFace->m_v1); - NvStripInfo *strip01 = new NvStripInfo(NvStripStartInfo(nextFace, edge01, true), stripId++, experimentId++); - experiments[experimentIndex++].push_back(strip01); - - // build the strip off of this face's 1-0 edge - NvEdgeInfo *edge10 = FindEdgeInfo(allEdgeInfos, nextFace->m_v0, nextFace->m_v1); - NvStripInfo *strip10 = new NvStripInfo(NvStripStartInfo(nextFace, edge10, false), stripId++, experimentId++); - experiments[experimentIndex++].push_back(strip10); - - // build the strip off of this face's 1-2 edge - NvEdgeInfo *edge12 = FindEdgeInfo(allEdgeInfos, nextFace->m_v1, nextFace->m_v2); - NvStripInfo *strip12 = new NvStripInfo(NvStripStartInfo(nextFace, edge12, true), stripId++, experimentId++); - experiments[experimentIndex++].push_back(strip12); - - // build the strip off of this face's 2-1 edge - NvEdgeInfo *edge21 = FindEdgeInfo(allEdgeInfos, nextFace->m_v1, nextFace->m_v2); - NvStripInfo *strip21 = new NvStripInfo(NvStripStartInfo(nextFace, edge21, false), stripId++, experimentId++); - experiments[experimentIndex++].push_back(strip21); - - // build the strip off of this face's 2-0 edge - NvEdgeInfo *edge20 = FindEdgeInfo(allEdgeInfos, nextFace->m_v2, nextFace->m_v0); - NvStripInfo *strip20 = new NvStripInfo(NvStripStartInfo(nextFace, edge20, true), stripId++, experimentId++); - experiments[experimentIndex++].push_back(strip20); - - // build the strip off of this face's 0-2 edge - NvEdgeInfo *edge02 = FindEdgeInfo(allEdgeInfos, nextFace->m_v2, nextFace->m_v0); - NvStripInfo *strip02 = new NvStripInfo(NvStripStartInfo(nextFace, edge02, false), stripId++, experimentId++); - experiments[experimentIndex++].push_back(strip02); - } - - // - // PHASE 2: Iterate through that we setup in the last phase - // and really build each of the strips and strips that follow to see how - // far we get - // - int numExperiments = experimentIndex; - for (i = 0; i < numExperiments; i++) - { - - // get the strip set - - // build the first strip of the list - experiments[i][0]->Build(allEdgeInfos, allFaceInfos); - int experimentId = experiments[i][0]->m_experimentId; - - NvStripInfo *stripIter = experiments[i][0]; - NvStripStartInfo startInfo(NULL, NULL, false); - while (FindTraversal(allFaceInfos, allEdgeInfos, stripIter, startInfo)) - { - - // create the new strip info - stripIter = new NvStripInfo(startInfo, stripId++, experimentId); - - // build the next strip - stripIter->Build(allEdgeInfos, allFaceInfos); - - // add it to the list - experiments[i].push_back(stripIter); - } - } - - // - // Phase 3: Find the experiment that has the most promise - // - int bestIndex = 0; - double bestValue = 0; - for (i = 0; i < numExperiments; i++) - { - const float avgStripSizeWeight = 1.0f; - const float numTrisWeight = 1.0f; - float avgStripSize = AvgStripSize(experiments[i]); - float numStrips = (float) experiments[i].size(); - float value = avgStripSize * avgStripSizeWeight + (avgStripSize * numStrips * numTrisWeight); - - if (value > bestValue) - { - bestValue = value; - bestIndex = i; - } - } - - // - // Phase 4: commit the best experiment of the bunch - // - CommitStrips(allStrips, experiments[bestIndex]); - - // and destroy all of the others - for (i = 0; i < numExperiments; i++) - { - if (i != bestIndex) - { - int numStrips = experiments[i].size(); - for (int j = 0; j < numStrips; j++) - { - delete experiments[i][j]; - } - } - } - - // delete the array that we used for all experiments - delete [] experiments; - } -} - - -/////////////////////////////////////////////////////////////////////////////////////////// -// CountRemainingTris() -// -// This will count the number of triangles left in the -// strip list starting at iter and finishing up at end -// -int NvStripifier::CountRemainingTris(std::list::iterator iter, -std::list::iterator end) -{ - int count = 0; - while (iter != end) - { - count += (*iter)->m_faces.size(); - iter++; - } - return count; -} - - -/////////////////////////////////////////////////////////////////////////////////////////// -// NextIsCW() -// -// Returns true if the next face should be ordered in CW fashion -// -bool NvStripifier::NextIsCW(const int numIndices) -{ - return ((numIndices % 2) == 0); -} - - -/////////////////////////////////////////////////////////////////////////////////////////// -// IsCW() -// -// Returns true if the face is ordered in CW fashion -// -bool NvStripifier::IsCW(NvFaceInfo *faceInfo, int v0, int v1) -{ - if (faceInfo->m_v0 == v0) - return (faceInfo->m_v1 == v1); - - else if (faceInfo->m_v1 == v0) - return (faceInfo->m_v2 == v1); - - else - return (faceInfo->m_v0 == v1); - - // shouldn't get here - assert(0); - return false; -} - - -//used in CreateStrips -template -inline void SWAP(T& first, T& second) -{ - T temp = first; - first = second; - second = temp; -} - - -/////////////////////////////////////////////////////////////////////////////////////////// -// CreateStrips() -// -// Up until now, the strips had been strips at heart, but tri lists in reality. -// Now, remove redundant indices, and stitch together strips to form one, huge uber-strip -// using degenerate tris. -// -void NvStripifier::CreateStrips( -NvStripInfoVec& strips, -NvFaceInfoVec&, -WordVec& stripIndices) -{ - // parameters: - // void NvStripifier::CreateStrips( - // NvStripInfoVec& strips, - // NvFaceInfoVec& leftoverFaces, - // WordVec& stripIndices) - // { - - NvFaceInfo tLastFace(0, 0, 0); - int nStripCount = strips.size(); - assert(nStripCount > 0); - - for (int i = 0; i < nStripCount; i++) - { - NvStripInfo *strip = strips[i]; - unsigned int nStripFaceCount = strip->m_faces.size(); - // unsigned int stripIndicesSize = stripIndices.size(); - assert(nStripFaceCount > 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) - { - SWAP(tFirstFace.m_v0, tFirstFace.m_v1); - } - else if (nUnique == tFirstFace.m_v2) - { - 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) - { - SWAP(tFirstFace.m_v1, tFirstFace.m_v2); - } - } - } - - if (i != 0) - { - // Double tap the first in the new strip - stripIndices.push_back(tFirstFace.m_v0); - - // Check CW/CCW ordering - if (NextIsCW(stripIndices.size()) != IsCW(strip->m_faces[0], tFirstFace.m_v0, tFirstFace.m_v1)) - { - stripIndices.push_back(tFirstFace.m_v0); - } - } - else - { - if(!IsCW(strip->m_faces[0], tFirstFace.m_v0, tFirstFace.m_v1)) - stripIndices.push_back(tFirstFace.m_v0); - } - - stripIndices.push_back(tFirstFace.m_v0); - stripIndices.push_back(tFirstFace.m_v1); - stripIndices.push_back(tFirstFace.m_v2); - - // Update last face info - tLastFace = tFirstFace; - } - - for (unsigned int j = 1; j < nStripFaceCount; j++) - { - int nUnique = NvStripifier::GetUniqueVertexInB(&tLastFace, strip->m_faces[j]); - if (nUnique != -1) - { - stripIndices.push_back(nUnique); - - // Update last face info - tLastFace.m_v0 = tLastFace.m_v1; - tLastFace.m_v1 = tLastFace.m_v2; - tLastFace.m_v2 = nUnique; - } - } - - // Double tap between strips. - stripIndices.push_back(tLastFace.m_v2); - - // Update last face info - tLastFace.m_v0 = tLastFace.m_v1; - tLastFace.m_v1 = tLastFace.m_v2; - tLastFace.m_v2 = tLastFace.m_v2; - } -} - - -/////////////////////////////////////////////////////////////////////////////////////////// -// OptimizeVertices() -// -// Function which optimizes the vertices in the mesh to minimize page misses -// -// Puts output verts into optimizedVerts vector -// -// -void NvStripifier::OptimizeVertices(NvStripInfoVec& strips, -NvFaceInfoVec& leftoverFaces, -WordVec& , -MyVertexVec& vertices, -MyVertexVec& optimizedVerts) -{ - // parameters. - // void NvStripifier::OptimizeVertices(NvStripInfoVec& strips, - // NvFaceInfoVec& leftoverFaces, - // WordVec& stripIndices, - // MyVertexVec& vertices, - // MyVertexVec& optimizedVerts) - - //caches oldIndex --> newIndex conversion - int *indexCache; - indexCache = new int[vertices.size()]; - - memset(indexCache, -1, sizeof(int)*vertices.size()); - - //first do the strips - unsigned int i; - for(i = 0; i < strips.size(); i++) - { - for(unsigned int j = 0; j < strips[i]->m_faces.size(); j++) - { - int v0 = strips[i]->m_faces[j]->m_v0; - int v1 = strips[i]->m_faces[j]->m_v1; - int v2 = strips[i]->m_faces[j]->m_v2; - - //v0 - int index = indexCache[v0]; - if(index == -1) - { - optimizedVerts.push_back(vertices[v0]); - strips[i]->m_faces[j]->m_v0 = optimizedVerts.size() - 1; - - indexCache[v0] = strips[i]->m_faces[j]->m_v0; - } - else - { - strips[i]->m_faces[j]->m_v0 = index; - } - - //v1 - index = indexCache[v1]; - if(index == -1) - { - optimizedVerts.push_back(vertices[v1]); - strips[i]->m_faces[j]->m_v1 = optimizedVerts.size() - 1; - - indexCache[v1] = strips[i]->m_faces[j]->m_v1; - } - else - { - strips[i]->m_faces[j]->m_v1 = index; - } - - //v2 - index = indexCache[v2]; - if(index == -1) - { - optimizedVerts.push_back(vertices[v2]); - strips[i]->m_faces[j]->m_v2 = optimizedVerts.size() - 1; - - indexCache[v2] = strips[i]->m_faces[j]->m_v2; - } - else - { - strips[i]->m_faces[j]->m_v2 = index; - } - - } - } - - //now do the leftover list - for(i = 0; i < leftoverFaces.size(); i++) - { - int v0 = leftoverFaces[i]->m_v0; - int v1 = leftoverFaces[i]->m_v1; - int v2 = leftoverFaces[i]->m_v2; - - //v0 - int index = indexCache[v0]; - if(index == -1) - { - optimizedVerts.push_back(vertices[v0]); - leftoverFaces[i]->m_v0 = optimizedVerts.size() - 1; - - indexCache[v0] = leftoverFaces[i]->m_v0; - } - else - { - leftoverFaces[i]->m_v0 = index; - } - - //v1 - index = indexCache[v1]; - if(index == -1) - { - optimizedVerts.push_back(vertices[v1]); - leftoverFaces[i]->m_v1 = optimizedVerts.size() - 1; - - indexCache[v1] = leftoverFaces[i]->m_v1; - } - else - { - leftoverFaces[i]->m_v1 = index; - } - - //v2 - index = indexCache[v2]; - if(index == -1) - { - optimizedVerts.push_back(vertices[v2]); - leftoverFaces[i]->m_v2 = optimizedVerts.size() - 1; - - indexCache[v2] = leftoverFaces[i]->m_v2; - } - else - { - leftoverFaces[i]->m_v2 = index; - } - } - - delete [] indexCache; - - assert(optimizedVerts.size() == vertices.size()); -} diff --git a/src/osgUtil/NvTriStripObjects.h b/src/osgUtil/NvTriStripObjects.h deleted file mode 100644 index 7931654dc..000000000 --- a/src/osgUtil/NvTriStripObjects.h +++ /dev/null @@ -1,296 +0,0 @@ - -#ifndef NV_TRISTRIP_OBJECTS_H -#define NV_TRISTRIP_OBJECTS_H - -#include -#include -#include - -///////////////////////////////////////////////////////////////////////////////// -// -// 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 NvFaceInfoVec; -typedef std::list NvFaceInfoList; -typedef std::list NvStripList; -typedef std::vector NvEdgeInfoVec; - -typedef std::vector WordVec; -typedef std::vector MyVertexVec; -typedef std::vector 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 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::iterator iter, std::list::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 diff --git a/src/osgUtil/TriStripVisitor.cpp b/src/osgUtil/TriStripVisitor.cpp index 898ee2e3e..038ec4806 100644 --- a/src/osgUtil/TriStripVisitor.cpp +++ b/src/osgUtil/TriStripVisitor.cpp @@ -6,7 +6,7 @@ #include -#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); } } diff --git a/src/osgUtil/TriStrip_graph_array.h b/src/osgUtil/TriStrip_graph_array.h new file mode 100644 index 000000000..452339b38 --- /dev/null +++ b/src/osgUtil/TriStrip_graph_array.h @@ -0,0 +1,425 @@ +// graph_array.h: interface for the graph_array class. +// +////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2002 Tanguy Fautré. +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. +// +// Tanguy Fautré +// softdev@pandora.be +// +////////////////////////////////////////////////////////////////////// +// +// Semi-dynamic directed graph +// *************************** +// +// Current version: 3.00 BETA 3 (04/12/2002) +// +// Comment: graph_array is equivalent to an array of nodes linked by +// arcs. +// This means you can't change the size (the number of nodes) +// of the graph once you created it (setsize() will delete +// any previous nodes and arcs). +// But you can add or remove arcs. +// +// History: - 3.00 BETA 3 (04/12/2002) - Added empty() +// - Changed some parameters from copy to reference +// - Fixed a bug with erase_arc +// - Un-inlined external functions +// - Added "insert_arc" which is equivalent to "insert" +// - 3.00 BETA 2 (16/11/2002) - Improved portability +// - 3.00 BETA 1 (27/08/2002) - First public release +// +////////////////////////////////////////////////////////////////////// + +#ifndef TRISTRIP_GRAPH_ARRAY_H +#define TRISTRIP_GRAPH_ARRAY_H + +// namespace common_structures +namespace common_structures { + + + + +// graph_array main class +template +class graph_array +{ +public: + + class arc; + class node; + + // New types + typedef size_t nodeid; + typedef std::vector::iterator node_iterator; + typedef std::vector::const_iterator const_node_iterator; + typedef std::vector::reverse_iterator node_reverse_iterator; + typedef std::vector::const_reverse_iterator const_node_reverse_iterator; + + typedef graph_array _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; + + 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::iterator out_arc_iterator; + typedef std::list::const_iterator const_out_arc_iterator; + + + // graph_array::node class + class node + { + public: + node & mark() { m_Marker = true; return (* this); } + node & unmark() { m_Marker = false; return (* this); } + bool marked() const { return m_Marker; } + + bool out_empty() const { return m_OutArcs.empty(); } + size_t number_of_out_arcs() const { return m_OutArcs.size(); } + + out_arc_iterator out_begin() { return m_OutArcs.begin(); } + out_arc_iterator out_end() { return m_OutArcs.end(); } + const_out_arc_iterator out_begin() const { return m_OutArcs.begin(); } + const_out_arc_iterator out_end() const { return m_OutArcs.end(); } + + nodetype & operator * () { return m_Elem; } + nodetype * operator -> () { return &m_Elem; } + const nodetype & operator * () const { return m_Elem; } + const nodetype * operator -> () const { return &m_Elem; } + + nodetype & operator = (const nodetype & Elem) { return (m_Elem = Elem); } + + protected: + friend class graph_array; + friend class std::vector; + + node() : m_Marker(false) { } + + std::list m_OutArcs; + nodetype m_Elem; + bool m_Marker; + }; + + + // Construction/Destruction + graph_array(); + explicit graph_array(const size_t NbNodes); + + // Node related member functions + void clear(); + bool empty() const; + void setsize(const size_t NbNodes); + size_t size() const; + + node & operator [] (const nodeid & i); + const node & operator [] (const nodeid & i) const; + + node_iterator begin(); + node_iterator end(); + const_node_iterator begin() const; + const_node_iterator end() const; + + node_reverse_iterator rbegin(); + node_reverse_iterator rend(); + const_node_reverse_iterator rbegin() const; + const_node_reverse_iterator rend() const; + + // Arc related member functions + size_t number_of_arcs() const; + + void erase_arcs(); + void erase_arcs(const node_iterator & Initial); + out_arc_iterator erase_arc(const out_arc_iterator & Pos); + + out_arc_iterator insert_arc(const nodeid & Initial, const nodeid & Terminal); + out_arc_iterator insert_arc(const nodeid & Initial, const nodeid & Terminal, const arctype & Elem); + out_arc_iterator insert_arc(const node_iterator & Initial, const node_iterator & Terminal); + out_arc_iterator insert_arc(const node_iterator & Initial, const node_iterator & Terminal, const arctype & Elem); + + // Another interface for insert_arc + out_arc_iterator insert(const nodeid & Initial, const nodeid & Terminal) { return insert_arc(Initial, Terminal); } + out_arc_iterator insert(const nodeid & Initial, const nodeid & Terminal, const arctype & Elem) { return insert_arc(Initial, Terminal, Elem); } + out_arc_iterator insert(const node_iterator & Initial, const node_iterator & Terminal) { return insert_arc(Initial, Terminal); } + out_arc_iterator insert(const node_iterator & Initial, const node_iterator & Terminal, const arctype & Elem) { return insert_arc(Initial, Terminal, Elem); } + + // Optimized (overloaded) functions + void swap(_mytype & Right); +// removed since it was causing g++ 2.95.3 to produce many compile errors +// presumably due to implicit import of the std::swap implementation. +// Robert Osfield, Jan 2002. +// friend void swap(_mytype & Left, _mytype & Right) { Left.swap(Right); } + +protected: + size_t m_NbArcs; + std::vector m_Nodes; +}; + + + +// Additional "low level", graph related, functions +template +void unmark_nodes(graph_array & G); + +template +void unmark_arcs_from_node(graph_array::node & N); + +template +void unmark_arcs(graph_array & G); + + + + +////////////////////////////////////////////////////////////////////////// +// graph_array Inline functions +////////////////////////////////////////////////////////////////////////// + +template +inline graph_array::graph_array() : m_NbArcs(0) { } + + +template +inline graph_array::graph_array(const size_t NbNodes) : m_NbArcs(0), m_Nodes(NbNodes) { } + + +template +inline void graph_array::clear() { + m_NbArcs = 0; + m_Nodes.clear(); +} + + + +template +inline bool graph_array::empty() const { + return m_Nodes.empty(); +} + + +template +inline size_t graph_array::size() const { + return m_Nodes.size(); +} + + +template +inline void graph_array::setsize(const size_t NbNodes) { + clear(); + m_Nodes.resize(NbNodes); +} + + +template +inline graph_array::node & graph_array::operator [] (const nodeid & i) { + // Debug check + assert(i < size()); + + return m_Nodes[i]; +} + + +template +inline const graph_array::node & graph_array::operator [] (const nodeid & i) const { + // Debug check + assert(i < size()); + + return m_Nodes[i]; +} + + +template +inline graph_array::node_iterator graph_array::begin() { + return m_Nodes.begin(); +} + + +template +inline graph_array::node_iterator graph_array::end() { + return m_Nodes.end(); +} + + +template +inline graph_array::const_node_iterator graph_array::begin() const { + return m_Nodes.begin(); +} + + +template +inline graph_array::const_node_iterator graph_array::end() const { + return m_Nodes.end(); +} + + +template +inline graph_array::node_reverse_iterator graph_array::rbegin() { + return m_Nodes.rbegin(); +} + + +template +inline graph_array::node_reverse_iterator graph_array::rend() { + return m_Nodes.rend(); +} + + +template +inline graph_array::const_node_reverse_iterator graph_array::rbegin() const { + return m_Nodes.rbegin(); +} + + +template +inline graph_array::const_node_reverse_iterator graph_array::rend() const { + return m_Nodes.rend(); +} + + +template +inline size_t graph_array::number_of_arcs() const { + return m_NbArcs; +} + + +template +inline graph_array::out_arc_iterator graph_array::insert_arc(const nodeid & Initial, const nodeid & Terminal) { + return (insert(begin() + Initial, begin() + Terminal)); +} + + +template +inline graph_array::out_arc_iterator graph_array::insert_arc(const nodeid & Initial, const nodeid & Terminal, const arctype & Elem) { + return (insert(begin() + Initial, begin() + Terminal, Elem)); +} + + +template +inline graph_array::out_arc_iterator graph_array::insert_arc(const node_iterator & Initial, const node_iterator & Terminal) { + ++m_NbArcs; + Initial->m_OutArcs.push_back(arc(Initial, Terminal)); + return (--(Initial->m_OutArcs.end())); +} + + +template +inline graph_array::out_arc_iterator graph_array::insert_arc(const node_iterator & Initial, const node_iterator & Terminal, const arctype & Elem) { + ++m_NbArcs; + Initial->m_OutArcs.push_back(arc(Initial, Terminal, Elem)); + return (--(Initial->m_OutArcs.end())); +} + + +template +inline graph_array::out_arc_iterator graph_array::erase_arc(const out_arc_iterator & Pos) { + --m_NbArcs; + return (Pos->initial()->m_OutArcs.erase(Pos)); +} + + +template +inline void graph_array::erase_arcs(const node_iterator & Initial) { + m_NbArcs -= (Initial->m_OutArcs.size()); + Initial->m_OutArcs.clear(); +} + + +template +inline void graph_array::erase_arcs() { + m_NbArcs = 0; + for (nodeid i = 0; i < Size(); ++i) + m_Nodes[i].m_OutArcs.clear(); +} + + +template +inline void graph_array::swap(_mytype & Right) { + std::swap(m_NbArcs, Right.m_NbArcs); + std::swap(m_Nodes, Right.m_Nodes); +} + + + +////////////////////////////////////////////////////////////////////////// +// additional functions +////////////////////////////////////////////////////////////////////////// + +template +void unmark_nodes(graph_array & G) +{ + typedef graph_array::node_iterator node_it; + + for (node_it NodeIt = G.begin(); NodeIt != G.end(); ++NodeIt) + NodeIt->unmark(); +} + + +template +void unmark_arcs_from_node(graph_array::node & N) +{ + typedef graph_array::out_arc_iterator arc_it; + + for (arc_it ArcIt = N.out_begin(); ArcIt != N.out_end(); ++ArcIt) + ArcIt->unmark(); +} + + +template +void unmark_arcs(graph_array & G) +{ + typedef graph_array::node_iterator node_it; + + for (node_it NodeIt = G.begin(); NodeIt != G.end(); ++NodeIt) + unmark_arcs_from_node(* NodeIt); +} + + + + +}; // namespace common_structures + +#endif diff --git a/src/osgUtil/TriStrip_heap_array.h b/src/osgUtil/TriStrip_heap_array.h new file mode 100644 index 000000000..a28a4997f --- /dev/null +++ b/src/osgUtil/TriStrip_heap_array.h @@ -0,0 +1,277 @@ +// heap_array.h: interface for the heap_array class. +// +////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2002 Tanguy Fautré. +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. +// +// Tanguy Fautré +// softdev@pandora.be +// +////////////////////////////////////////////////////////////////////// +// +// Semi-dynamic indexed heap +// ************************* +// +// Current version: 1.00 BETA 1 (24/10/2002) +// +// Comment: heap_array acts like a normal heap, you can push elements +// and then get the greatest one. +// However you cannot push any more element once an element +// has been removed (pop, erase, etc...). +// Elements can be modified after they've been pushed into +// the heap via their indice. +// +// History: - +// +////////////////////////////////////////////////////////////////////// + +#ifndef TRISTRIP_HEAP_ARRAY_H +#define TRISTRIP_HEAP_ARRAY_H + + +// namespace common_structures +namespace common_structures { + + + + +template > +class heap_array +{ +public: + + struct heap_is_locked { }; + + + // heap_array main interface. Pre = PreCondition, Post = PostCondition + + heap_array() : m_Locked(false) { } // Post: ((size() == 0) && ! locked()) + + void clear(); // Post: ((size() == 0) && ! locked()) + + void reserve(size_t Size); + size_t size() const; + + bool empty() const; + bool locked() const; + bool removed(size_t i) const; // Pre: (valid(i)) + bool valid(size_t i) const; + + const T & top() const; // Pre: (! empty()) + const T & peek(size_t i) const; // Pre: (valid(i) && ! removed(i)) + const T & operator [] (size_t i) const; // Pre: (valid(i) && ! removed(i)) + + size_t push(const T & Elem); // Pre: (! locked()) else throw (heap_is_locked) + + void pop(); // Pre: (! empty()) Post: (locked()) + void erase(size_t i); // Pre: (valid(i) && ! removed(i)) Post: (locked()) + void update(size_t i, const T & Elem); // Pre: (valid(i) && ! removed(i)) Post: (locked()) + +protected: + + struct linker { + linker(const T & Elem, size_t i) : m_Elem(Elem), m_Indice(i) { } + + T m_Elem; + size_t m_Indice; + }; + + typedef std::vector linked_heap; + typedef std::vector finder; + + void Adjust(size_t i); + void Swap(size_t a, size_t b); + bool Less(const linker & a, const linker & b) const; + + linked_heap m_Heap; + finder m_Finder; + CmpT m_Compare; + bool m_Locked; +}; + + + + +////////////////////////////////////////////////////////////////////////// +// heap_indexed Inline functions +////////////////////////////////////////////////////////////////////////// + +template +inline void heap_array::clear() { + m_Heap.clear(); + m_Finder.clear(); + m_Locked = false; +} + + +template +inline bool heap_array::empty() const { + return m_Heap.empty(); +} + + +template +inline bool heap_array::locked() const { + return m_Locked; +} + + +template +inline void heap_array::reserve(size_t Size) { + m_Heap.reserve(Size); + m_Finder.reserve(Size); +} + + +template +inline size_t heap_array::size() const { + return m_Heap.size(); +} + + +template +inline const T & heap_array::top() const { + // Debug check to ensure heap is not empty + assert(! empty()); + + return m_Heap.front().m_Elem; +} + + +template +inline const T & heap_array::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 +inline const T & heap_array::operator [] (size_t i) const { + return peek(i); +} + + +template +inline void heap_array::pop() { + m_Locked = true; + + // Debug check to ensure heap is not empty + assert(! empty()); + + Swap(0, size() - 1); + m_Heap.pop_back(); + Adjust(0); +} + + +template +inline size_t heap_array::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 +inline void heap_array::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 +inline bool heap_array::removed(size_t i) const { + return (m_Finder[i] >= m_Heap.size()); +} + + +template +inline bool heap_array::valid(size_t i) const { + return (i < m_Finder.size()); +} + + +template +inline void heap_array::update(size_t i, const T & Elem) { + // Debug check to ensure element is still present + assert(! removed(i)); + + size_t j = m_Finder[i]; + m_Heap[j].m_Elem = Elem; + Adjust(j); +} + + +template +inline void heap_array::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 +inline void heap_array::Swap(size_t a, size_t b) { + std::swap(m_Heap[a], m_Heap[b]); + + // use (size_t &) to get rid of a bogus compile warning + (size_t &) (m_Finder[(m_Heap[a].m_Indice)]) = a; + (size_t &) (m_Finder[(m_Heap[b].m_Indice)]) = b; +} + + +template +inline bool heap_array::Less(const linker & a, const linker & b) const { + return m_Compare(a.m_Elem, b.m_Elem); +} + + + + +}; // namespace common_structures + +#endif diff --git a/src/osgUtil/TriStrip_tri_stripper.cpp b/src/osgUtil/TriStrip_tri_stripper.cpp new file mode 100644 index 000000000..685bcaac0 --- /dev/null +++ b/src/osgUtil/TriStrip_tri_stripper.cpp @@ -0,0 +1,575 @@ +// 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 "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(-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 diff --git a/src/osgUtil/TriStrip_tri_stripper.h b/src/osgUtil/TriStrip_tri_stripper.h new file mode 100644 index 000000000..f3018fcec --- /dev/null +++ b/src/osgUtil/TriStrip_tri_stripper.h @@ -0,0 +1,380 @@ +// tri_stripper.h: interface for the tri_stripper class. +// +////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2002 Tanguy Fautré. +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required.eap_array.h TriStrip_tri_stripper.cpp TriStrip_tri_stripper.h + +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. +// +// Tanguy Fautré +// softdev@pandora.be +// +////////////////////////////////////////////////////////////////////// +// +// Tri Stripper +// ************ +// +// Current version: 1.00 BETA 5 (10/12/2002) +// +// Comment: Triangle stripper in O(n.log(n)). +// +// Currently there are no protection against crazy values +// given via SetMinStripSize() and SetCacheSize(). +// So be careful. (Min. strip size should be equal or greater +// than 2, cache size should be about 10 for GeForce 256/2 +// and about 16-18 for GeForce 3/4.) +// +// History: - 1.00 BETA 5 (10/12/2002) - Fixed a bug in Stripify() that could sometimes +// cause it to go into an infinite loop. +// (thanks to Remy for the bug report) +// - 1.00 BETA 4 (18/11/2002) - Removed the dependency on OpenGL: +// modified gl_primitives to primitives, +// and gl_primitives_vector to primitives_vector; +// and added primitive_type. +// (thanks to Patrik for noticing this useless dependency) +// - 1.00 BETA 3 (18/11/2002) - Fixed a bug in LinkNeightboursTri() that could cause a crash +// (thanks to Nicolas for finding it) +// - 1.00 BETA 2 (16/11/2002) - Improved portability +// - 1.00 BETA 1 (27/10/2002) - First public release +// +////////////////////////////////////////////////////////////////////// + +#ifndef TRISTRIP_TRI_STRIPPER_H +#define TRISTRIP_TRI_STRIPPER_H + +#include +#include +#include +#include +#include eap_array.h TriStrip_tri_stripper.cpp TriStrip_tri_stripper.h + +#include + +// 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 indices; + + enum primitive_type { + PT_Triangles = 0x0004, // = GL_TRIANGLES + PT_Triangle_Strip = 0x0005 // = GL_TRIANGLE_STRIP + }; + + struct primitives + { + indices m_Indices; + primitive_type m_Type; + }; + + typedef std::vector primitives_vector; + + 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 triangles_graph; + typedef common_structures::heap_array triangles_heap; + typedef std::vector triangle_edges; + typedef std::vector triangle_indices; + typedef std::deque indices_cache; + + + void InitCache(); + void InitTriGraph(); + void InitTriHeap(); + 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