Commit 72fb3910 authored by Christopher Tenter's avatar Christopher Tenter
Browse files

MeshCompiler: 64bit stability + docu update

git-svn-id: http://www.openflipper.org/svnrepo/OpenFlipper/branches/Free@17005 383ad7c9-94d9-4d36-a494-682f7c89f535
parent 43fbaa25
......@@ -5,7 +5,7 @@
#include <list>
#include <cassert>
#include <iostream>
#include <sstream>
#include <ACG/Geometry/GPUCacheOptimizer.hh>
......@@ -329,8 +329,8 @@ void MeshCompiler::setAttribVec(int _attrIdx, int _num, const void* _data, int _
// copy elementwise because of striding
for (int i = 0; i < _num; ++i)
{
memcpy(inbuf->internalBuf + size * i,
(const char*)_data + _stride * i,
memcpy(inbuf->internalBuf + (size_t)(size * i),
(const char*)_data + (size_t)(_stride * i),
size);
}
}
......@@ -389,7 +389,7 @@ void MeshCompiler::splitVertices()
int fsize = getFaceSize(i);
curOffset += fsize;
maxFaceCorners_ = std::max(maxFaceCorners_, fsize);
maxFaceCorners_ = std::max((int)maxFaceCorners_, fsize);
}
delete splitter_;
......@@ -397,7 +397,6 @@ void MeshCompiler::splitVertices()
input_[inputIDPos_].count,
adjacencyVert_.bufSize);
numIndices_ = faceInput_->getNumIndices();
faceBufSplit_.resize(numIndices_, -1);
// count # vertices after splitting
......@@ -534,7 +533,7 @@ void MeshCompiler::forceUnsharedFaceVertex()
}
void MeshCompiler::getInputFaceVertex( int i, int j, int* _out )
void MeshCompiler::getInputFaceVertex( int i, int j, int* _out ) const
{
for (unsigned int k = 0; k < decl_.getNumElements(); ++k)
_out[k] = getInputIndex(i, j, k);
......@@ -556,7 +555,6 @@ MeshCompiler::MeshCompiler(const VertexDeclaration& _decl)
numTris_ = 0;
numFaces_ = 0;
interleavedInput_ = 0;
curFaceInputPos_ = 0;
indices_ = 0;
......@@ -664,10 +662,6 @@ void MeshCompiler::setNumFaces( const int _numFaces, const int _numIndices )
faceInput_ = internalInput;
deleteFaceInputeData_ = true;
// internal face-offset buffer required for mesh processing
faceStart_.resize(_numFaces, -1);
faceSize_.resize(_numFaces, 0);
}
......@@ -683,12 +677,6 @@ void MeshCompiler::setFaceAttrib( int _i, int _numEdges, int* _v, int _attrID )
{
input->setFaceData(_i, _numEdges, _v, _attrID);
}
if (faceSize_.empty())
faceSize_.resize(numFaces_, 0);
faceSize_[_i] = (short)_numEdges;
}
void MeshCompiler::setFaceAttrib( int _i, int _v0, int _v1, int _v2, int _attrID )
......@@ -1059,6 +1047,9 @@ void MeshCompiler::optimize()
void MeshCompiler::build(bool _optimizeVCache, bool _needPerFaceAttribute)
{
// array allocation/copy data/validation check etc.
prepareData();
/*
1. step
Split vertices s.t. we can create an interleaved vertex buffer.
......@@ -1174,7 +1165,7 @@ void MeshCompiler::setAttrib( int _attrIdx, int _v, const void* _data )
assert(inbuf->count > _v);
memcpy(inbuf->internalBuf + _v * inbuf->stride, _data, inbuf->attrSize);
memcpy(inbuf->internalBuf + (size_t)(_v * inbuf->stride), _data, inbuf->attrSize);
}
......@@ -1234,8 +1225,6 @@ void MeshCompiler::dbgdump(const char* _filename) const
fprintf(file, "faces %d\nindices %d\n", numFaces_, numIndices_);
fprintf(file, "interleavedInput %d\n\n", interleavedInput_);
for (size_t i = 0; i < faceBufSplit_.size(); ++i)
fprintf(file, "faceBufSplit_[%d] = %d\n", (int)i, faceBufSplit_[i]);
......@@ -1316,7 +1305,7 @@ void MeshCompiler::VertexElementInput::getElementData(int _idx, void* _dst) cons
assert(_idx >= 0);
assert(_idx < count);
memcpy(_dst, data + _idx * stride, attrSize);
memcpy(_dst, data + (size_t)(_idx * stride), attrSize);
}
......@@ -1511,8 +1500,8 @@ void MeshCompiler::dbgdumpAdjList( const char* _filename ) const
void MeshCompiler::setFaceGroup( int _i, int _groupID )
{
if ((int)faceGroupIDs_.size() < numFaces_)
faceGroupIDs_.resize(numFaces_, -1);
if ((int)faceGroupIDs_.size() <= std::max(numFaces_,_i))
faceGroupIDs_.resize(std::max(numFaces_,_i+1), -1);
faceGroupIDs_[_i] = _groupID;
}
......@@ -1568,7 +1557,7 @@ int MeshCompiler::mapToDrawTriID( const int _faceID, const int _k /*= 0*/, int*
return faceToTriMap_[offset + _k];
}
int MeshCompiler::getMemoryUsage() const
size_t MeshCompiler::getMemoryUsage() const
{
size_t usage = faceStart_.size() * 4;
usage += faceSize_.size() * 2;
......@@ -1599,6 +1588,105 @@ int MeshCompiler::getMemoryUsage() const
return usage;
}
std::string MeshCompiler::checkInputData() const
{
std::stringstream strm;
int faceV[16];
for (int i = 0; i < numFaces_; ++i)
{
std::map<int, int> facePositions;
for (int k = 0; k < getFaceSize(i); ++k)
{
getInputFaceVertex(i, k, faceV);
for (int a = 0; a < numAttributes_; ++a)
{
// index boundary check
if (faceV[a] >= input_[a].count)
strm << "Error: input index (face/corner/attribute: " << i << "/" << k << "/" << a << ") invalid: " << faceV[a] << " >= buffer size (" << input_[a].count << ")\n";
if (faceV[a] < 0)
strm << "Error: input index (face/corner/attribute: " << i << "/" << k << "/" << a << ") invalid: " << faceV[a] << "\n";
}
if (numAttributes_)
facePositions[faceV[0]] = k;
}
// degenerate check
if ((int)facePositions.size() != getFaceSize(i))
strm << "Warning: degenerate face " << i << "\n";
// empty face
if (!getFaceSize(i))
strm << "Warning: empty face " << i << "\n";
}
return strm.str();
}
void MeshCompiler::prepareData()
{
// update face count, in case not provided by user
numFaces_ = faceInput_->getNumFaces();
numIndices_ = faceInput_->getNumIndices();
// clip empty faces from the end (user estimated too many faces)
for (int i = numFaces_-1; i >= 0 && !faceInput_->getFaceSize(i); --i)
--numFaces_;
// internal face-offset buffer required for mesh processing
faceStart_.resize(numFaces_, -1);
faceSize_.resize(numFaces_, 0);
for (int i = 0; i < numFaces_; ++i)
{
faceSize_[i] = (short)faceInput_->getFaceSize(i);
numIndices_ += faceSize_[i];
}
}
void MeshCompiler::setFaceInput( MeshCompilerFaceInput* _faceInput )
{
faceInput_ = _faceInput;
}
void MeshCompiler::setIndexBufferInterleaved( int _numTris, int _indexSize, const void* _indices )
{
assert(_indices);
assert(_indexSize);
setNumFaces(_numTris, _numTris * 3);
for (int i = 0; i < _numTris; ++i)
{
int tri[3] = {-1, -1, -1};
for (int k = 0; k < 3; ++k)
{
int offs = i * 3 + k;
switch(_indexSize)
{
case 1: tri[k] = ((char*)_indices)[offs]; break;
case 2: tri[k] = ((short*)_indices)[offs]; break;
case 4: tri[k] = ((int*)_indices)[offs]; break;
case 8: tri[k] = (int)((long long*)_indices)[offs]; break;
default: break;
}
}
setFaceVerts(i, 3, tri);
}
}
int MeshCompiler::getNumFaces() const
{
return numFaces_;
}
void MeshCompilerDefaultFaceInput::dbgWriteToObjFile(FILE* _file, int _posAttrID, int _normalAttrID, int _texcAttrID)
{
......@@ -1646,11 +1734,23 @@ int MeshCompilerDefaultFaceInput::getSingleFaceAttr( int _faceID, int _faceCorne
int offset = faceOffset_[_faceID];
assert(_faceCorner < getFaceSize(_faceID));
if (faceData_[_attrID].empty())
{
// try to use index from base vertex element (usually position)
return faceData_[0][offset + _faceCorner];
}
return faceData_[_attrID][offset + _faceCorner];
}
void MeshCompilerDefaultFaceInput::setFaceData( int _faceID, int _size, int* _data, int _attrID /*= 0*/ )
{
// update face count
if (numFaces_ <= _faceID)
numFaces_ = _faceID + 1;
// reserve mem
if (faceData_[_attrID].capacity() == 0)
faceData_[_attrID].reserve(numIndices_);
......
......@@ -5,6 +5,7 @@
#include <map>
#include <vector>
#include <cstdio>
#include <string>
/*
......@@ -167,6 +168,11 @@ public:
virtual ~MeshCompiler();
//===========================================================================
/** @name Vertex Data Input
* @{ */
//===========================================================================
/** set input vertex positions
*
* @param _num Number of vertex positions
......@@ -204,11 +210,36 @@ public:
void setAttrib(int _attrIdx, int _v, const void* _data);
/** @} */
//===========================================================================
/** @name Flexible Face Data Input
* @{ */
//===========================================================================
/** Set Face data input
*
* Making use of the MeshCompilerFaceInput interface completly overrides the default input behavior.
* Any subsequent call to default input data functions such as setNumFaces(), setFaceVerts() etc. will be ignored
*
* @param _faceInput user defined face input (no internal copy made, do not delete while using MeshCompiler)
*/
void setFaceInput(MeshCompilerFaceInput* _faceInput);
/** @} */
//===========================================================================
/** @name Default Face Data Input
* @{ */
//===========================================================================
/** set number of faces and indices
/** Set number of faces and indices if known by user
*
* @param _numFaces Number of faces.
* @param _numIndices Number of indices, i.e. 3 * numFaces for triangle meshes. Value 0 accepted if unknown (performance hit)
* User may give a rough estimate of face/index count.
* A more accurate estimation improves efficiency: too low numbers result in performance hit, too high numbers in memory consumption
* @param _numFaces Number of faces. Value 0 accepted at cost of performance
* @param _numIndices Number of indices, i.e. 3 * numFaces for triangle meshes. Value 0 accepted at cost of performance
*/
void setNumFaces(const int _numFaces, const int _numIndices);
......@@ -222,20 +253,85 @@ public:
*/
void setIndexBufferInterleaved(int _numTris, int _indexSize, const void* _indices);
/** Set vertex ids per triangle.
*
* @param _i Face ID
* @param _v0 1st vertex id
* @param _v1 2nd vertex id
* @param _v2 3rd vertex id
*/
void setFaceVerts(int _i, int _v0, int _v1, int _v2);
void setFaceVerts(int _i, int _numEdges, int* _v);
/** Set vertex ids per face.
*
* @param _i Face id
* @param _faceSize Size of face, ie. number of vertices of face
* @param _v Vertex ids
*/
void setFaceVerts(int _i, int _faceSize, int* _v);
/** Set normal ids per triangle.
*
* @param _i Face ID
* @param _v0 1st normal id
* @param _v1 2nd normal id
* @param _v2 3rd normal id
*/
void setFaceNormals(int _i, int _v0, int _v1, int _v2);
void setFaceNormals(int _i, int _numEdges, int* _v);
/** Set normal ids per face.
*
* @param _i Face id
* @param _faceSize Size of face, ie. number of vertices of face
* @param _v Normal ids
*/
void setFaceNormals(int _i, int _faceSize, int* _v);
/** Set texcoord ids per triangle.
*
* @param _i Face ID
* @param _v0 1st texcoord id
* @param _v1 2nd texcoord id
* @param _v2 3rd texcoord id
*/
void setFaceTexCoords(int _i, int _v0, int _v1, int _v2);
void setFaceTexCoords(int _i, int _numEdges, int* _v);
/** Set texcoord ids per face.
*
* @param _i Face id
* @param _faceSize Size of face, ie. number of vertices of face
* @param _v Texcoord ids
*/
void setFaceTexCoords(int _i, int _faceSize, int* _v);
/** Set attribute ids per triangle.
*
* @param _i Face id
* @param _v0 1st element id
* @param _v1 2nd element id
* @param _v2 3rd element id
* @param _attrID Which attribute: index of VertexDeclaration element array
*/
void setFaceAttrib(int _i, int _v0, int _v1, int _v2, int _attrID);
void setFaceAttrib(int _i, int _numEdges, int* _v, int _attrID);
void setFaceInterleaved(int _it, int _v0, int _v1, int _v2);
void setFaceInterleaved(int _it, int _numEdges, int* _v);
/** Set attribute ids per face.
*
* @param _i Face id
* @param _faceSize Size of face, ie. number of vertices of face
* @param _v Element ids
* @param _attrID Which attribute: index of VertexDeclaration element array
*/
void setFaceAttrib(int _i, int _faceSize, int* _v, int _attrID);
/** @} */
//===========================================================================
/** @name Face Grouping and Subsets
* @{ */
//===========================================================================
/** Specify face groups.
*
......@@ -246,18 +342,39 @@ public:
*/
void setFaceGroup(int _i, int _groupID);
inline int getFaceSize(const int _i) const
// subset/group management
struct Subset
{
// return faceInput_->getFaceSize(_i);
return faceSize_[_i];
}
int id; // subset id
unsigned int startIndex; // 1st occurrence of group in index buffer
unsigned int numTris; // number of tris belonging to subset in index buffer
unsigned int numFaces; // number of faces belonging to subset
unsigned int startFace; // index into sorted list of faces
};
/// get subset ID of a group
int findGroupSubset(int _groupID);
int getFaceGroup(int _faceID) const;
int getTriGroup(int _triID) const;
int getNumSubsets() const {return (int)subsets_.size();}
const Subset* getSubset(int _i) const;
/** @} */
/* \brief Build draw vertex + index buffer.
//===========================================================================
/** @name Mesh Compilation
* @{ */
//===========================================================================
/* \brief Build vertex + index buffer.
*
* @param _optimizeVCache Reorder faces for optimized vcache usage. Low performance hit
* @param _needPerFaceAttribute User wants to set per-face attributes in draw vertex buffer. The first referenced vertex of each face can be used to store per-face data. Big performance hit
* @param _optimizeVCache Reorder faces for optimized vcache usage. Low performance hit on build() execution time
* @param _needPerFaceAttribute User wants to set per-face attributes in draw vertex buffer. The first referenced vertex of each face can be used to store per-face data. High performance hit on execution time
*/
void build(bool _optimizeVCache = true, bool _needPerFaceAttribute = false);
......@@ -273,16 +390,24 @@ public:
void getVertexBuffer(void* _dst, const int _offset = 0, const int _range = -1);
/* Get index buffer ready for rendering.
*
* @param _dst Pointer to memory address where the index buffer should be copied to
*/
void getIndexBuffer(void* _dst) const;
int* getIndexBuffer() const {return indices_;}
/** Get number of triangles in final buffer.
*/
int getNumTriangles() const;
/** Get number of input faces.
*/
int getNumFaces() const;
/** Get size of input face
*/
inline int getFaceSize(const int _i) const
{
return faceSize_[_i];
}
/** Get vertex in final draw vertex buffer.
*/
void getVertex(int _id, void* _out) const;
......@@ -291,6 +416,17 @@ public:
*/
int getIndex(int _i) const;
/** @} */
//===========================================================================
/** @name Input/Output ID mapping
* @{ */
//===========================================================================
/** Mapping from draw vertex id -> input vertex id
*
* @param _i Vertex ID in draw buffer
......@@ -325,39 +461,19 @@ public:
*/
int mapToDrawTriID(const int _faceID, const int _k = 0, int* _numTrisOut = 0) const;
// fast update functions if input data changed
void updateFace(int _faceID);
void updateFaces();
/** @} */
// subset/group management
struct Subset
{
int id;
unsigned int startIndex;
unsigned int numTris;
unsigned int numFaces;
unsigned int startFace; // index into sorted list
};
/// get subset ID of a group
int findGroupSubset(int _groupID);
int getFaceGroup(int _faceID) const;
int getTriGroup(int _triID) const;
int getNumSubsets() const {return subsets_.size();}
const Subset* getSubset(int _i) const;
private:
// compute adjacency information: vertex -> neighboring faces, face -> neighboring faces
void computeAdjacency();
// convert per-face vertices to unique ids
void splitVertices();
private:
......@@ -368,7 +484,7 @@ private:
j: corner index
_out: output vertex (index for each attribute)
*/
void getInputFaceVertex(int _face, int _corner, int* _out);
void getInputFaceVertex(int _face, int _corner, int* _out) const;
int getInputIndex(const int _face, const int _corner, const int _attrId) const;
......@@ -424,10 +540,9 @@ private:
int numFaces_,
numIndices_;
bool interleavedInput_; // is input vertex buffer interleaved
std::vector<int> faceStart_; // start position in buf for each face
std::vector<short> faceSize_; // face size, copy of faceInput_->getFaceSize() for better performance
int maxFaceCorners_; // max(faceCorners_)
size_t maxFaceCorners_; // max(faceCorners_)
std::vector<int> faceGroupIDs_; // group id for each face (optional input)
int curFaceInputPos_; // current # indices set by user
......@@ -556,26 +671,46 @@ private:
int getInputIndexOffset(const int _face, const int _corner, const bool _rotation = true) const;
/// build() preparation
void prepareData();
// make sure each face has one vertex id without any references by neighboring faces
// split vertices when necessary
void forceUnsharedFaceVertex();
// convert n-poly -> tris (triangle fans)
void triangulate();
// sort input faces by group ids
void sortFacesByGroup();
// v-cache optimization + vertex reorder
void optimize();
// create vertex mapping: input id <-> final buffer id
void createVertexMap();
// create face mapping: input id <-> final tri id
void createFaceMap();
// debugging tools
public:
// debugging tools
/// dump mesh info to text file
void dbgdump(const char* _filename) const;
/// dump mesh in wavefront obj format
void dbgdumpObj(const char* _filename) const;
/// dump adjacency list to text file
void dbgdumpAdjList(const char* _filename) const;
int getMemoryUsage() const;
/// return memory consumption in bytes
size_t getMemoryUsage() const;
/// check for errors in input data
std::string checkInputData() const;
};
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment