增加第三方库NvTriStrip
This commit is contained in:
parent
e44a89af78
commit
d6ebb6a65f
9
3rdpty/NvTriStrip/CMakeLists.txt
Normal file
9
3rdpty/NvTriStrip/CMakeLists.txt
Normal file
@ -0,0 +1,9 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
|
||||
SET(NVTRISTRIP_HEADER_FILES VertexCache.h NvTriStripObjects.h NvTriStrip.h)
|
||||
SET(NVTRISTRIP_SOURCE_FILES NvTriStripObjects.cpp NvTriStrip.cpp)
|
||||
|
||||
SOURCE_GROUP("Header Files" FILES ${NVTRISTRIP_HEADER_FILES})
|
||||
SOURCE_GROUP("Source Files" FILES ${NVTRISTRIP_SOURCE_FILES})
|
||||
|
||||
add_library(NvTriStrip STATIC ${NVTRISTRIP_SOURCE_FILES} ${NVTRISTRIP_HEADER_FILES})
|
502
3rdpty/NvTriStrip/NvTriStrip.cpp
Normal file
502
3rdpty/NvTriStrip/NvTriStrip.cpp
Normal file
@ -0,0 +1,502 @@
|
||||
#include "NvTriStripObjects.h"
|
||||
#include "NvTriStrip.h"
|
||||
|
||||
namespace NvTriStrip
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
//private data
|
||||
static unsigned int cacheSize = CACHESIZE_GEFORCE3_6;
|
||||
static bool bStitchStrips = true;
|
||||
static unsigned int minStripSize = 0;
|
||||
static bool bListsOnly = false;
|
||||
static unsigned int restartVal = 0;
|
||||
static bool bRestart = false;
|
||||
|
||||
void EnableRestart(const unsigned int _restartVal)
|
||||
{
|
||||
bRestart = true;
|
||||
restartVal = _restartVal;
|
||||
}
|
||||
|
||||
void DisableRestart()
|
||||
{
|
||||
bRestart = false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// SetListsOnly()
|
||||
//
|
||||
// If set to true, will return an optimized list, with no strips at all.
|
||||
//
|
||||
// Default value: false
|
||||
//
|
||||
void SetListsOnly(const bool _bListsOnly)
|
||||
{
|
||||
bListsOnly = _bListsOnly;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// SetCacheSize()
|
||||
//
|
||||
// Sets the cache size which the stripfier uses to optimize the data.
|
||||
// Controls the length of the generated individual strips.
|
||||
// This is the "actual" cache size, so 24 for GeForce3 and 16 for GeForce1/2
|
||||
// You may want to play around with this number to tweak performance.
|
||||
//
|
||||
// Default value: 16
|
||||
//
|
||||
void SetCacheSize(const unsigned int _cacheSize)
|
||||
{
|
||||
cacheSize = _cacheSize;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// SetStitchStrips()
|
||||
//
|
||||
// bool to indicate whether to stitch together strips into one huge strip or not.
|
||||
// If set to true, you'll get back one huge strip stitched together using degenerate
|
||||
// triangles.
|
||||
// If set to false, you'll get back a large number of separate strips.
|
||||
//
|
||||
// Default value: true
|
||||
//
|
||||
void SetStitchStrips(const bool _bStitchStrips)
|
||||
{
|
||||
bStitchStrips = _bStitchStrips;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// SetMinStripSize()
|
||||
//
|
||||
// Sets the minimum acceptable size for a strip, in triangles.
|
||||
// All strips generated which are shorter than this will be thrown into one big, separate list.
|
||||
//
|
||||
// Default value: 0
|
||||
//
|
||||
void SetMinStripSize(const unsigned int _minStripSize)
|
||||
{
|
||||
minStripSize = _minStripSize;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
//Cleanup strips / faces, used by generatestrips
|
||||
void Cleanup(NvStripInfoVec& tempStrips, NvFaceInfoVec& tempFaces)
|
||||
{
|
||||
int i,j;
|
||||
|
||||
//delete strips
|
||||
for(i = 0; i < tempStrips.size(); i++)
|
||||
{
|
||||
for(j = 0; j < tempStrips[i]->m_faces.size(); j++)
|
||||
{
|
||||
delete tempStrips[i]->m_faces[j];
|
||||
tempStrips[i]->m_faces[j] = nullptr;
|
||||
}
|
||||
tempStrips[i]->m_faces.resize(0);
|
||||
delete tempStrips[i];
|
||||
tempStrips[i] = nullptr;
|
||||
}
|
||||
|
||||
//delete faces
|
||||
for(i = 0; i < tempFaces.size(); i++)
|
||||
{
|
||||
delete tempFaces[i];
|
||||
tempFaces[i] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
//SameTriangle()
|
||||
//
|
||||
//Returns true if the two triangles defined by firstTri and secondTri are the same
|
||||
// The "same" is defined in this case as having the same indices with the same winding order
|
||||
//
|
||||
bool SameTriangle(unsigned short firstTri0, unsigned short firstTri1, unsigned short firstTri2,
|
||||
unsigned short secondTri0, unsigned short secondTri1, unsigned short secondTri2)
|
||||
{
|
||||
bool isSame = false;
|
||||
|
||||
if (firstTri0 == secondTri0)
|
||||
{
|
||||
if (firstTri1 == secondTri1)
|
||||
{
|
||||
if (firstTri2 == secondTri2)
|
||||
isSame = true;
|
||||
}
|
||||
}
|
||||
else if (firstTri0 == secondTri1)
|
||||
{
|
||||
if (firstTri1 == secondTri2)
|
||||
{
|
||||
if (firstTri2 == secondTri0)
|
||||
isSame = true;
|
||||
}
|
||||
}
|
||||
else if (firstTri0 == secondTri2)
|
||||
{
|
||||
if (firstTri1 == secondTri0)
|
||||
{
|
||||
if (firstTri2 == secondTri1)
|
||||
isSame = true;
|
||||
}
|
||||
}
|
||||
|
||||
return isSame;
|
||||
}
|
||||
|
||||
|
||||
bool TestTriangle(const unsigned short v0, const unsigned short v1, const unsigned short v2, const std::vector<NvFaceInfo>* in_bins, const int NUMBINS)
|
||||
{
|
||||
//hash this triangle
|
||||
bool isLegit = false;
|
||||
int ctr = v0 % NUMBINS;
|
||||
for (int k = 0; k < in_bins[ctr].size(); ++k)
|
||||
{
|
||||
//check triangles in this bin
|
||||
if (SameTriangle(in_bins[ctr][k].m_v0, in_bins[ctr][k].m_v1, in_bins[ctr][k].m_v2,
|
||||
v0, v1, v2))
|
||||
{
|
||||
isLegit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isLegit)
|
||||
{
|
||||
ctr = v1 % NUMBINS;
|
||||
for (int k = 0; k < in_bins[ctr].size(); ++k)
|
||||
{
|
||||
//check triangles in this bin
|
||||
if (SameTriangle(in_bins[ctr][k].m_v0, in_bins[ctr][k].m_v1, in_bins[ctr][k].m_v2,
|
||||
v0, v1, v2))
|
||||
{
|
||||
isLegit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isLegit)
|
||||
{
|
||||
ctr = v2 % NUMBINS;
|
||||
for (int k = 0; k < in_bins[ctr].size(); ++k)
|
||||
{
|
||||
//check triangles in this bin
|
||||
if (SameTriangle(in_bins[ctr][k].m_v0, in_bins[ctr][k].m_v1, in_bins[ctr][k].m_v2,
|
||||
v0, v1, v2))
|
||||
{
|
||||
isLegit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return isLegit;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// GenerateStrips()
|
||||
//
|
||||
// in_indices: input index list, the indices you would use to render
|
||||
// in_numIndices: number of entries in in_indices
|
||||
// primGroups: array of optimized/stripified PrimitiveGroups
|
||||
// numGroups: number of groups returned
|
||||
//
|
||||
// Be sure to call delete[] on the returned primGroups to avoid leaking mem
|
||||
//
|
||||
bool GenerateStrips(const unsigned short* in_indices, const unsigned int in_numIndices,
|
||||
PrimitiveGroup** primGroups, unsigned short* numGroups, bool validateEnabled)
|
||||
{
|
||||
//put data in format that the stripifier likes
|
||||
WordVec tempIndices;
|
||||
tempIndices.resize(in_numIndices);
|
||||
unsigned short maxIndex = 0;
|
||||
unsigned short minIndex = 0xFFFF;
|
||||
for(int i = 0; i < in_numIndices; i++)
|
||||
{
|
||||
tempIndices[i] = in_indices[i];
|
||||
if (in_indices[i] > maxIndex)
|
||||
maxIndex = in_indices[i];
|
||||
if (in_indices[i] < minIndex)
|
||||
minIndex = in_indices[i];
|
||||
}
|
||||
NvStripInfoVec tempStrips;
|
||||
NvFaceInfoVec tempFaces;
|
||||
|
||||
NvStripifier stripifier;
|
||||
|
||||
//do actual stripification
|
||||
stripifier.Stripify(tempIndices, cacheSize, minStripSize, maxIndex, tempStrips, tempFaces);
|
||||
|
||||
//stitch strips together
|
||||
IntVec stripIndices;
|
||||
unsigned int numSeparateStrips = 0;
|
||||
|
||||
if(bListsOnly)
|
||||
{
|
||||
//if we're outputting only lists, we're done
|
||||
*numGroups = 1;
|
||||
(*primGroups) = new PrimitiveGroup[*numGroups];
|
||||
PrimitiveGroup* primGroupArray = *primGroups;
|
||||
|
||||
//count the total number of indices
|
||||
unsigned int numIndices = 0;
|
||||
for(int i = 0; i < tempStrips.size(); i++)
|
||||
{
|
||||
numIndices += tempStrips[i]->m_faces.size() * 3;
|
||||
}
|
||||
|
||||
//add in the list
|
||||
numIndices += tempFaces.size() * 3;
|
||||
|
||||
primGroupArray[0].type = PT_LIST;
|
||||
primGroupArray[0].numIndices = numIndices;
|
||||
primGroupArray[0].indices = new unsigned short[numIndices];
|
||||
|
||||
//do strips
|
||||
unsigned int indexCtr = 0;
|
||||
for(int i = 0; i < tempStrips.size(); i++)
|
||||
{
|
||||
for(int j = 0; j < tempStrips[i]->m_faces.size(); j++)
|
||||
{
|
||||
//degenerates are of no use with lists
|
||||
if(!NvStripifier::IsDegenerate(tempStrips[i]->m_faces[j]))
|
||||
{
|
||||
primGroupArray[0].indices[indexCtr++] = tempStrips[i]->m_faces[j]->m_v0;
|
||||
primGroupArray[0].indices[indexCtr++] = tempStrips[i]->m_faces[j]->m_v1;
|
||||
primGroupArray[0].indices[indexCtr++] = tempStrips[i]->m_faces[j]->m_v2;
|
||||
}
|
||||
else
|
||||
{
|
||||
//we've removed a tri, reduce the number of indices
|
||||
primGroupArray[0].numIndices -= 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//do lists
|
||||
for(int i = 0; i < tempFaces.size(); i++)
|
||||
{
|
||||
primGroupArray[0].indices[indexCtr++] = tempFaces[i]->m_v0;
|
||||
primGroupArray[0].indices[indexCtr++] = tempFaces[i]->m_v1;
|
||||
primGroupArray[0].indices[indexCtr++] = tempFaces[i]->m_v2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
stripifier.CreateStrips(tempStrips, stripIndices, bStitchStrips, numSeparateStrips, bRestart, restartVal);
|
||||
|
||||
//if we're stitching strips together, we better get back only one strip from CreateStrips()
|
||||
assert( (bStitchStrips && (numSeparateStrips == 1)) || !bStitchStrips);
|
||||
|
||||
//convert to output format
|
||||
*numGroups = numSeparateStrips; //for the strips
|
||||
if(tempFaces.size() != 0)
|
||||
(*numGroups)++; //we've got a list as well, increment
|
||||
(*primGroups) = new PrimitiveGroup[*numGroups];
|
||||
|
||||
PrimitiveGroup* primGroupArray = *primGroups;
|
||||
|
||||
//first, the strips
|
||||
int startingLoc = 0;
|
||||
for(int stripCtr = 0; stripCtr < numSeparateStrips; stripCtr++)
|
||||
{
|
||||
int stripLength = 0;
|
||||
|
||||
if(!bStitchStrips)
|
||||
{
|
||||
int i;
|
||||
//if we've got multiple strips, we need to figure out the correct length
|
||||
for(i = startingLoc; i < stripIndices.size(); i++)
|
||||
{
|
||||
if(stripIndices[i] == -1)
|
||||
break;
|
||||
}
|
||||
|
||||
stripLength = i - startingLoc;
|
||||
}
|
||||
else
|
||||
stripLength = stripIndices.size();
|
||||
|
||||
primGroupArray[stripCtr].type = PT_STRIP;
|
||||
primGroupArray[stripCtr].indices = new unsigned short[stripLength];
|
||||
primGroupArray[stripCtr].numIndices = stripLength;
|
||||
|
||||
int indexCtr = 0;
|
||||
for(int i = startingLoc; i < stripLength + startingLoc; i++)
|
||||
primGroupArray[stripCtr].indices[indexCtr++] = stripIndices[i];
|
||||
|
||||
//we add 1 to account for the -1 separating strips
|
||||
//this doesn't break the stitched case since we'll exit the loop
|
||||
startingLoc += stripLength + 1;
|
||||
}
|
||||
|
||||
//next, the list
|
||||
if(tempFaces.size() != 0)
|
||||
{
|
||||
int faceGroupLoc = (*numGroups) - 1; //the face group is the last one
|
||||
primGroupArray[faceGroupLoc].type = PT_LIST;
|
||||
primGroupArray[faceGroupLoc].indices = new unsigned short[tempFaces.size() * 3];
|
||||
primGroupArray[faceGroupLoc].numIndices = tempFaces.size() * 3;
|
||||
int indexCtr = 0;
|
||||
for(int i = 0; i < tempFaces.size(); i++)
|
||||
{
|
||||
primGroupArray[faceGroupLoc].indices[indexCtr++] = tempFaces[i]->m_v0;
|
||||
primGroupArray[faceGroupLoc].indices[indexCtr++] = tempFaces[i]->m_v1;
|
||||
primGroupArray[faceGroupLoc].indices[indexCtr++] = tempFaces[i]->m_v2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//validate generated data against input
|
||||
if (validateEnabled)
|
||||
{
|
||||
const int NUMBINS = 100;
|
||||
|
||||
std::vector<NvFaceInfo> in_bins[NUMBINS];
|
||||
|
||||
//hash input indices on first index
|
||||
for (int i = 0; i < in_numIndices; i += 3)
|
||||
{
|
||||
NvFaceInfo faceInfo(in_indices[i], in_indices[i + 1], in_indices[i + 2]);
|
||||
in_bins[in_indices[i] % NUMBINS].push_back(faceInfo);
|
||||
}
|
||||
|
||||
for (int i = 0; i < *numGroups; ++i)
|
||||
{
|
||||
switch ((*primGroups)[i].type)
|
||||
{
|
||||
case PT_LIST:
|
||||
{
|
||||
for (int j = 0; j < (*primGroups)[i].numIndices; j += 3)
|
||||
{
|
||||
unsigned short v0 = (*primGroups)[i].indices[j];
|
||||
unsigned short v1 = (*primGroups)[i].indices[j + 1];
|
||||
unsigned short v2 = (*primGroups)[i].indices[j + 2];
|
||||
|
||||
//ignore degenerates
|
||||
if (NvStripifier::IsDegenerate(v0, v1, v2))
|
||||
continue;
|
||||
|
||||
if (!TestTriangle(v0, v1, v2, in_bins, NUMBINS))
|
||||
{
|
||||
Cleanup(tempStrips, tempFaces);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PT_STRIP:
|
||||
{
|
||||
int brokenCtr = 0;
|
||||
bool flip = false;
|
||||
for (int j = 2; j < (*primGroups)[i].numIndices; ++j)
|
||||
{
|
||||
unsigned short v0 = (*primGroups)[i].indices[j - 2];
|
||||
unsigned short v1 = (*primGroups)[i].indices[j - 1];
|
||||
unsigned short v2 = (*primGroups)[i].indices[j];
|
||||
|
||||
if (flip)
|
||||
{
|
||||
//swap v1 and v2
|
||||
unsigned short swap = v1;
|
||||
v1 = v2;
|
||||
v2 = swap;
|
||||
}
|
||||
|
||||
//ignore degenerates
|
||||
if (NvStripifier::IsDegenerate(v0, v1, v2))
|
||||
{
|
||||
flip = !flip;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!TestTriangle(v0, v1, v2, in_bins, NUMBINS))
|
||||
{
|
||||
Cleanup(tempStrips, tempFaces);
|
||||
return false;
|
||||
}
|
||||
|
||||
flip = !flip;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PT_FAN:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//clean up everything
|
||||
Cleanup(tempStrips, tempFaces);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// RemapIndices()
|
||||
//
|
||||
// Function to remap your indices to improve spatial locality in your vertex buffer.
|
||||
//
|
||||
// in_primGroups: array of PrimitiveGroups you want remapped
|
||||
// numGroups: number of entries in in_primGroups
|
||||
// numVerts: number of vertices in your vertex buffer, also can be thought of as the range
|
||||
// of acceptable values for indices in your primitive groups.
|
||||
// remappedGroups: array of remapped PrimitiveGroups
|
||||
//
|
||||
// Note that, according to the remapping handed back to you, you must reorder your
|
||||
// vertex buffer.
|
||||
//
|
||||
void RemapIndices(const PrimitiveGroup* in_primGroups, const unsigned short numGroups,
|
||||
const unsigned short numVerts, PrimitiveGroup** remappedGroups)
|
||||
{
|
||||
(*remappedGroups) = new PrimitiveGroup[numGroups];
|
||||
|
||||
//caches oldIndex --> newIndex conversion
|
||||
int *indexCache;
|
||||
indexCache = new int[numVerts];
|
||||
memset(indexCache, -1, sizeof(int)*numVerts);
|
||||
|
||||
//loop over primitive groups
|
||||
unsigned int indexCtr = 0;
|
||||
for(int i = 0; i < numGroups; i++)
|
||||
{
|
||||
unsigned int numIndices = in_primGroups[i].numIndices;
|
||||
|
||||
//init remapped group
|
||||
(*remappedGroups)[i].type = in_primGroups[i].type;
|
||||
(*remappedGroups)[i].numIndices = numIndices;
|
||||
(*remappedGroups)[i].indices = new unsigned short[numIndices];
|
||||
|
||||
for(int j = 0; j < numIndices; j++)
|
||||
{
|
||||
int cachedIndex = indexCache[in_primGroups[i].indices[j]];
|
||||
if(cachedIndex == -1) //we haven't seen this index before
|
||||
{
|
||||
//point to "last" vertex in VB
|
||||
(*remappedGroups)[i].indices[j] = indexCtr;
|
||||
|
||||
//add to index cache, increment
|
||||
indexCache[in_primGroups[i].indices[j]] = indexCtr++;
|
||||
}
|
||||
else
|
||||
{
|
||||
//we've seen this index before
|
||||
(*remappedGroups)[i].indices[j] = cachedIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete[] indexCache;
|
||||
}
|
||||
}//namespace NvTriStrip
|
141
3rdpty/NvTriStrip/NvTriStrip.h
Normal file
141
3rdpty/NvTriStrip/NvTriStrip.h
Normal file
@ -0,0 +1,141 @@
|
||||
#ifndef NVTRISTRIP_H
|
||||
#define NVTRISTRIP_H
|
||||
|
||||
namespace NvTriStrip
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Public interface for stripifier
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//GeForce1 and 2 cache size
|
||||
#define CACHESIZE_GEFORCE1_2 16
|
||||
|
||||
//GeForce3 and 4,5,6 cache size
|
||||
#define CACHESIZE_GEFORCE3_6 24
|
||||
|
||||
enum PrimType
|
||||
{
|
||||
PT_LIST,
|
||||
PT_STRIP,
|
||||
PT_FAN
|
||||
};
|
||||
|
||||
struct PrimitiveGroup
|
||||
{
|
||||
PrimType type;
|
||||
unsigned int numIndices;
|
||||
unsigned short* indices;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PrimitiveGroup() : type(PT_STRIP), numIndices(0), indices(nullptr) {}
|
||||
~PrimitiveGroup()
|
||||
{
|
||||
if(indices)
|
||||
delete[] indices;
|
||||
indices = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// EnableRestart()
|
||||
//
|
||||
// For GPUs that support primitive restart, this sets a value as the restart index
|
||||
//
|
||||
// Restart is meaningless if strips are not being stitched together, so enabling restart
|
||||
// makes NvTriStrip forcing stitching. So, you'll get back one strip.
|
||||
//
|
||||
// Default value: disabled
|
||||
//
|
||||
void EnableRestart(const unsigned int restartVal);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// DisableRestart()
|
||||
//
|
||||
// For GPUs that support primitive restart, this disables using primitive restart
|
||||
//
|
||||
void DisableRestart();
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// SetCacheSize()
|
||||
//
|
||||
// Sets the cache size which the stripfier uses to optimize the data.
|
||||
// Controls the length of the generated individual strips.
|
||||
// This is the "actual" cache size, so 24 for GeForce3 and 16 for GeForce1/2
|
||||
// You may want to play around with this number to tweak performance.
|
||||
//
|
||||
// Default value: 16
|
||||
//
|
||||
void SetCacheSize(const unsigned int cacheSize);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// SetStitchStrips()
|
||||
//
|
||||
// bool to indicate whether to stitch together strips into one huge strip or not.
|
||||
// If set to true, you'll get back one huge strip stitched together using degenerate
|
||||
// triangles.
|
||||
// If set to false, you'll get back a large number of separate strips.
|
||||
//
|
||||
// Default value: true
|
||||
//
|
||||
void SetStitchStrips(const bool bStitchStrips);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// SetMinStripSize()
|
||||
//
|
||||
// Sets the minimum acceptable size for a strip, in triangles.
|
||||
// All strips generated which are shorter than this will be thrown into one big, separate list.
|
||||
//
|
||||
// Default value: 0
|
||||
//
|
||||
void SetMinStripSize(const unsigned int minSize);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// SetListsOnly()
|
||||
//
|
||||
// If set to true, will return an optimized list, with no strips at all.
|
||||
//
|
||||
// Default value: false
|
||||
//
|
||||
void SetListsOnly(const bool bListsOnly);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// GenerateStrips()
|
||||
//
|
||||
// in_indices: input index list, the indices you would use to render
|
||||
// in_numIndices: number of entries in in_indices
|
||||
// primGroups: array of optimized/stripified PrimitiveGroups
|
||||
// numGroups: number of groups returned
|
||||
//
|
||||
// Be sure to call delete[] on the returned primGroups to avoid leaking mem
|
||||
//
|
||||
bool GenerateStrips(const unsigned short* in_indices, const unsigned int in_numIndices,
|
||||
PrimitiveGroup** primGroups, unsigned short* numGroups, bool validateEnabled = false);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// RemapIndices()
|
||||
//
|
||||
// Function to remap your indices to improve spatial locality in your vertex buffer.
|
||||
//
|
||||
// in_primGroups: array of PrimitiveGroups you want remapped
|
||||
// numGroups: number of entries in in_primGroups
|
||||
// numVerts: number of vertices in your vertex buffer, also can be thought of as the range
|
||||
// of acceptable values for indices in your primitive groups.
|
||||
// remappedGroups: array of remapped PrimitiveGroups
|
||||
//
|
||||
// Note that, according to the remapping handed back to you, you must reorder your
|
||||
// vertex buffer.
|
||||
//
|
||||
// Credit goes to the MS Xbox crew for the idea for this interface.
|
||||
//
|
||||
void RemapIndices(const PrimitiveGroup* in_primGroups, const unsigned short numGroups,
|
||||
const unsigned short numVerts, PrimitiveGroup** remappedGroups);
|
||||
}//namespace NvTriStrip
|
||||
#endif
|
1757
3rdpty/NvTriStrip/NvTriStripObjects.cpp
Normal file
1757
3rdpty/NvTriStrip/NvTriStripObjects.cpp
Normal file
File diff suppressed because it is too large
Load Diff
243
3rdpty/NvTriStrip/NvTriStripObjects.h
Normal file
243
3rdpty/NvTriStrip/NvTriStripObjects.h
Normal file
@ -0,0 +1,243 @@
|
||||
#ifndef NV_TRISTRIP_OBJECTS_H
|
||||
#define NV_TRISTRIP_OBJECTS_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <windows.h>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include "VertexCache.h"
|
||||
|
||||
namespace NvTriStrip
|
||||
{
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Types defined for stripification
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct MyVertex {
|
||||
float x, y, z;
|
||||
float nx, ny, nz;
|
||||
};
|
||||
|
||||
typedef MyVertex MyVector;
|
||||
|
||||
struct MyFace {
|
||||
int v1, v2, v3;
|
||||
float nx, ny, nz;
|
||||
};
|
||||
|
||||
class NvFaceInfo {
|
||||
public:
|
||||
|
||||
// vertex indices
|
||||
NvFaceInfo(int v0, int v1, int v2, bool bIsFake = false){
|
||||
m_v0 = v0; m_v1 = v1; m_v2 = v2;
|
||||
m_stripId = -1;
|
||||
m_testStripId = -1;
|
||||
m_experimentId = -1;
|
||||
m_bIsFake = bIsFake;
|
||||
}
|
||||
|
||||
// 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?
|
||||
bool m_bIsFake; //if true, will be deleted when the strip it's in is deleted
|
||||
};
|
||||
|
||||
// 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 = nullptr;
|
||||
m_face1 = nullptr;
|
||||
m_nextV0 = nullptr;
|
||||
m_nextV1 = nullptr;
|
||||
|
||||
// we will appear in 2 lists. this is a good
|
||||
// way to make sure we delete it the second time
|
||||
// we hit it in the edge infos
|
||||
m_refCount = 2;
|
||||
|
||||
}
|
||||
|
||||
// ref and unref
|
||||
void Unref () { if (--m_refCount == 0) delete this; }
|
||||
|
||||
// data members are left public
|
||||
UINT m_refCount;
|
||||
NvFaceInfo *m_face0, *m_face1;
|
||||
int m_v0, m_v1;
|
||||
NvEdgeInfo *m_nextV0, *m_nextV1;
|
||||
};
|
||||
|
||||
|
||||
// This class is a quick summary of parameters used
|
||||
// to begin a triangle strip. Some operations may
|
||||
// want to create lists of such items, so they were
|
||||
// pulled out into a class
|
||||
class NvStripStartInfo {
|
||||
public:
|
||||
NvStripStartInfo(NvFaceInfo *startFace, NvEdgeInfo *startEdge, bool toV1){
|
||||
m_startFace = startFace;
|
||||
m_startEdge = startEdge;
|
||||
m_toV1 = toV1;
|
||||
}
|
||||
NvFaceInfo *m_startFace;
|
||||
NvEdgeInfo *m_startEdge;
|
||||
bool m_toV1;
|
||||
};
|
||||
|
||||
|
||||
typedef std::vector<NvFaceInfo*> NvFaceInfoVec;
|
||||
typedef std::list <NvFaceInfo*> NvFaceInfoList;
|
||||
typedef std::list <NvFaceInfoVec*> NvStripList;
|
||||
typedef std::vector<NvEdgeInfo*> NvEdgeInfoVec;
|
||||
|
||||
typedef std::vector<WORD> WordVec;
|
||||
typedef std::vector<int> IntVec;
|
||||
typedef std::vector<MyVertex> MyVertexVec;
|
||||
typedef std::vector<MyFace> MyFaceVec;
|
||||
|
||||
template<class T>
|
||||
inline void SWAP(T& first, T& second)
|
||||
{
|
||||
T temp = first;
|
||||
first = second;
|
||||
second = temp;
|
||||
}
|
||||
|
||||
// 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;
|
||||
m_numDegenerates = 0;
|
||||
}
|
||||
|
||||
// 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 == nullptr)
|
||||
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;
|
||||
|
||||
int m_numDegenerates;
|
||||
};
|
||||
|
||||
typedef std::vector<NvStripInfo*> NvStripInfoVec;
|
||||
|
||||
//The actual stripifier
|
||||
class NvStripifier {
|
||||
public:
|
||||
|
||||
// Constructor
|
||||
NvStripifier()=default;
|
||||
~NvStripifier()=default;
|
||||
|
||||
//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_cacheSize, const int in_minStripLength,
|
||||
const unsigned short maxIndex, NvStripInfoVec &allStrips, NvFaceInfoVec &allFaces);
|
||||
void CreateStrips(const NvStripInfoVec& allStrips, IntVec& stripIndices, const bool bStitchStrips, unsigned int& numSeparateStrips, const bool bRestart, const unsigned int restartVal);
|
||||
|
||||
static int GetUniqueVertexInB(NvFaceInfo *faceA, NvFaceInfo *faceB);
|
||||
//static int GetSharedVertex(NvFaceInfo *faceA, NvFaceInfo *faceB);
|
||||
static void GetSharedVertices(NvFaceInfo *faceA, NvFaceInfo *faceB, int* vertex0, int* vertex1);
|
||||
|
||||
static bool IsDegenerate(const NvFaceInfo* face);
|
||||
static bool IsDegenerate(const unsigned short v0, const unsigned short v1, const unsigned short v2);
|
||||
|
||||
protected:
|
||||
|
||||
WordVec indices;
|
||||
int cacheSize;
|
||||
int minStripLength;
|
||||
float meshJump;
|
||||
bool bFirstTimeResetPoint;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Big mess of functions called during stripification
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//********************
|
||||
bool IsMoneyFace(const NvFaceInfo& face);
|
||||
bool FaceContainsIndex(const NvFaceInfo& face, const unsigned int index);
|
||||
|
||||
bool IsCW(NvFaceInfo *faceInfo, int v0, int v1);
|
||||
bool NextIsCW(const int numIndices);
|
||||
|
||||
static int GetNextIndex(const WordVec &indices, NvFaceInfo *face);
|
||||
static NvEdgeInfo *FindEdgeInfo(NvEdgeInfoVec &edgeInfos, int v0, int v1);
|
||||
static NvFaceInfo *FindOtherFace(NvEdgeInfoVec &edgeInfos, int v0, int v1, NvFaceInfo *faceInfo);
|
||||
NvFaceInfo *FindGoodResetPoint(NvFaceInfoVec &faceInfos, NvEdgeInfoVec &edgeInfos);
|
||||
|
||||
void FindAllStrips(NvStripInfoVec &allStrips, NvFaceInfoVec &allFaceInfos, NvEdgeInfoVec &allEdgeInfos, int numSamples);
|
||||
void SplitUpStripsAndOptimize(NvStripInfoVec &allStrips, NvStripInfoVec &outStrips, NvEdgeInfoVec& edgeInfos, NvFaceInfoVec& outFaceList);
|
||||
void RemoveSmallStrips(NvStripInfoVec& allStrips, NvStripInfoVec& allBigStrips, NvFaceInfoVec& faceList);
|
||||
|
||||
bool FindTraversal(NvFaceInfoVec &faceInfos, NvEdgeInfoVec &edgeInfos, NvStripInfo *strip, NvStripStartInfo &startInfo);
|
||||
int CountRemainingTris(std::list<NvStripInfo*>::iterator iter, std::list<NvStripInfo*>::iterator end);
|
||||
|
||||
void CommitStrips(NvStripInfoVec &allStrips, const NvStripInfoVec &strips);
|
||||
|
||||
float AvgStripSize(const NvStripInfoVec &strips);
|
||||
int FindStartPoint(NvFaceInfoVec &faceInfos, NvEdgeInfoVec &edgeInfos);
|
||||
|
||||
void UpdateCacheStrip(VertexCache* vcache, NvStripInfo* strip);
|
||||
void UpdateCacheFace(VertexCache* vcache, NvFaceInfo* face);
|
||||
float CalcNumHitsStrip(VertexCache* vcache, NvStripInfo* strip);
|
||||
int CalcNumHitsFace(VertexCache* vcache, NvFaceInfo* face);
|
||||
int NumNeighbors(NvFaceInfo* face, NvEdgeInfoVec& edgeInfoVec);
|
||||
|
||||
void BuildStripifyInfo(NvFaceInfoVec &faceInfos, NvEdgeInfoVec &edgeInfos, const unsigned short maxIndex);
|
||||
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 NvStripInfo;
|
||||
};
|
||||
}//namespace NvTriStrip
|
||||
#endif
|
79
3rdpty/NvTriStrip/VertexCache.h
Normal file
79
3rdpty/NvTriStrip/VertexCache.h
Normal file
@ -0,0 +1,79 @@
|
||||
#ifndef VERTEX_CACHE_H
|
||||
#define VERTEX_CACHE_H
|
||||
|
||||
#include<string.h>
|
||||
|
||||
namespace NvTriStrip
|
||||
{
|
||||
class VertexCache
|
||||
{
|
||||
public:
|
||||
|
||||
VertexCache(int size)
|
||||
{
|
||||
numEntries = size;
|
||||
|
||||
entries = new int[numEntries];
|
||||
|
||||
for(int i = 0; i < numEntries; i++)
|
||||
entries[i] = -1;
|
||||
}
|
||||
|
||||
VertexCache() { VertexCache(16); }
|
||||
~VertexCache() { delete[] entries; entries = nullptr; }
|
||||
|
||||
bool InCache(int entry)
|
||||
{
|
||||
bool returnVal = false;
|
||||
for(int i = 0; i < numEntries; i++)
|
||||
{
|
||||
if(entries[i] == entry)
|
||||
{
|
||||
returnVal = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return returnVal;
|
||||
}
|
||||
|
||||
int 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;
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
memset(entries, -1, sizeof(int) * numEntries);
|
||||
}
|
||||
|
||||
void Copy(VertexCache* inVcache)
|
||||
{
|
||||
for(int i = 0; i < numEntries; i++)
|
||||
{
|
||||
inVcache->Set(i, entries[i]);
|
||||
}
|
||||
}
|
||||
|
||||
int At(int index) { return entries[index]; }
|
||||
void Set(int index, int value) { entries[index] = value; }
|
||||
|
||||
private:
|
||||
|
||||
int *entries;
|
||||
int numEntries;
|
||||
};
|
||||
}//namespace NvTriStrip
|
||||
#endif
|
@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
|
||||
PROJECT(ULRE)
|
||||
|
||||
@ -14,8 +14,7 @@ check_system_bits()
|
||||
check_system_version()
|
||||
set_compiler_param()
|
||||
set_output_directory()
|
||||
|
||||
|
||||
|
||||
IF(WIN32)
|
||||
add_subdirectory(3rdpty/glfw)
|
||||
include_directories(3rdpty/glfw/include)
|
||||
@ -39,13 +38,14 @@ add_definitions(-DMATH_AVX)
|
||||
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/3rdpty/MathGeoLib/src)
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/3rdpty/GLEWCore/inc)
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/3rdpty/NvTriStrip)
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/inc)
|
||||
|
||||
|
||||
SET(ROOT_INCLUDE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/inc)
|
||||
|
||||
add_subdirectory(3rdpty/MathGeoLib)
|
||||
add_subdirectory(3rdpty/GLEWCore)
|
||||
add_subdirectory(3rdpty/NvTriStrip)
|
||||
add_subdirectory(src)
|
||||
|
||||
SET(ULRE ULRE.Base
|
||||
|
Loading…
x
Reference in New Issue
Block a user