ADD Vertex utility class to simplify conversion from and to interleaved vertices.
Refactor JoinVerticesProcess to utilize the new utility. ADD basic operators for aiColor4D, move to dedicated header and implementation file. ADD some utility functions to SpatialSort. ADD my existing Catmull-Clark implementation to Assimp for all model formats with support for subdivision surfaces. Slightly WIP, likely to produce errors on non-closed meshes. Currently only implemented in the AC3D loader. Switch to byteswap intrinsics instead of inline assembly (bswap). Currently MSVC only. FIX phong shading in assimp_view. VertexTriangleAdjacency class now also works on arbitrary polygons - UNTESTED, tbd. git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@532 67173fc5-114c-0410-ac8e-9d2fd5bffc1fpull/1/head
parent
ce29aca94e
commit
2e3fee99f0
|
@ -50,7 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "ACLoader.h"
|
||||
#include "ParsingUtils.h"
|
||||
#include "fast_atof.h"
|
||||
//#include "Subdivision.h"
|
||||
#include "Subdivision.h"
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
|
@ -251,6 +251,11 @@ void AC3DImporter::LoadObjectSection(std::vector<Object>& objects)
|
|||
SkipSpaces(&buffer);
|
||||
obj.subDiv = strtol10(buffer,&buffer);
|
||||
}
|
||||
else if (TokenMatch(buffer,"crease",6))
|
||||
{
|
||||
SkipSpaces(&buffer);
|
||||
obj.crease = fast_atof(buffer);
|
||||
}
|
||||
else if (TokenMatch(buffer,"numvert",7))
|
||||
{
|
||||
SkipSpaces(&buffer);
|
||||
|
@ -529,6 +534,7 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object,
|
|||
}
|
||||
unsigned int* pip = node->mMeshes = new unsigned int[node->mNumMeshes];
|
||||
unsigned int mat = 0;
|
||||
const size_t oldm = meshes.size();
|
||||
for (MatTable::const_iterator cit = needMat.begin(), cend = needMat.end();
|
||||
cit != cend; ++cit, ++mat)
|
||||
{
|
||||
|
@ -621,6 +627,7 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object,
|
|||
++uv;
|
||||
}
|
||||
|
||||
|
||||
if (0x1 == type && tmp-1 == m)
|
||||
{
|
||||
// if this is a closed line repeat its beginning now
|
||||
|
@ -641,20 +648,26 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object,
|
|||
}
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
// Now apply catmull clark subdivision if necessary. However, this is
|
||||
// not *absolutely* correct: it might be we split a mesh up into
|
||||
// multiple sub meshes, one for each material. AC3D doesn't do that
|
||||
// in its subdivision implementation, so our output *could* look
|
||||
// different in some cases.
|
||||
|
||||
if (object.subDiv)
|
||||
{
|
||||
Subdivider* div = Subdivider::Create(Subdivider::CATMULL_CLARKE);
|
||||
div->Subdivide(mesh,object.subDiv);
|
||||
delete div;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Now apply catmull clark subdivision if necessary. We split meshes into
|
||||
// materials which is not done by AC3D during smoothing, so we need to
|
||||
// collect all meshes using the same material group.
|
||||
if (object.subDiv) {
|
||||
if (configEvalSubdivision) {
|
||||
boost::scoped_ptr<Subdivider> div(Subdivider::Create(Subdivider::CATMULL_CLARKE));
|
||||
DefaultLogger::get()->info("AC3D: Evaluating subdivision surface: "+object.name);
|
||||
|
||||
std::vector<aiMesh*> cpy(meshes.size()-oldm,NULL);
|
||||
div->Subdivide(&meshes[oldm],cpy.size(),&cpy.front(),object.subDiv,true);
|
||||
std::copy(cpy.begin(),cpy.end(),meshes.begin()+oldm);
|
||||
|
||||
// previous meshes are deleted vy Subdivide().
|
||||
}
|
||||
else {
|
||||
DefaultLogger::get()->info("AC3D: Letting the subdivision surface untouched due to my configuration: "
|
||||
+object.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -713,6 +726,7 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object,
|
|||
void AC3DImporter::SetupProperties(const Importer* pImp)
|
||||
{
|
||||
configSplitBFCull = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_AC_SEPARATE_BFCULL,1) ? true : false;
|
||||
configEvalSubdivision = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_AC_EVAL_SUBDIVISION,1) ? true : false;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
|
|
@ -169,6 +169,9 @@ protected:
|
|||
// number of subdivisions to be performed on the
|
||||
// imported data
|
||||
unsigned int subDiv;
|
||||
|
||||
// max angle limit for smoothing
|
||||
float crease;
|
||||
};
|
||||
|
||||
|
||||
|
@ -185,63 +188,53 @@ protected:
|
|||
|
||||
// -------------------------------------------------------------------
|
||||
/** Called by Importer::GetExtensionList() for each loaded importer.
|
||||
* See BaseImporter::GetExtensionList() for details
|
||||
*/
|
||||
* See BaseImporter::GetExtensionList() for details */
|
||||
void GetExtensionList(std::string& append);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Imports the given file into the given scene structure.
|
||||
* See BaseImporter::InternReadFile() for details
|
||||
*/
|
||||
* See BaseImporter::InternReadFile() for details*/
|
||||
void InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||
IOSystem* pIOHandler);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Called prior to ReadFile().
|
||||
* The function is a request to the importer to update its configuration
|
||||
* basing on the Importer's configuration property list.
|
||||
*/
|
||||
* basing on the Importer's configuration property list.*/
|
||||
void SetupProperties(const Importer* pImp);
|
||||
|
||||
private:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Get the next line from the file.
|
||||
* @return false if the end of the file was reached
|
||||
*/
|
||||
* @return false if the end of the file was reached*/
|
||||
bool GetNextLine();
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Load the object section. This method is called recursively to
|
||||
* load subobjects, the method returns after a 'kids 0' was
|
||||
* encountered.
|
||||
* @objects List of output objects
|
||||
*/
|
||||
* @objects List of output objects*/
|
||||
void LoadObjectSection(std::vector<Object>& objects);
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Convert all objects into meshes and nodes.
|
||||
* @param object Current object to work on
|
||||
* @param meshes Pointer to the list of output meshes
|
||||
* @param outMaterials List of output materials
|
||||
* @param materials Material list
|
||||
* @param Scenegraph node for the object
|
||||
*/
|
||||
* @param Scenegraph node for the object */
|
||||
aiNode* ConvertObjectSection(Object& object,
|
||||
std::vector<aiMesh*>& meshes,
|
||||
std::vector<MaterialHelper*>& outMaterials,
|
||||
const std::vector<Material>& materials,
|
||||
aiNode* parent = NULL);
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Convert a material
|
||||
* @param object Current object
|
||||
* @param matSrc Source material description
|
||||
* @param matDest Destination material to be filled
|
||||
*/
|
||||
* @param matDest Destination material to be filled */
|
||||
void ConvertMaterial(const Object& object,
|
||||
const Material& matSrc,
|
||||
MaterialHelper& matDest);
|
||||
|
@ -257,6 +250,10 @@ private:
|
|||
// their bf cull flags set are separated.
|
||||
bool configSplitBFCull;
|
||||
|
||||
// Configuration switch: subdivision surfaces are only
|
||||
// evaluated if the value is true.
|
||||
bool configEvalSubdivision;
|
||||
|
||||
// counts how many objects we have in the tree.
|
||||
// basing on this information we can find a
|
||||
// good estimate how many meshes we'll have in the final scene.
|
||||
|
|
|
@ -46,92 +46,110 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "../include/aiAssert.h"
|
||||
#include "../include/aiTypes.h"
|
||||
|
||||
namespace Assimp
|
||||
{
|
||||
#if _MSC_VER >= 1400
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** \brief Defines some useful byte order swap routines.
|
||||
namespace Assimp {
|
||||
// --------------------------------------------------------------------------------------
|
||||
/** Defines some useful byte order swap routines.
|
||||
*
|
||||
* This can e.g. be used for the conversion from and to littel and big endian.
|
||||
* This is required by some loaders since some model formats
|
||||
*/
|
||||
* This is required to read big-endian model formats on little-endian machines,
|
||||
* and vice versa. Direct use of this class is DEPRECATED. Use #StreamReader instead. */
|
||||
// --------------------------------------------------------------------------------------
|
||||
class ByteSwap
|
||||
{
|
||||
ByteSwap() {}
|
||||
|
||||
public:
|
||||
//! Swap the byte oder of 2 byte of data
|
||||
//! \param szOut Buffer to be swapped
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
/** Swap two bytes of data
|
||||
* @param[inout] _szOut A void* to save the reintcasts for the caller. */
|
||||
static inline void Swap2(void* _szOut)
|
||||
{
|
||||
ai_assert(NULL != _szOut);
|
||||
int8_t* szOut = (int8_t*)_szOut;
|
||||
ai_assert(_szOut);
|
||||
|
||||
#if _MSC_VER >= 1400
|
||||
uint16_t* const szOut = reinterpret_cast<uint16_t*>(_szOut);
|
||||
*szOut = _byteswap_ushort(*szOut);
|
||||
#else
|
||||
uint8_t* const szOut = reinterpret_cast<uint8_t*>(_szOut);
|
||||
std::swap(szOut[0],szOut[1]);
|
||||
#endif
|
||||
}
|
||||
|
||||
//! Swap the byte oder of 4 byte of data
|
||||
//! \param szOut Buffer to be swapped
|
||||
// ----------------------------------------------------------------------
|
||||
/** Swap four bytes of data
|
||||
* @param[inout] _szOut A void* to save the reintcasts for the caller. */
|
||||
static inline void Swap4(void* _szOut)
|
||||
{
|
||||
ai_assert(NULL != _szOut);
|
||||
ai_assert(_szOut);
|
||||
|
||||
#if _MSC_VER >= 1400 && (defined _M_X86)
|
||||
__asm
|
||||
{
|
||||
mov edi, _szOut
|
||||
mov eax, dword_ptr[edi]
|
||||
bswap eax
|
||||
mov dword_ptr[edi], eax
|
||||
};
|
||||
#if _MSC_VER >= 1400
|
||||
uint32_t* const szOut = reinterpret_cast<uint32_t*>(_szOut);
|
||||
*szOut = _byteswap_ulong(*szOut);
|
||||
#else
|
||||
int8_t* szOut = (int8_t*)_szOut;
|
||||
uint8_t* const szOut = reinterpret_cast<uint8_t*>(_szOut);
|
||||
std::swap(szOut[0],szOut[3]);
|
||||
std::swap(szOut[1],szOut[2]);
|
||||
#endif
|
||||
}
|
||||
|
||||
//! Swap the byte oder of 8 byte of data
|
||||
//! \param szOut Buffer to be swapped
|
||||
// ----------------------------------------------------------------------
|
||||
/** Swap eight bytes of data
|
||||
* @param[inout] _szOut A void* to save the reintcasts for the caller. */
|
||||
static inline void Swap8(void* _szOut)
|
||||
{
|
||||
ai_assert(NULL != _szOut);
|
||||
int8_t* szOut = (int8_t*)_szOut;
|
||||
ai_assert(_szOut);
|
||||
|
||||
#if _MSC_VER >= 1400
|
||||
uint64_t* const szOut = reinterpret_cast<uint64_t*>(_szOut);
|
||||
*szOut = _byteswap_uint64(*szOut);
|
||||
#else
|
||||
uint8_t* const szOut = reinterpret_cast<uint8_t*>(_szOut);
|
||||
std::swap(szOut[0],szOut[7]);
|
||||
std::swap(szOut[1],szOut[6]);
|
||||
std::swap(szOut[2],szOut[5]);
|
||||
std::swap(szOut[3],szOut[4]);
|
||||
#endif
|
||||
}
|
||||
|
||||
//! Swap a single precision float
|
||||
//! \param fOut Float value to be swapped
|
||||
// ----------------------------------------------------------------------
|
||||
/** ByteSwap a float. Not a joke.
|
||||
* @param[inout] fOut ehm. .. */
|
||||
static inline void Swap(float* fOut)
|
||||
{
|
||||
Swap4(fOut);
|
||||
}
|
||||
|
||||
//! Swap a double precision float
|
||||
//! \param fOut Double value to be swapped
|
||||
// ----------------------------------------------------------------------
|
||||
/** ByteSwap a double. Not a joke.
|
||||
* @param[inout] fOut ehm. .. */
|
||||
static inline void Swap(double* fOut)
|
||||
{
|
||||
Swap8(fOut);
|
||||
}
|
||||
|
||||
//! Swap a 16 bit integer
|
||||
//! \param fOut Integer to be swapped
|
||||
// ----------------------------------------------------------------------
|
||||
/** ByteSwap an int16t. Not a joke.
|
||||
* @param[inout] fOut ehm. .. */
|
||||
static inline void Swap(int16_t* fOut)
|
||||
{
|
||||
Swap2(fOut);
|
||||
}
|
||||
|
||||
//! Swap a 32 bit integer
|
||||
//! \param fOut Integer to be swapped
|
||||
// ----------------------------------------------------------------------
|
||||
/** ByteSwap an int32t. Not a joke.
|
||||
* @param[inout] fOut ehm. .. */
|
||||
static inline void Swap(int32_t* fOut)
|
||||
{
|
||||
Swap4(fOut);
|
||||
}
|
||||
|
||||
//! Swap a 64 bit integer
|
||||
//! \param fOut Integer to be swapped
|
||||
// ----------------------------------------------------------------------
|
||||
/** ByteSwap an int64t. Not a joke.
|
||||
* @param[inout] fOut ehm. .. */
|
||||
static inline void Swap(int64_t* fOut)
|
||||
{
|
||||
Swap8(fOut);
|
||||
|
@ -140,7 +158,10 @@ public:
|
|||
|
||||
} // Namespace Assimp
|
||||
|
||||
// byteswap macros for BigEndian/LittleEndian support
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// ByteSwap macros for BigEndian/LittleEndian support
|
||||
// --------------------------------------------------------------------------------------
|
||||
#if (defined AI_BUILD_BIG_ENDIAN)
|
||||
# define AI_LSWAP2(p)
|
||||
# define AI_LSWAP4(p)
|
||||
|
|
|
@ -52,6 +52,9 @@ SOURCE_GROUP( Common FILES
|
|||
TargetAnimation.h
|
||||
RemoveComments.cpp
|
||||
RemoveComments.h
|
||||
Subdivision.cpp
|
||||
Subdivision.h
|
||||
Vertex.h
|
||||
)
|
||||
|
||||
SOURCE_GROUP( 3DS FILES
|
||||
|
@ -580,6 +583,9 @@ ADD_LIBRARY( assimp SHARED
|
|||
../contrib/zlib/zutil.c
|
||||
../contrib/zlib/zutil.h
|
||||
../contrib/ConvertUTF/ConvertUTF.c
|
||||
Subdivision.cpp
|
||||
Subdivision.h
|
||||
Vertex.h
|
||||
)
|
||||
ADD_DEFINITIONS(-DASSIMP_BUILD_DLL_EXPORT)
|
||||
|
||||
|
|
|
@ -48,22 +48,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include "JoinVerticesProcess.h"
|
||||
#include "ProcessHelper.h"
|
||||
#include "Vertex.h"
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
namespace Assimp
|
||||
{
|
||||
// Data structure to keep a vertex in an interlaced format
|
||||
struct Vertex
|
||||
{
|
||||
aiVector3D mPosition;
|
||||
aiVector3D mNormal;
|
||||
aiVector3D mTangent, mBitangent;
|
||||
aiColor4D mColors [AI_MAX_NUMBER_OF_COLOR_SETS];
|
||||
aiVector3D mTexCoords [AI_MAX_NUMBER_OF_TEXTURECOORDS];
|
||||
};
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
JoinVerticesProcess::JoinVerticesProcess()
|
||||
|
@ -131,8 +118,9 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
|
|||
BOOST_STATIC_ASSERT( AI_MAX_NUMBER_OF_TEXTURECOORDS == 4);
|
||||
|
||||
// Return early if we don't have any positions
|
||||
if (!pMesh->HasPositions() || !pMesh->HasFaces())
|
||||
if (!pMesh->HasPositions() || !pMesh->HasFaces()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// We'll never have more vertices afterwards.
|
||||
std::vector<Vertex> uniqueVertices;
|
||||
|
@ -143,34 +131,39 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
|
|||
// for each vertex whether it was replaced by an existing unique vertex (true) or a new vertex was created for it (false)
|
||||
std::vector<bool> isVertexUnique( pMesh->mNumVertices, false);
|
||||
|
||||
// A little helper to find locally close vertices faster
|
||||
// FIX: check whether we can reuse the SpatialSort of a previous step
|
||||
// A little helper to find locally close vertices faster.
|
||||
// Try to reuse the lookup table from the last step.
|
||||
const static float epsilon = 1e-5f;
|
||||
float posEpsilonSqr;
|
||||
SpatialSort* vertexFinder = NULL;
|
||||
SpatialSort _vertexFinder;
|
||||
|
||||
typedef std::pair<SpatialSort,float> SpatPair;
|
||||
if (shared) {
|
||||
std::vector<std::pair<SpatialSort,float> >* avf;
|
||||
std::vector<SpatPair >* avf;
|
||||
shared->GetProperty(AI_SPP_SPATIAL_SORT,avf);
|
||||
if (avf) {
|
||||
std::pair<SpatialSort,float>& blubb = avf->operator [] (meshIndex);
|
||||
vertexFinder = &blubb.first;posEpsilonSqr = blubb.second;
|
||||
SpatPair& blubb = (*avf)[meshIndex];
|
||||
vertexFinder = &blubb.first;
|
||||
posEpsilonSqr = blubb.second;
|
||||
}
|
||||
}
|
||||
if (!vertexFinder) {
|
||||
// bad, need to compute it.
|
||||
_vertexFinder.Fill(pMesh->mVertices, pMesh->mNumVertices, sizeof( aiVector3D));
|
||||
vertexFinder = &_vertexFinder;
|
||||
posEpsilonSqr = ComputePositionEpsilon(pMesh);
|
||||
}
|
||||
|
||||
// squared because we check against squared length of the vector difference
|
||||
// Squared because we check against squared length of the vector difference
|
||||
static const float squareEpsilon = epsilon * epsilon;
|
||||
|
||||
// again, better waste some bytes than a realloc ...
|
||||
// Again, better waste some bytes than a realloc ...
|
||||
std::vector<unsigned int> verticesFound;
|
||||
verticesFound.reserve(10);
|
||||
|
||||
// run an optimized code path if we don't have multiple UVs or vertex colors
|
||||
// Run an optimized code path if we don't have multiple UVs or vertex colors.
|
||||
// This should yield false in more than 99% of all imports ...
|
||||
const bool complex = (
|
||||
pMesh->mTextureCoords[1] ||
|
||||
pMesh->mTextureCoords[2] ||
|
||||
|
@ -181,49 +174,22 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
|
|||
pMesh->mColors[3] );
|
||||
|
||||
// Now check each vertex if it brings something new to the table
|
||||
for( unsigned int a = 0; a < pMesh->mNumVertices; a++)
|
||||
{
|
||||
for( unsigned int a = 0; a < pMesh->mNumVertices; a++) {
|
||||
// collect the vertex data
|
||||
Vertex v;
|
||||
v.mPosition = pMesh->mVertices[a];
|
||||
|
||||
if (pMesh->mNormals)
|
||||
v.mNormal = pMesh->mNormals[a];
|
||||
if (pMesh->mTangents)
|
||||
v.mTangent = pMesh->mTangents[a];
|
||||
if (pMesh->mBitangents)
|
||||
v.mBitangent = pMesh->mBitangents[a];
|
||||
|
||||
if (pMesh->mColors[0]) { // manually unrolled here
|
||||
v.mColors[0] = pMesh->mColors[0][a];
|
||||
if (pMesh->mColors[1]) {
|
||||
v.mColors[1] = pMesh->mColors[1][a];
|
||||
if (pMesh->mColors[2]) {
|
||||
v.mColors[2] = pMesh->mColors[2][a];
|
||||
if (pMesh->mColors[3]) {
|
||||
v.mColors[3] = pMesh->mColors[3][a];
|
||||
}}}}
|
||||
if (pMesh->mTextureCoords[0]) { // manually unrolled here
|
||||
v.mTexCoords[0] = pMesh->mTextureCoords[0][a];
|
||||
if (pMesh->mTextureCoords[1]) {
|
||||
v.mTexCoords[1] = pMesh->mTextureCoords[1][a];
|
||||
if (pMesh->mTextureCoords[2]) {
|
||||
v.mTexCoords[2] = pMesh->mTextureCoords[2][a];
|
||||
if (pMesh->mTextureCoords[3]) {
|
||||
v.mTexCoords[3] = pMesh->mTextureCoords[3][a];
|
||||
}}}}
|
||||
Vertex v(pMesh,a);
|
||||
|
||||
// collect all vertices that are close enough to the given position
|
||||
vertexFinder->FindPositions( v.mPosition, posEpsilonSqr, verticesFound);
|
||||
|
||||
vertexFinder->FindPositions( v.position, posEpsilonSqr, verticesFound);
|
||||
unsigned int matchIndex = 0xffffffff;
|
||||
|
||||
// check all unique vertices close to the position if this vertex is already present among them
|
||||
for( unsigned int b = 0; b < verticesFound.size(); b++)
|
||||
{
|
||||
for( unsigned int b = 0; b < verticesFound.size(); b++) {
|
||||
|
||||
const unsigned int vidx = verticesFound[b];
|
||||
const unsigned int uidx = replaceIndex[ vidx];
|
||||
if( uidx == 0xffffffff || !isVertexUnique[ vidx])
|
||||
if( uidx == 0xffffffff || !isVertexUnique[ vidx]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const Vertex& uv = uniqueVertices[ uidx];
|
||||
// Position mismatch is impossible - the vertex finder already discarded all non-matching positions
|
||||
|
@ -231,36 +197,35 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
|
|||
// We just test the other attributes even if they're not present in the mesh.
|
||||
// In this case they're initialized to 0 so the comparision succeeds.
|
||||
// By this method the non-present attributes are effectively ignored in the comparision.
|
||||
if( (uv.mNormal - v.mNormal).SquareLength() > squareEpsilon)
|
||||
if( (uv.normal - v.normal).SquareLength() > squareEpsilon)
|
||||
continue;
|
||||
if( (uv.mTangent - v.mTangent).SquareLength() > squareEpsilon)
|
||||
if( (uv.texcoords[0] - v.texcoords[0]).SquareLength() > squareEpsilon)
|
||||
continue;
|
||||
if( (uv.mBitangent - v.mBitangent).SquareLength() > squareEpsilon)
|
||||
if( (uv.tangent - v.tangent).SquareLength() > squareEpsilon)
|
||||
continue;
|
||||
|
||||
if( (uv.mTexCoords[0] - v.mTexCoords[0]).SquareLength() > squareEpsilon)
|
||||
if( (uv.bitangent - v.bitangent).SquareLength() > squareEpsilon)
|
||||
continue;
|
||||
|
||||
// Usually we won't have vertex colors or multiple UVs, so we can skip from here
|
||||
// Actually this increases runtime performance slightly.
|
||||
if (complex)
|
||||
{
|
||||
// Actually this increases runtime performance slightly, at least if branch
|
||||
// prediction is on our side.
|
||||
if (complex){
|
||||
// manually unrolled because continue wouldn't work as desired in an inner loop
|
||||
if( GetColorDifference( uv.mColors[0], v.mColors[0]) > squareEpsilon)
|
||||
if( GetColorDifference( uv.colors[0], v.colors[0]) > squareEpsilon)
|
||||
continue;
|
||||
if( GetColorDifference( uv.mColors[1], v.mColors[1]) > squareEpsilon)
|
||||
if( GetColorDifference( uv.colors[1], v.colors[1]) > squareEpsilon)
|
||||
continue;
|
||||
if( GetColorDifference( uv.mColors[2], v.mColors[2]) > squareEpsilon)
|
||||
if( GetColorDifference( uv.colors[2], v.colors[2]) > squareEpsilon)
|
||||
continue;
|
||||
if( GetColorDifference( uv.mColors[3], v.mColors[3]) > squareEpsilon)
|
||||
if( GetColorDifference( uv.colors[3], v.colors[3]) > squareEpsilon)
|
||||
continue;
|
||||
|
||||
// texture coord matching manually unrolled as well
|
||||
if( (uv.mTexCoords[1] - v.mTexCoords[1]).SquareLength() > squareEpsilon)
|
||||
if( (uv.texcoords[1] - v.texcoords[1]).SquareLength() > squareEpsilon)
|
||||
continue;
|
||||
if( (uv.mTexCoords[2] - v.mTexCoords[2]).SquareLength() > squareEpsilon)
|
||||
if( (uv.texcoords[2] - v.texcoords[2]).SquareLength() > squareEpsilon)
|
||||
continue;
|
||||
if( (uv.mTexCoords[3] - v.mTexCoords[3]).SquareLength() > squareEpsilon)
|
||||
if( (uv.texcoords[3] - v.texcoords[3]).SquareLength() > squareEpsilon)
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -285,8 +250,7 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
|
|||
}
|
||||
}
|
||||
|
||||
if (!DefaultLogger::isNullLogger() && DefaultLogger::get()->getLogSeverity() == Logger::VERBOSE)
|
||||
{
|
||||
if (!DefaultLogger::isNullLogger() && DefaultLogger::get()->getLogSeverity() == Logger::VERBOSE) {
|
||||
char szBuff[128]; // should be sufficiently large in every case
|
||||
::sprintf(szBuff,"Mesh %i | Verts in: %i out: %i | ~%.1f%%",
|
||||
meshIndex,
|
||||
|
@ -299,57 +263,62 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
|
|||
// replace vertex data with the unique data sets
|
||||
pMesh->mNumVertices = (unsigned int)uniqueVertices.size();
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// NOTE - we're *not* calling Vertex::SortBack() because it would check for
|
||||
// presence of every single vertex component once PER VERTEX. And our CPU
|
||||
// dislikes branches, even if they're easily predictable.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Position
|
||||
delete [] pMesh->mVertices;
|
||||
pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
|
||||
for( unsigned int a = 0; a < pMesh->mNumVertices; a++)
|
||||
pMesh->mVertices[a] = uniqueVertices[a].mPosition;
|
||||
pMesh->mVertices[a] = uniqueVertices[a].position;
|
||||
|
||||
// Normals, if present
|
||||
if( pMesh->mNormals)
|
||||
{
|
||||
delete [] pMesh->mNormals;
|
||||
pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
|
||||
for( unsigned int a = 0; a < pMesh->mNumVertices; a++)
|
||||
pMesh->mNormals[a] = uniqueVertices[a].mNormal;
|
||||
for( unsigned int a = 0; a < pMesh->mNumVertices; a++) {
|
||||
pMesh->mNormals[a] = uniqueVertices[a].normal;
|
||||
}
|
||||
}
|
||||
// Tangents, if present
|
||||
if( pMesh->mTangents)
|
||||
{
|
||||
delete [] pMesh->mTangents;
|
||||
pMesh->mTangents = new aiVector3D[pMesh->mNumVertices];
|
||||
for( unsigned int a = 0; a < pMesh->mNumVertices; a++)
|
||||
pMesh->mTangents[a] = uniqueVertices[a].mTangent;
|
||||
for( unsigned int a = 0; a < pMesh->mNumVertices; a++) {
|
||||
pMesh->mTangents[a] = uniqueVertices[a].tangent;
|
||||
}
|
||||
}
|
||||
// Bitangents as well
|
||||
if( pMesh->mBitangents)
|
||||
{
|
||||
delete [] pMesh->mBitangents;
|
||||
pMesh->mBitangents = new aiVector3D[pMesh->mNumVertices];
|
||||
for( unsigned int a = 0; a < pMesh->mNumVertices; a++)
|
||||
pMesh->mBitangents[a] = uniqueVertices[a].mBitangent;
|
||||
for( unsigned int a = 0; a < pMesh->mNumVertices; a++) {
|
||||
pMesh->mBitangents[a] = uniqueVertices[a].bitangent;
|
||||
}
|
||||
}
|
||||
// Vertex colors
|
||||
for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; a++)
|
||||
for( unsigned int a = 0; pMesh->HasVertexColors(a); a++)
|
||||
{
|
||||
if( !pMesh->mColors[a])
|
||||
break;
|
||||
|
||||
delete [] pMesh->mColors[a];
|
||||
pMesh->mColors[a] = new aiColor4D[pMesh->mNumVertices];
|
||||
for( unsigned int b = 0; b < pMesh->mNumVertices; b++)
|
||||
pMesh->mColors[a][b] = uniqueVertices[b].mColors[a];
|
||||
for( unsigned int b = 0; b < pMesh->mNumVertices; b++) {
|
||||
pMesh->mColors[a][b] = uniqueVertices[b].colors[a];
|
||||
}
|
||||
}
|
||||
// Texture coords
|
||||
for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++)
|
||||
for( unsigned int a = 0; pMesh->HasTextureCoords(a); a++)
|
||||
{
|
||||
if( !pMesh->mTextureCoords[a])
|
||||
break;
|
||||
|
||||
delete [] pMesh->mTextureCoords[a];
|
||||
pMesh->mTextureCoords[a] = new aiVector3D[pMesh->mNumVertices];
|
||||
for( unsigned int b = 0; b < pMesh->mNumVertices; b++)
|
||||
pMesh->mTextureCoords[a][b] = uniqueVertices[b].mTexCoords[a];
|
||||
for( unsigned int b = 0; b < pMesh->mNumVertices; b++) {
|
||||
pMesh->mTextureCoords[a][b] = uniqueVertices[b].texcoords[a];
|
||||
}
|
||||
}
|
||||
|
||||
// adjust the indices in all faces
|
||||
|
@ -407,8 +376,9 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
|
|||
*/
|
||||
delete bone;
|
||||
--pMesh->mNumBones;
|
||||
for (unsigned int n = a; n < pMesh->mNumBones; ++n)
|
||||
for (unsigned int n = a; n < pMesh->mNumBones; ++n) {
|
||||
pMesh->mBones[n] = pMesh->mBones[n+1];
|
||||
}
|
||||
|
||||
--a;
|
||||
DefaultLogger::get()->warn("Removing bone -> no weights remaining");
|
||||
|
|
|
@ -366,7 +366,7 @@ inline void FindMeshCenterTransformed (aiMesh* mesh, aiVector3D& out,
|
|||
// Compute a good epsilon value for position comparisons on a mesh
|
||||
inline float ComputePositionEpsilon(const aiMesh* pMesh)
|
||||
{
|
||||
const float epsilon = 1e-5f;
|
||||
const float epsilon = 1e-4f;
|
||||
|
||||
// calculate the position bounds so we have a reliable epsilon to check position differences against
|
||||
aiVector3D minVec, maxVec;
|
||||
|
@ -374,6 +374,26 @@ inline float ComputePositionEpsilon(const aiMesh* pMesh)
|
|||
return (maxVec - minVec).Length() * epsilon;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// Compute a good epsilon value for position comparisons on a array of meshes
|
||||
inline float ComputePositionEpsilon(const aiMesh* const* pMeshes, size_t num)
|
||||
{
|
||||
const float epsilon = 1e-4f;
|
||||
|
||||
// calculate the position bounds so we have a reliable epsilon to check position differences against
|
||||
aiVector3D minVec, maxVec, mi, ma;
|
||||
MinMaxChooser<aiVector3D>()(minVec,maxVec);
|
||||
|
||||
for (size_t a = 0; a < num; ++a) {
|
||||
const aiMesh* pMesh = pMeshes[a];
|
||||
ArrayBounds(pMesh->mVertices,pMesh->mNumVertices,mi,ma);
|
||||
|
||||
minVec = std::min(minVec,mi);
|
||||
maxVec = std::max(maxVec,ma);
|
||||
}
|
||||
return (maxVec - minVec).Length() * epsilon;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// Compute an unique value for the vertex format of a mesh
|
||||
inline unsigned int GetMeshVFormatUnique(aiMesh* pcMesh)
|
||||
|
|
|
@ -50,10 +50,22 @@ using namespace Assimp;
|
|||
// Constructs a spatially sorted representation from the given position array.
|
||||
SpatialSort::SpatialSort( const aiVector3D* pPositions, unsigned int pNumPositions,
|
||||
unsigned int pElementOffset)
|
||||
|
||||
// define the reference plane. We choose some arbitrary vector away from all basic axises
|
||||
// in the hope that no model spreads all its vertices along this plane.
|
||||
: mPlaneNormal(0.8523f, 0.34321f, 0.5736f)
|
||||
{
|
||||
mPlaneNormal.Normalize();
|
||||
Fill(pPositions,pNumPositions,pElementOffset);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
SpatialSort :: SpatialSort()
|
||||
: mPlaneNormal(0.8523f, 0.34321f, 0.5736f)
|
||||
{
|
||||
mPlaneNormal.Normalize();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor
|
||||
SpatialSort::~SpatialSort()
|
||||
|
@ -63,15 +75,27 @@ SpatialSort::~SpatialSort()
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void SpatialSort::Fill( const aiVector3D* pPositions, unsigned int pNumPositions,
|
||||
unsigned int pElementOffset)
|
||||
unsigned int pElementOffset,
|
||||
bool pFinalize /*= true */)
|
||||
{
|
||||
// define the reference plane. We choose some arbitrary vector away from all basic axises
|
||||
// in the hope that no model spreads all its vertices along this plane.
|
||||
mPlaneNormal.Set( 0.8523f, 0.34321f, 0.5736f);
|
||||
mPlaneNormal.Normalize();
|
||||
mPositions.clear();
|
||||
Append(pPositions,pNumPositions,pElementOffset,pFinalize);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void SpatialSort :: Finalize()
|
||||
{
|
||||
std::sort( mPositions.begin(), mPositions.end());
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void SpatialSort::Append( const aiVector3D* pPositions, unsigned int pNumPositions,
|
||||
unsigned int pElementOffset,
|
||||
bool pFinalize /*= true */)
|
||||
{
|
||||
// store references to all given positions along with their distance to the reference plane
|
||||
mPositions.reserve( pNumPositions);
|
||||
const size_t initial = mPositions.size();
|
||||
mPositions.reserve(initial + (pFinalize?pNumPositions:pNumPositions*2));
|
||||
for( unsigned int a = 0; a < pNumPositions; a++)
|
||||
{
|
||||
const char* tempPointer = reinterpret_cast<const char*> (pPositions);
|
||||
|
@ -79,16 +103,19 @@ void SpatialSort::Fill( const aiVector3D* pPositions, unsigned int pNumPositions
|
|||
|
||||
// store position by index and distance
|
||||
float distance = *vec * mPlaneNormal;
|
||||
mPositions.push_back( Entry( a, *vec, distance));
|
||||
mPositions.push_back( Entry( a+initial, *vec, distance));
|
||||
}
|
||||
|
||||
if (pFinalize) {
|
||||
// now sort the array ascending by distance.
|
||||
std::sort( mPositions.begin(), mPositions.end());
|
||||
Finalize();
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns an iterator for all positions close to the given position.
|
||||
void SpatialSort::FindPositions( const aiVector3D& pPosition, float pRadius, std::vector<unsigned int>& poResults) const
|
||||
void SpatialSort::FindPositions( const aiVector3D& pPosition,
|
||||
float pRadius, std::vector<unsigned int>& poResults) const
|
||||
{
|
||||
const float dist = pPosition * mPlaneNormal;
|
||||
const float minDist = dist - pRadius, maxDist = dist + pRadius;
|
||||
|
@ -141,4 +168,36 @@ void SpatialSort::FindPositions( const aiVector3D& pPosition, float pRadius, std
|
|||
// that's it
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
unsigned int SpatialSort::GenerateMappingTable(std::vector<unsigned int>& fill,float pRadius) const
|
||||
{
|
||||
fill.resize(mPositions.size(),0xffffffff);
|
||||
float dist, maxDist;
|
||||
|
||||
unsigned int t=0;
|
||||
const float pSquared = pRadius*pRadius;
|
||||
for (size_t i = 0; i < mPositions.size();) {
|
||||
dist = mPositions[i].mPosition * mPlaneNormal;
|
||||
maxDist = dist + pRadius;
|
||||
|
||||
fill[mPositions[i].mIndex] = t;
|
||||
const aiVector3D& oldpos = mPositions[i].mPosition;
|
||||
for (++i; i < fill.size() && mPositions[i].mDistance < maxDist
|
||||
&& (mPositions[i].mPosition - oldpos).SquareLength() < pSquared; ++i)
|
||||
{
|
||||
fill[mPositions[i].mIndex] = t;
|
||||
}
|
||||
++t;
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
||||
// debug invariant: mPositions[i].mIndex values must range from 0 to mPositions.size()-1
|
||||
for (size_t i = 0; i < fill.size(); ++i) {
|
||||
ai_assert(fill[i]<mPositions.size());
|
||||
}
|
||||
|
||||
#endif
|
||||
return t;
|
||||
}
|
||||
|
||||
|
|
|
@ -54,48 +54,83 @@ namespace Assimp
|
|||
* by their indices and sorts them by their distance to an arbitrary chosen plane.
|
||||
* You can then query the instance for all vertices close to a given position in an average O(log n)
|
||||
* time, with O(n) worst case complexity when all vertices lay on the plane. The plane is chosen
|
||||
* so that it avoids common planes in usual data sets.
|
||||
*/
|
||||
* so that it avoids common planes in usual data sets. */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
class ASSIMP_API SpatialSort
|
||||
{
|
||||
public:
|
||||
|
||||
SpatialSort() {/* This is unintialized. This is evil. This is OK. */}
|
||||
SpatialSort();
|
||||
|
||||
// ------------------------------------------------------------------------------------
|
||||
/** Constructs a spatially sorted representation from the given position array.
|
||||
* Supply the positions in its layout in memory, the class will only refer to them
|
||||
* by index.
|
||||
* @param pPositions Pointer to the first position vector of the array.
|
||||
* @param pNumPositions Number of vectors to expect in that array.
|
||||
* @param pElementOffset Offset in bytes from the beginning of one vector in memory
|
||||
* to the beginning of the next vector.
|
||||
*/
|
||||
* to the beginning of the next vector. */
|
||||
SpatialSort( const aiVector3D* pPositions, unsigned int pNumPositions,
|
||||
unsigned int pElementOffset);
|
||||
|
||||
/** Destructor */
|
||||
~SpatialSort();
|
||||
|
||||
/** Sets the input data for the SpatialSort. This replaces the old data.
|
||||
public:
|
||||
|
||||
// ------------------------------------------------------------------------------------
|
||||
/** Sets the input data for the SpatialSort. This replaces existing data, if any.
|
||||
* The new data receives new indices in ascending order.
|
||||
*
|
||||
* @param pPositions Pointer to the first position vector of the array.
|
||||
* @param pNumPositions Number of vectors to expect in that array.
|
||||
* @param pElementOffset Offset in bytes from the beginning of one vector in memory
|
||||
* to the beginning of the next vector.
|
||||
*/
|
||||
* @param pFinalize Specifies whether the SpatialSort's internal representation
|
||||
* is finalized after the new data has been added. Finalization is
|
||||
* required in order to use #FindPosition() or #GenerateMappingTable().
|
||||
* If you don't finalize yet, you can use #Append() to add data from
|
||||
* other sources.*/
|
||||
void Fill( const aiVector3D* pPositions, unsigned int pNumPositions,
|
||||
unsigned int pElementOffset);
|
||||
unsigned int pElementOffset,
|
||||
bool pFinalize = true);
|
||||
|
||||
|
||||
/** Destructor */
|
||||
~SpatialSort();
|
||||
// ------------------------------------------------------------------------------------
|
||||
/** Same as #Fill(), except the method appends to existing data in the #SpatialSort. */
|
||||
void Append( const aiVector3D* pPositions, unsigned int pNumPositions,
|
||||
unsigned int pElementOffset,
|
||||
bool pFinalize = true);
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------
|
||||
/** Finalize the spatial hash data structure. This can be useful after
|
||||
* multiple calls to #Append() with the pFinalize parameter set to false.
|
||||
* This is finally required before one of #FindPositions() and #GenerateMappingTable()
|
||||
* can be called to query the spatial sort.*/
|
||||
void Finalize();
|
||||
|
||||
// ------------------------------------------------------------------------------------
|
||||
/** Returns an iterator for all positions close to the given position.
|
||||
* @param pPosition The position to look for vertices.
|
||||
* @param pRadius Maximal distance from the position a vertex may have to be counted in.
|
||||
* @param poResults The container to store the indices of the found positions. Will be emptied
|
||||
* by the call so it may contain anything.
|
||||
* @return An iterator to iterate over all vertices in the given area.
|
||||
*/
|
||||
void FindPositions( const aiVector3D& pPosition, float pRadius, std::vector<unsigned int>& poResults) const;
|
||||
* @param poResults The container to store the indices of the found positions.
|
||||
* Will be emptied by the call so it may contain anything.
|
||||
* @return An iterator to iterate over all vertices in the given area.*/
|
||||
void FindPositions( const aiVector3D& pPosition, float pRadius,
|
||||
std::vector<unsigned int>& poResults) const;
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------
|
||||
/** Compute a table that maps each vertex ID referring to a spatially close
|
||||
* enough position to the same output ID. Output IDs are assigned in ascending order
|
||||
* from 0...n.
|
||||
* @param fill Will be filled with numPositions entries.
|
||||
* @param pRadius Maximal distance from the position a vertex may have to
|
||||
* be counted in.
|
||||
* @return Number of unique vertices (n). */
|
||||
unsigned int GenerateMappingTable(std::vector<unsigned int>& fill,
|
||||
float pRadius) const;
|
||||
|
||||
protected:
|
||||
/** Normal of the sorting plane, normalized. The center is always at (0, 0, 0) */
|
||||
|
|
|
@ -0,0 +1,586 @@
|
|||
/*
|
||||
Open Asset Import Library (ASSIMP)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2008, ASSIMP Development Team
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the ASSIMP team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the ASSIMP Development Team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "AssimpPCH.h"
|
||||
|
||||
#include "Subdivision.h"
|
||||
#include "SceneCombiner.h"
|
||||
#include "SpatialSort.h"
|
||||
#include "ProcessHelper.h"
|
||||
#include "Vertex.h"
|
||||
|
||||
using namespace Assimp;
|
||||
void mydummy() {}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Subdivider stub class to implement the Catmull-Clarke subdivision algorithm. The
|
||||
* implementation is basing on recursive refinement. Directly evaluating the result is also
|
||||
* possibel and much quicker, but it depends on lengthy matrix lookup tables. */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
class CatmullClarkSubdivider : public Subdivider
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
void Subdivide (const aiMesh* mesh, aiMesh*& out, unsigned int num, bool discard_input);
|
||||
void Subdivide (const aiMesh* const * smesh, size_t nmesh,
|
||||
aiMesh** out, unsigned int num, bool discard_input);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Intermediate description of an edge between two corners of a polygon*/
|
||||
// ---------------------------------------------------------------------------
|
||||
struct Edge
|
||||
{
|
||||
Edge()
|
||||
: ref(0)
|
||||
{}
|
||||
Vertex edge_point, midpoint;
|
||||
unsigned int ref;
|
||||
};
|
||||
|
||||
|
||||
|
||||
typedef std::vector<unsigned int> UIntVector;
|
||||
typedef std::map<uint64_t,Edge> EdgeMap;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Hashing function to derive an index into an #EdgeMap from two given
|
||||
// 'unsigned int' vertex coordinates (!!distinct coordinates - same
|
||||
// vertex position == same index!!).
|
||||
// NOTE - this leads to rare hash collisions if a) sizeof(unsigned int)>4
|
||||
// and (id[0]>2^32-1 or id[0]>2^32-1).
|
||||
// MAKE_EDGE_HASH() uses temporaries, so INIT_EDGE_HASH() needs to be put
|
||||
// at the head of every function which is about to use MAKE_EDGE_HASH().
|
||||
// Reason is that the hash is that hash construction needs to hold the
|
||||
// invariant id0<id1 to identify an edge - else two hashes would refer
|
||||
// to the same edge.
|
||||
// ---------------------------------------------------------------------------
|
||||
#define MAKE_EDGE_HASH(id0,id1) (eh_tmp0__=id0,eh_tmp1__=id1,\
|
||||
(eh_tmp0__<eh_tmp1__?std::swap(eh_tmp0__,eh_tmp1__):mydummy()),(uint64_t)eh_tmp0__^((uint64_t)eh_tmp1__<<32u))
|
||||
|
||||
|
||||
#define INIT_EDGE_HASH_TEMPORARIES()\
|
||||
unsigned int eh_tmp0__, eh_tmp1__;
|
||||
|
||||
private:
|
||||
|
||||
void InternSubdivide (const aiMesh* const * smesh,
|
||||
size_t nmesh,aiMesh** out, unsigned int num);
|
||||
};
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Construct a subdivider of a specific type
|
||||
Subdivider* Subdivider::Create (Algorithm algo)
|
||||
{
|
||||
switch (algo)
|
||||
{
|
||||
case CATMULL_CLARKE:
|
||||
return new CatmullClarkSubdivider();
|
||||
};
|
||||
|
||||
ai_assert(false);
|
||||
return NULL; // shouldn't happen
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Call the Catmull Clark subdivision algorithm for one mesh
|
||||
void CatmullClarkSubdivider::Subdivide (
|
||||
const aiMesh* mesh,
|
||||
aiMesh*& out,
|
||||
unsigned int num,
|
||||
bool discard_input
|
||||
)
|
||||
{
|
||||
assert(mesh != out);
|
||||
Subdivide(&mesh,1,&out,num,discard_input);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Call the Catmull Clark subdivision algorithm for multiple meshes
|
||||
void CatmullClarkSubdivider::Subdivide (
|
||||
const aiMesh* const * smesh,
|
||||
size_t nmesh,
|
||||
aiMesh** out,
|
||||
unsigned int num,
|
||||
bool discard_input
|
||||
)
|
||||
{
|
||||
ai_assert(NULL != smesh && NULL != out);
|
||||
|
||||
// course, both regions may not overlap
|
||||
assert(smesh<out || smesh+nmesh>out+nmesh);
|
||||
if (!num) {
|
||||
|
||||
// No subdivision at all. Need to copy all the meshes .. argh.
|
||||
if (discard_input) {
|
||||
for (size_t s = 0; s < nmesh; ++s) {
|
||||
out[s] = const_cast<aiMesh*>( smesh[s] );
|
||||
const_cast<aiMesh*&>( smesh[s] ) = NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (size_t s = 0; s < nmesh; ++s) {
|
||||
SceneCombiner::Copy(out+s,smesh[s]);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<const aiMesh*> inmeshes;
|
||||
std::vector<aiMesh*> outmeshes;
|
||||
std::vector<unsigned int> maptbl;
|
||||
|
||||
inmeshes.reserve(nmesh);
|
||||
outmeshes.reserve(nmesh);
|
||||
maptbl.reserve(nmesh);
|
||||
|
||||
// Remove pure line and point meshes from the working set to reduce the
|
||||
// number of edge cases the subdivider is forced to deal with. Line and
|
||||
// point meshes are simply passed through.
|
||||
for (size_t s = 0; s < nmesh; ++s) {
|
||||
const aiMesh* i = smesh[s];
|
||||
if ((i->mPrimitiveTypes & aiPrimitiveType_LINE|aiPrimitiveType_POINT)==i->mPrimitiveTypes) {
|
||||
DefaultLogger::get()->debug("Catmull-Clark Subdivider: Skipping pure line/point mesh");
|
||||
|
||||
if (discard_input) {
|
||||
out[s] = const_cast<aiMesh*>( i );
|
||||
const_cast<aiMesh*&>( smesh[s] ) = NULL;
|
||||
}
|
||||
else {
|
||||
SceneCombiner::Copy(out+s,i);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
outmeshes.push_back(NULL);inmeshes.push_back(i);
|
||||
maptbl.push_back(s);
|
||||
}
|
||||
|
||||
// Do the actual subdivision on the preallocated storage. InternSubdivide
|
||||
// *always* assumes that enough storage is available, it does not bother
|
||||
// checking any ranges.
|
||||
ai_assert(inmeshes.size()==outmeshes.size()&&inmeshes.size()==maptbl.size());
|
||||
if (inmeshes.empty()) {
|
||||
DefaultLogger::get()->warn("Catmull-Clark Subdivider: Pure point/line scene, I can't do anything");
|
||||
return;
|
||||
}
|
||||
InternSubdivide(&inmeshes.front(),inmeshes.size(),&outmeshes.front(),num);
|
||||
for (unsigned int i = 0; i < maptbl.size(); ++i) {
|
||||
ai_assert(outmeshes[i]);
|
||||
out[maptbl[i]] = outmeshes[i];
|
||||
}
|
||||
|
||||
if (discard_input) {
|
||||
for (size_t s = 0; s < nmesh; ++s) {
|
||||
delete smesh[s];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Note - this is an implementation of the standard (recursive) Cm-Cl algorithm without further
|
||||
// optimizations (except we're using some nice LUTs). A description of the algorithm can be found
|
||||
// here: http://en.wikipedia.org/wiki/Catmull-Clark_subdivision_surface
|
||||
//
|
||||
// The code is mostly O(n), however parts are O(nlogn) which is therefore the algorithm's
|
||||
// expected total runtime complexity. The implementation is able to work in-place on the same
|
||||
// mesh arrays. Calling #InternSubdivide() directly is not encouraged. The code can operate
|
||||
// in-place unless 'smesh' and 'out' are equal (no strange overlaps or reorderings).
|
||||
// Previous data is replaced/deleted then.
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void CatmullClarkSubdivider::InternSubdivide (
|
||||
const aiMesh* const * smesh,
|
||||
size_t nmesh,
|
||||
aiMesh** out,
|
||||
unsigned int num
|
||||
)
|
||||
{
|
||||
ai_assert(NULL != smesh && NULL != out);
|
||||
INIT_EDGE_HASH_TEMPORARIES();
|
||||
|
||||
// no subdivision requested or end of recursive refinement
|
||||
if (!num) {
|
||||
return;
|
||||
}
|
||||
|
||||
UIntVector maptbl;
|
||||
SpatialSort spatial;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// 0. Offset table to index all meshes continously , generate a spatially
|
||||
// sorted representation of all vertices in all meshes.
|
||||
// ---------------------------------------------------------------------
|
||||
typedef std::pair<unsigned int,unsigned int> IntPair;
|
||||
std::vector<IntPair> moffsets(nmesh);
|
||||
unsigned int totfaces = 0, totvert = 0;
|
||||
for (size_t t = 0; t < nmesh; ++t) {
|
||||
const aiMesh* mesh = smesh[t];
|
||||
|
||||
spatial.Append(mesh->mVertices,mesh->mNumVertices,sizeof(aiVector3D),false);
|
||||
moffsets[t] = IntPair(totfaces,totvert);
|
||||
|
||||
totfaces += mesh->mNumFaces;
|
||||
totvert += mesh->mNumVertices;
|
||||
}
|
||||
|
||||
spatial.Finalize();
|
||||
const unsigned int num_unique = spatial.GenerateMappingTable(maptbl,ComputePositionEpsilon(smesh,nmesh));
|
||||
|
||||
|
||||
#define FLATTEN_VERTEX_IDX(mesh_idx, vert_idx) (moffsets[mesh_idx].second+vert_idx)
|
||||
#define FLATTEN_FACE_IDX(mesh_idx, face_idx) (moffsets[mesh_idx].first+face_idx)
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// 1. Compute the centroid point for all faces
|
||||
// ---------------------------------------------------------------------
|
||||
std::vector<Vertex> centroids(totfaces);
|
||||
unsigned int nfacesout = 0;
|
||||
for (size_t t = 0, n = 0; t < nmesh; ++t) {
|
||||
const aiMesh* mesh = smesh[t];
|
||||
for (unsigned int i = 0; i < mesh->mNumFaces;++i,++n)
|
||||
{
|
||||
const aiFace& face = mesh->mFaces[i];
|
||||
Vertex& c = centroids[n];
|
||||
|
||||
for (unsigned int a = 0; a < face.mNumIndices;++a) {
|
||||
c += Vertex(mesh,face.mIndices[a]);
|
||||
}
|
||||
|
||||
c /= static_cast<float>(face.mNumIndices);
|
||||
nfacesout += face.mNumIndices;
|
||||
}
|
||||
}
|
||||
|
||||
EdgeMap edges;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// 2. Set each edge point to be the average of all neighbouring
|
||||
// face points and original points. Every edge exists twice
|
||||
// if there is a neighboring face.
|
||||
// ---------------------------------------------------------------------
|
||||
for (size_t t = 0, n = 0; t < nmesh; ++t) {
|
||||
const aiMesh* mesh = smesh[t];
|
||||
|
||||
for (unsigned int i = 0; i < mesh->mNumFaces;++i) {
|
||||
const aiFace& face = mesh->mFaces[i];
|
||||
|
||||
for (unsigned int p =0; p< face.mNumIndices; ++p) {
|
||||
const unsigned int id[] = {
|
||||
face.mIndices[p],
|
||||
face.mIndices[p==face.mNumIndices-1?0:p+1]
|
||||
};
|
||||
const unsigned int mp[] = {
|
||||
maptbl[FLATTEN_VERTEX_IDX(t,id[0])],
|
||||
maptbl[FLATTEN_VERTEX_IDX(t,id[1])]
|
||||
};
|
||||
|
||||
Edge& e = edges[MAKE_EDGE_HASH(mp[0],mp[1])];
|
||||
e.ref++;
|
||||
if (e.ref<=2) {
|
||||
if (e.ref==1) { // original points (end points) - add only once
|
||||
e.edge_point = e.midpoint = Vertex(mesh,id[0])+Vertex(mesh,id[1]);
|
||||
e.midpoint *= 0.5f;
|
||||
}
|
||||
e.edge_point += centroids[FLATTEN_FACE_IDX(t,i)];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// 3. Normalize edge points
|
||||
// ---------------------------------------------------------------------
|
||||
{unsigned int bad_cnt = 0;
|
||||
for (EdgeMap::iterator it = edges.begin(); it != edges.end(); ++it) {
|
||||
if ((*it).second.ref < 2) {
|
||||
ai_assert((*it).second.ref);
|
||||
++bad_cnt;
|
||||
}
|
||||
(*it).second.edge_point *= 1.f/((*it).second.ref+2.f);
|
||||
}
|
||||
|
||||
if (bad_cnt) {
|
||||
// Report the number of bad edges. bad edges are referenced by less than two
|
||||
// faces in the mesh. They occur at outer model boundaries in non-closed
|
||||
// shapes.
|
||||
char tmp[512];
|
||||
sprintf(tmp,"Catmull-Clark Subdivider: got %i bad edges touching only one face (totally %i edges). ",
|
||||
bad_cnt,edges.size());
|
||||
|
||||
DefaultLogger::get()->debug(tmp);
|
||||
}}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// 4. Compute a vertex-face adjacency table. We can't reuse the code
|
||||
// from VertexTriangleAdjacency because we need the table for multiple
|
||||
// meshes and out vertex indices need to be mapped to distinct values
|
||||
// first.
|
||||
// ---------------------------------------------------------------------
|
||||
UIntVector faceadjac(nfacesout), cntadjfac(maptbl.size(),0), ofsadjvec(maptbl.size()+1,0); {
|
||||
for (size_t t = 0; t < nmesh; ++t) {
|
||||
const aiMesh* const minp = smesh[t];
|
||||
for (unsigned int i = 0; i < minp->mNumFaces; ++i) {
|
||||
|
||||
const aiFace& f = minp->mFaces[i];
|
||||
for (unsigned int n = 0; n < f.mNumIndices; ++n) {
|
||||
++cntadjfac[maptbl[FLATTEN_VERTEX_IDX(t,f.mIndices[n])]];
|
||||
}
|
||||
}
|
||||
}
|
||||
unsigned int cur = 0;
|
||||
for (size_t i = 0; i < cntadjfac.size(); ++i) {
|
||||
ofsadjvec[i+1] = cur;
|
||||
cur += cntadjfac[i];
|
||||
}
|
||||
for (size_t t = 0; t < nmesh; ++t) {
|
||||
const aiMesh* const minp = smesh[t];
|
||||
for (unsigned int i = 0; i < minp->mNumFaces; ++i) {
|
||||
|
||||
const aiFace& f = minp->mFaces[i];
|
||||
for (unsigned int n = 0; n < f.mNumIndices; ++n) {
|
||||
faceadjac[ofsadjvec[1+maptbl[FLATTEN_VERTEX_IDX(t,f.mIndices[n])]]++] = FLATTEN_FACE_IDX(t,i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check the other way round for consistency
|
||||
#ifdef _DEBUG
|
||||
|
||||
for (size_t t = 0; t < ofsadjvec.size()-1; ++t) {
|
||||
for (unsigned int m = 0; m < cntadjfac[t]; ++m) {
|
||||
const unsigned int fidx = faceadjac[ofsadjvec[t]+m];
|
||||
ai_assert(fidx < totfaces);
|
||||
for (size_t n = 1; n < nmesh; ++n) {
|
||||
|
||||
if (moffsets[n].first > fidx) {
|
||||
const aiMesh* msh = smesh[--n];
|
||||
const aiFace& f = msh->mFaces[fidx-moffsets[n].first];
|
||||
|
||||
bool haveit = false;
|
||||
for (unsigned int i = 0; i < f.mNumIndices; ++i) {
|
||||
if (maptbl[FLATTEN_VERTEX_IDX(n,f.mIndices[i])]==(unsigned int)t) {
|
||||
haveit = true; break;
|
||||
}
|
||||
}
|
||||
ai_assert(haveit);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#define GET_ADJACENT_FACES_AND_CNT(vidx,fstartout,numout) \
|
||||
fstartout = &faceadjac[ofsadjvec[vidx]], numout = cntadjfac[vidx]
|
||||
|
||||
typedef std::pair<bool,Vertex> TouchedOVertex;
|
||||
std::vector<TouchedOVertex > new_points(num_unique,TouchedOVertex(false,Vertex()));
|
||||
// ---------------------------------------------------------------------
|
||||
// 5. Spawn a quad from each face point to the corresponding edge points
|
||||
// the original points being the fourth quad points.
|
||||
// ---------------------------------------------------------------------
|
||||
for (size_t t = 0; t < nmesh; ++t) {
|
||||
const aiMesh* const minp = smesh[t];
|
||||
aiMesh* const mout = out[t] = new aiMesh();
|
||||
|
||||
for (unsigned int a = 0; a < minp->mNumFaces; ++a) {
|
||||
mout->mNumFaces += minp->mFaces[a].mNumIndices;
|
||||
}
|
||||
|
||||
// We need random access to the old face buffer, so reuse is not possible.
|
||||
mout->mFaces = new aiFace[mout->mNumFaces];
|
||||
|
||||
mout->mNumVertices = mout->mNumFaces*4;
|
||||
mout->mVertices = new aiVector3D[mout->mNumVertices];
|
||||
|
||||
// quads only, keep material index
|
||||
mout->mPrimitiveTypes = aiPrimitiveType_POLYGON;
|
||||
mout->mMaterialIndex = minp->mMaterialIndex;
|
||||
|
||||
if (minp->HasNormals()) {
|
||||
mout->mNormals = new aiVector3D[mout->mNumVertices];
|
||||
}
|
||||
|
||||
if (minp->HasTangentsAndBitangents()) {
|
||||
mout->mTangents = new aiVector3D[mout->mNumVertices];
|
||||
mout->mBitangents = new aiVector3D[mout->mNumVertices];
|
||||
}
|
||||
|
||||
for(unsigned int i = 0; minp->HasTextureCoords(i); ++i) {
|
||||
mout->mTextureCoords[i] = new aiVector3D[mout->mNumVertices];
|
||||
mout->mNumUVComponents[i] = minp->mNumUVComponents[i];
|
||||
}
|
||||
|
||||
for(unsigned int i = 0; minp->HasVertexColors(i); ++i) {
|
||||
mout->mColors[i] = new aiColor4D[mout->mNumVertices];
|
||||
}
|
||||
|
||||
mout->mNumVertices = mout->mNumFaces<<2u;
|
||||
for (unsigned int i = 0, v = 0, n = 0; i < minp->mNumFaces;++i) {
|
||||
|
||||
const aiFace& face = minp->mFaces[i];
|
||||
for (unsigned int a = 0; a < face.mNumIndices;++a) {
|
||||
|
||||
// Get a clean new face.
|
||||
aiFace& faceOut = mout->mFaces[n++];
|
||||
faceOut.mIndices = new unsigned int [faceOut.mNumIndices = 4];
|
||||
|
||||
// Spawn a new quadrilateral (ccw winding) for this original point between:
|
||||
// a) face centroid
|
||||
centroids[FLATTEN_FACE_IDX(t,i)].SortBack(mout,faceOut.mIndices[0]=v++);
|
||||
|
||||
// b) adjacent edge on the left, seen from the centroid
|
||||
const Edge& e0 = edges[MAKE_EDGE_HASH(maptbl[FLATTEN_VERTEX_IDX(t,face.mIndices[a])],
|
||||
maptbl[FLATTEN_VERTEX_IDX(t,face.mIndices[a==face.mNumIndices-1?0:a+1])
|
||||
])]; // fixme: replace with mod face.mNumIndices?
|
||||
|
||||
// c) adjacent edge on the right, seen from the centroid
|
||||
const Edge& e1 = edges[MAKE_EDGE_HASH(maptbl[FLATTEN_VERTEX_IDX(t,face.mIndices[a])],
|
||||
maptbl[FLATTEN_VERTEX_IDX(t,face.mIndices[!a?face.mNumIndices-1:a-1])
|
||||
])]; // fixme: replace with mod face.mNumIndices?
|
||||
|
||||
e0.edge_point.SortBack(mout,faceOut.mIndices[3]=v++);
|
||||
e1.edge_point.SortBack(mout,faceOut.mIndices[1]=v++);
|
||||
|
||||
// d= original point P with distinct index i
|
||||
// F := 0
|
||||
// R := 0
|
||||
// n := 0
|
||||
// for each face f containing i
|
||||
// F := F+ centroid of f
|
||||
// R := R+ midpoint of edge of f from i to i+1
|
||||
// n := n+1
|
||||
//
|
||||
// (F+2R+(n-3)P)/n
|
||||
const unsigned int org = maptbl[FLATTEN_VERTEX_IDX(t,face.mIndices[a])];
|
||||
TouchedOVertex& ov = new_points[org];
|
||||
|
||||
if (!ov.first) {
|
||||
ov.first = true;
|
||||
|
||||
const unsigned int* adj; unsigned int cnt;
|
||||
GET_ADJACENT_FACES_AND_CNT(org,adj,cnt);
|
||||
|
||||
if (cnt < 3) {
|
||||
ov.second = Vertex(minp,face.mIndices[a]);
|
||||
}
|
||||
else {
|
||||
|
||||
Vertex F,R;
|
||||
for (unsigned int o = 0; o < cnt; ++o) {
|
||||
ai_assert(adj[o] < totfaces);
|
||||
F += centroids[adj[o]];
|
||||
|
||||
// adj[0] is a global face index - search the face in the mesh list
|
||||
const aiMesh* mp = NULL;
|
||||
size_t nidx;
|
||||
|
||||
if (adj[o] < moffsets[0].first) {
|
||||
mp = smesh[nidx=0];
|
||||
}
|
||||
else {
|
||||
for (nidx = 1; nidx<= nmesh; ++nidx) {
|
||||
if (nidx == nmesh ||moffsets[nidx].first > adj[o]) {
|
||||
mp = smesh[--nidx];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ai_assert(adj[o]-moffsets[nidx].first < mp->mNumFaces);
|
||||
const aiFace& f = mp->mFaces[adj[o]-moffsets[nidx].first];
|
||||
# ifdef _DEBUG
|
||||
bool haveit = false;
|
||||
# endif
|
||||
|
||||
// find our original point in the face
|
||||
for (unsigned int m = 0; m < f.mNumIndices; ++m) {
|
||||
if (maptbl[FLATTEN_VERTEX_IDX(nidx,f.mIndices[m])] == org) {
|
||||
|
||||
// add *both* edges. this way, we can be sure that we add
|
||||
// *all* adjacent edges to R. In a closed shape, every
|
||||
// edge is added twice - so we simply leave out the
|
||||
// factor 2.f in the amove formula and get the right
|
||||
// result.
|
||||
|
||||
const Edge& c0 = edges[MAKE_EDGE_HASH(org,maptbl[FLATTEN_VERTEX_IDX(
|
||||
nidx,f.mIndices[!m?f.mNumIndices-1:m-1])])];
|
||||
// fixme: replace with mod face.mNumIndices?
|
||||
|
||||
const Edge& c1 = edges[MAKE_EDGE_HASH(org,maptbl[FLATTEN_VERTEX_IDX(
|
||||
nidx,f.mIndices[m==f.mNumIndices-1?0:m+1])])];
|
||||
// fixme: replace with mod face.mNumIndices?
|
||||
R += c0.midpoint+c1.midpoint;
|
||||
|
||||
# ifdef _DEBUG
|
||||
haveit = true;
|
||||
# endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// this invariant *must* hold if the vertex-to-face adjacency table is valid
|
||||
ai_assert(haveit);
|
||||
}
|
||||
|
||||
const float div = static_cast<float>(cnt), divsq = 1.f/(div*div);
|
||||
ov.second = Vertex(minp,face.mIndices[a])*((div-3.f) / div) + R*divsq + F*divsq;
|
||||
}
|
||||
}
|
||||
ov.second.SortBack(mout,faceOut.mIndices[2]=v++);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// 7. Apply the next subdivision step.
|
||||
// ---------------------------------------------------------------------
|
||||
if (num != 1) {
|
||||
std::vector<aiMesh*> tmp(nmesh);
|
||||
InternSubdivide (out,nmesh,&tmp.front(),num-1);
|
||||
for (size_t i = 0; i < nmesh; ++i) {
|
||||
delete out[i];
|
||||
out[i] = tmp[i];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
Open Asset Import Library (ASSIMP)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2008, ASSIMP Development Team
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the ASSIMP team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the ASSIMP Development Team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file Defines a helper class to evaluate subdivision surfaces.*/
|
||||
#ifndef AI_SUBDISIVION_H_INC
|
||||
#define AI_SUBDISIVION_H_INC
|
||||
namespace Assimp {
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
/** Helper class to evaluate subdivision surfaces. Different algorithms
|
||||
* are provided for choice. */
|
||||
// ------------------------------------------------------------------------------
|
||||
class ASSIMP_API Subdivider
|
||||
{
|
||||
public:
|
||||
|
||||
/** Enumerates all supported subvidision algorithms */
|
||||
enum Algorithm {
|
||||
CATMULL_CLARKE = 0x1
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
/** Create a subdivider of a specific type
|
||||
*
|
||||
* @param algo Algorithm to be used for subdivision
|
||||
* @return Subdivider instance. */
|
||||
static Subdivider* Create (Algorithm algo);
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
/** Subdivide a mesh using the selected algorithm
|
||||
*
|
||||
* @param mesh First mesh to be subdivided. Must be in verbose
|
||||
* format.
|
||||
* @param out Receives the output mesh, allocated by me.
|
||||
* @param num Number of subdivisions to perform.
|
||||
* @param discard_input If true is passed, the input mesh is
|
||||
* deleted after the subdivision is complete. This can
|
||||
* improve performance because it allows the optimization
|
||||
* to reuse the existing mesh for intermediate results.
|
||||
* @pre out!=mesh*/
|
||||
virtual void Subdivide (const aiMesh* mesh,
|
||||
aiMesh*& out, unsigned int num,
|
||||
bool discard_input = false) = 0;
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
/** Subdivide multiple meshes using the selected algorithm. This
|
||||
* avoids erroneous smoothing on objects consisting of multiple
|
||||
* per-material meshes. Usually, most 3d modellers smooth on a
|
||||
* per-object base, regardless the materials assigned to the
|
||||
* meshes.
|
||||
*
|
||||
* @param smesh Array of meshes to be subdivided. Must be in
|
||||
* verbose format.
|
||||
* @param nmesh Number of meshes in smesh.
|
||||
* @param out Receives the output meshes. The array must be
|
||||
* sufficiently large (at least @c nmesh elements). Output meshes
|
||||
* map one-to-one to their corresponding input meshes. The
|
||||
* meshes are allocated by the function.
|
||||
* @param discard_input If true is passed, input meshes are
|
||||
* deleted after the subdivision is complete. This can
|
||||
* improve performance because it allows the optimization
|
||||
* to reuse existing meshes for intermediate results.
|
||||
* @param num Number of subdivisions to perform.
|
||||
* @pre nmesh != 0, smesh and out may not overlap*/
|
||||
virtual void Subdivide (
|
||||
const aiMesh* const * smesh,
|
||||
size_t nmesh,
|
||||
aiMesh** out,
|
||||
unsigned int num,
|
||||
bool discard_input = false) = 0;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
} // end namespace Assimp
|
||||
|
||||
|
||||
#endif // !! AI_SUBDISIVION_H_INC
|
||||
|
|
@ -0,0 +1,301 @@
|
|||
/*
|
||||
Open Asset Import Library (ASSIMP)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2008, ASSIMP Development Team
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the ASSIMP team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the ASSIMP Development Team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
/** @file Defines a helper class to represent an interleaved vertex */
|
||||
#ifndef AI_VERTEX_H_INC
|
||||
#define AI_VERTEX_H_INC
|
||||
namespace Assimp {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// std::plus-family operates on operands with identical types - we need to
|
||||
// support all the (vectype op float) combinations in vector maths.
|
||||
// Providing T(float) would open the way to endless implicit conversions.
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
namespace Intern {
|
||||
template <typename T0, typename T1, typename TRES = T0> struct plus {
|
||||
TRES operator() (const T0& t0, const T1& t1) const {
|
||||
return t0+t1;
|
||||
}
|
||||
};
|
||||
template <typename T0, typename T1, typename TRES = T0> struct minus {
|
||||
TRES operator() (const T0& t0, const T1& t1) const {
|
||||
return t0-t1;
|
||||
}
|
||||
};
|
||||
template <typename T0, typename T1, typename TRES = T0> struct multiplies {
|
||||
TRES operator() (const T0& t0, const T1& t1) const {
|
||||
return t0*t1;
|
||||
}
|
||||
};
|
||||
template <typename T0, typename T1, typename TRES = T0> struct divides {
|
||||
TRES operator() (const T0& t0, const T1& t1) const {
|
||||
return t0/t1;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
/** Intermediate description a vertex with all possible components. Defines a full set of
|
||||
* operators, so you may use such a 'Vertex' in basic arithmetics. All operators are applied
|
||||
* to *all* vertex components equally. This is useful for stuff like interpolation
|
||||
* or subdivision, but won't work if special handling is required for some vertex components. */
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
class Vertex
|
||||
{
|
||||
friend Vertex operator + (const Vertex&,const Vertex&);
|
||||
friend Vertex operator - (const Vertex&,const Vertex&);
|
||||
|
||||
friend Vertex operator + (const Vertex&,float);
|
||||
friend Vertex operator - (const Vertex&,float);
|
||||
friend Vertex operator * (const Vertex&,float);
|
||||
friend Vertex operator / (const Vertex&,float);
|
||||
|
||||
friend Vertex operator + (float, const Vertex&);
|
||||
friend Vertex operator - (float, const Vertex&);
|
||||
friend Vertex operator * (float, const Vertex&);
|
||||
friend Vertex operator / (float, const Vertex&);
|
||||
|
||||
public:
|
||||
|
||||
Vertex() {}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Extract a particular vertex from a mesh and interleave all components */
|
||||
explicit Vertex(const aiMesh* msh, unsigned int idx) {
|
||||
ai_assert(idx < msh->mNumVertices);
|
||||
position = msh->mVertices[idx];
|
||||
|
||||
if (msh->HasNormals()) {
|
||||
normal = msh->mNormals[idx];
|
||||
}
|
||||
|
||||
if (msh->HasTangentsAndBitangents()) {
|
||||
tangent = msh->mTangents[idx];
|
||||
bitangent = msh->mBitangents[idx];
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; msh->HasTextureCoords(i); ++i) {
|
||||
texcoords[i] = msh->mTextureCoords[i][idx];
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; msh->HasVertexColors(i); ++i) {
|
||||
colors[i] = msh->mColors[i][idx];
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Vertex& operator += (const Vertex& v) {
|
||||
*this = *this+v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vertex& operator -= (const Vertex& v) {
|
||||
*this = *this-v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Vertex& operator += (float v) {
|
||||
*this = *this+v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vertex& operator -= (float v) {
|
||||
*this = *this-v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vertex& operator *= (float v) {
|
||||
*this = *this*v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Vertex& operator /= (float v) {
|
||||
*this = *this/v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Convert back to non-interleaved storage */
|
||||
void SortBack(aiMesh* out, unsigned int idx) const {
|
||||
|
||||
ai_assert(idx<out->mNumVertices);
|
||||
out->mVertices[idx] = position;
|
||||
|
||||
if (out->HasNormals()) {
|
||||
out->mNormals[idx] = normal;
|
||||
}
|
||||
|
||||
if (out->HasTangentsAndBitangents()) {
|
||||
out->mTangents[idx] = tangent;
|
||||
out->mBitangents[idx] = bitangent;
|
||||
}
|
||||
|
||||
for(unsigned int i = 0; out->HasTextureCoords(i); ++i) {
|
||||
out->mTextureCoords[i][idx] = texcoords[i];
|
||||
}
|
||||
|
||||
for(unsigned int i = 0; out->HasVertexColors(i); ++i) {
|
||||
out->mColors[i][idx] = colors[i];
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Construct from two operands and a binary operation to combine them */
|
||||
template <template <typename t> class op> static Vertex BinaryOp(const Vertex& v0, const Vertex& v1) {
|
||||
// this is a heavy task for the compiler to optimize ... *pray*
|
||||
|
||||
Vertex res;
|
||||
res.position = op<aiVector3D>()(v0.position,v1.position);
|
||||
res.normal = op<aiVector3D>()(v0.normal,v1.normal);
|
||||
res.tangent = op<aiVector3D>()(v0.tangent,v1.tangent);
|
||||
res.bitangent = op<aiVector3D>()(v0.bitangent,v1.bitangent);
|
||||
|
||||
for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
|
||||
res.texcoords[i] = op<aiVector3D>()(v0.texcoords[i],v1.texcoords[i]);
|
||||
}
|
||||
for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i) {
|
||||
res.colors[i] = op<aiColor4D>()(v0.colors[i],v1.colors[i]);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** This time binary arithmetics of v0 with a floating-point number */
|
||||
template <template <typename, typename, typename> class op> static Vertex BinaryOp(const Vertex& v0, float f) {
|
||||
// this is a heavy task for the compiler to optimize ... *pray*
|
||||
|
||||
Vertex res;
|
||||
res.position = op<aiVector3D,float,aiVector3D>()(v0.position,f);
|
||||
res.normal = op<aiVector3D,float,aiVector3D>()(v0.normal,f);
|
||||
res.tangent = op<aiVector3D,float,aiVector3D>()(v0.tangent,f);
|
||||
res.bitangent = op<aiVector3D,float,aiVector3D>()(v0.bitangent,f);
|
||||
|
||||
for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
|
||||
res.texcoords[i] = op<aiVector3D,float,aiVector3D>()(v0.texcoords[i],f);
|
||||
}
|
||||
for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i) {
|
||||
res.colors[i] = op<aiColor4D,float,aiColor4D>()(v0.colors[i],f);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** This time binary arithmetics of v0 with a floating-point number */
|
||||
template <template <typename, typename, typename> class op> static Vertex BinaryOp(float f, const Vertex& v0) {
|
||||
// this is a heavy task for the compiler to optimize ... *pray*
|
||||
|
||||
Vertex res;
|
||||
res.position = op<float,aiVector3D,aiVector3D>()(f,v0.position);
|
||||
res.normal = op<float,aiVector3D,aiVector3D>()(f,v0.normal);
|
||||
res.tangent = op<float,aiVector3D,aiVector3D>()(f,v0.tangent);
|
||||
res.bitangent = op<float,aiVector3D,aiVector3D>()(f,v0.bitangent);
|
||||
|
||||
for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
|
||||
res.texcoords[i] = op<float,aiVector3D,aiVector3D>()(f,v0.texcoords[i]);
|
||||
}
|
||||
for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i) {
|
||||
res.colors[i] = op<float,aiColor4D,aiColor4D>()(f,v0.colors[i]);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
aiVector3D position;
|
||||
aiVector3D normal;
|
||||
aiVector3D tangent, bitangent;
|
||||
|
||||
aiVector3D texcoords[AI_MAX_NUMBER_OF_TEXTURECOORDS];
|
||||
aiColor4D colors[AI_MAX_NUMBER_OF_COLOR_SETS];
|
||||
};
|
||||
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AI_FORCE_INLINE Vertex operator + (const Vertex& v0,const Vertex& v1) {
|
||||
return Vertex::BinaryOp<std::plus>(v0,v1);
|
||||
}
|
||||
|
||||
AI_FORCE_INLINE Vertex operator - (const Vertex& v0,const Vertex& v1) {
|
||||
return Vertex::BinaryOp<std::minus>(v0,v1);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AI_FORCE_INLINE Vertex operator + (const Vertex& v0,float f) {
|
||||
return Vertex::BinaryOp<Intern::plus>(v0,f);
|
||||
}
|
||||
|
||||
AI_FORCE_INLINE Vertex operator - (const Vertex& v0,float f) {
|
||||
return Vertex::BinaryOp<Intern::minus>(v0,f);
|
||||
}
|
||||
|
||||
AI_FORCE_INLINE Vertex operator * (const Vertex& v0,float f) {
|
||||
return Vertex::BinaryOp<Intern::multiplies>(v0,f);
|
||||
}
|
||||
|
||||
AI_FORCE_INLINE Vertex operator / (const Vertex& v0,float f) {
|
||||
return Vertex::BinaryOp<Intern::divides>(v0,f);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AI_FORCE_INLINE Vertex operator + (float f,const Vertex& v0) {
|
||||
return Vertex::BinaryOp<Intern::plus>(f,v0);
|
||||
}
|
||||
|
||||
AI_FORCE_INLINE Vertex operator - (float f,const Vertex& v0) {
|
||||
return Vertex::BinaryOp<Intern::minus>(f,v0);
|
||||
}
|
||||
|
||||
AI_FORCE_INLINE Vertex operator * (float f,const Vertex& v0) {
|
||||
return Vertex::BinaryOp<Intern::multiplies>(f,v0);
|
||||
}
|
||||
|
||||
AI_FORCE_INLINE Vertex operator / (float f,const Vertex& v0) {
|
||||
return Vertex::BinaryOp<Intern::divides>(f,v0);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
|
@ -39,93 +39,103 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file Implementation of the VertexTriangleAdjacency helper class
|
||||
*/
|
||||
|
||||
/** @file Implementation of the VertexTriangleAdjacency helper class */
|
||||
#include "AssimpPCH.h"
|
||||
|
||||
// internal headers
|
||||
#include "VertexTriangleAdjacency.h"
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Compute a vertex-to-faces adjacency table. To save small memory allocations, the information
|
||||
// is encoded in three continous buffers - the offset table maps a single vertex index to an
|
||||
// entry in the adjacency table, which in turn contains n entries, which are the faces adjacent
|
||||
// to the vertex. n is taken from the third buffer, which stores face counts per vertex.
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
VertexTriangleAdjacency::VertexTriangleAdjacency(aiFace *pcFaces,
|
||||
unsigned int iNumFaces,
|
||||
unsigned int iNumVertices /*= 0*/,
|
||||
bool bComputeNumTriangles /*= false*/)
|
||||
{
|
||||
// compute the number of referenced vertices if it wasn't specified by the caller
|
||||
// ---------------------------------------------------------------------
|
||||
// 0: compute the number of referenced vertices if not
|
||||
// specified by the caller.
|
||||
// ---------------------------------------------------------------------
|
||||
const aiFace* const pcFaceEnd = pcFaces + iNumFaces;
|
||||
if (!iNumVertices) {
|
||||
|
||||
for (aiFace* pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace) {
|
||||
ai_assert(3 == pcFace->mNumIndices);
|
||||
iNumVertices = std::max(iNumVertices,pcFace->mIndices[0]);
|
||||
iNumVertices = std::max(iNumVertices,pcFace->mIndices[1]);
|
||||
iNumVertices = std::max(iNumVertices,pcFace->mIndices[2]);
|
||||
for (unsigned int i = 0; i < pcFace->mNumIndices; ++i) {
|
||||
iNumVertices = std::max(iNumVertices,pcFace->mIndices[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
unsigned int* pi;
|
||||
|
||||
// allocate storage
|
||||
// ---------------------------------------------------------------------
|
||||
// 1. Allocate output storage
|
||||
// ---------------------------------------------------------------------
|
||||
if (bComputeNumTriangles) {
|
||||
pi = mLiveTriangles = new unsigned int[iNumVertices+1];
|
||||
memset(mLiveTriangles,0,sizeof(unsigned int)*(iNumVertices+1));
|
||||
|
||||
mOffsetTable = new unsigned int[iNumVertices+2]+1;
|
||||
}
|
||||
else {
|
||||
pi = mOffsetTable = new unsigned int[iNumVertices+2]+1;
|
||||
memset(mOffsetTable,0,sizeof(unsigned int)*(iNumVertices+1));
|
||||
mLiveTriangles = NULL; // important, otherwise the d'tor would crash
|
||||
// important, otherwise the d'tor would crash
|
||||
mLiveTriangles = NULL;
|
||||
}
|
||||
|
||||
// get a pointer to the end of the buffer
|
||||
unsigned int* piEnd = pi+iNumVertices;
|
||||
*piEnd++ = 0u;
|
||||
|
||||
// first pass: compute the number of faces referencing each vertex
|
||||
for (aiFace* pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace)
|
||||
{
|
||||
pi[pcFace->mIndices[0]]++;
|
||||
pi[pcFace->mIndices[1]]++;
|
||||
pi[pcFace->mIndices[2]]++;
|
||||
// ---------------------------------------------------------------------
|
||||
// 2. Compute the number of faces referencing each vertex
|
||||
// ---------------------------------------------------------------------
|
||||
for (aiFace* pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace) {
|
||||
for (unsigned int i = 0; i < pcFace->mNumIndices; ++i) {
|
||||
pi[pcFace->mIndices[i]]++;
|
||||
}
|
||||
}
|
||||
|
||||
// second pass: compute the final offset table
|
||||
// ---------------------------------------------------------------------
|
||||
// 3. Compute the offset table to map each face to a
|
||||
// start position in the adjacency table.
|
||||
// ---------------------------------------------------------------------
|
||||
unsigned int iSum = 0;
|
||||
unsigned int* piCurOut = this->mOffsetTable;
|
||||
unsigned int* piCurOut = mOffsetTable;
|
||||
for (unsigned int* piCur = pi; piCur != piEnd;++piCur,++piCurOut) {
|
||||
|
||||
unsigned int iLastSum = iSum;
|
||||
iSum += *piCur;
|
||||
*piCurOut = iLastSum;
|
||||
}
|
||||
pi = this->mOffsetTable;
|
||||
pi = mOffsetTable;
|
||||
|
||||
// third pass: compute the final table
|
||||
this->mAdjacencyTable = new unsigned int[iSum];
|
||||
// ---------------------------------------------------------------------
|
||||
// 4. Compute the final adjacency table
|
||||
// ---------------------------------------------------------------------
|
||||
mAdjacencyTable = new unsigned int[iSum];
|
||||
iSum = 0;
|
||||
for (aiFace* pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace,++iSum) {
|
||||
|
||||
unsigned int idx = pcFace->mIndices[0];
|
||||
mAdjacencyTable[pi[idx]++] = iSum;
|
||||
|
||||
idx = pcFace->mIndices[1];
|
||||
mAdjacencyTable[pi[idx]++] = iSum;
|
||||
|
||||
idx = pcFace->mIndices[2];
|
||||
mAdjacencyTable[pi[idx]++] = iSum;
|
||||
for (unsigned int i = 0; i < pcFace->mNumIndices; ++i) {
|
||||
mAdjacencyTable[pi[pcFace->mIndices[i]]++] = iSum;
|
||||
}
|
||||
// fourth pass: undo the offset computations made during the third pass
|
||||
// We could do this in a separate buffer, but this would be TIMES slower.
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// 5. Undo the offset computations made during step 4
|
||||
// ---------------------------------------------------------------------
|
||||
--mOffsetTable;
|
||||
*mOffsetTable = 0u;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
VertexTriangleAdjacency::~VertexTriangleAdjacency()
|
||||
{
|
||||
// delete allocated storage
|
||||
delete[] mOffsetTable;
|
||||
delete[] mAdjacencyTable;
|
||||
delete[] mLiveTriangles;
|
||||
|
|
|
@ -49,54 +49,54 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
struct aiMesh;
|
||||
namespace Assimp {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// --------------------------------------------------------------------------------------------
|
||||
/** @brief The VertexTriangleAdjacency class computes a vertex-triangle
|
||||
* adjacency map from a given index buffer.
|
||||
*
|
||||
* @note The input data is expected to be triangulated.
|
||||
*/
|
||||
* @note Although it is called #VertexTriangleAdjacency, the current version does also
|
||||
* support arbitrary polygons. */
|
||||
// --------------------------------------------------------------------------------------------
|
||||
class ASSIMP_API VertexTriangleAdjacency
|
||||
{
|
||||
public:
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** @brief Construction from an existing index buffer
|
||||
* @param pcFaces Index buffer
|
||||
* @param iNumFaces Number of faces in the buffer
|
||||
* @param iNumVertices Number of referenced vertices. This value
|
||||
* is computed automatically if 0 is specified.
|
||||
* @param bComputeNumTriangles If you want the class to compute
|
||||
* a list which contains the number of referenced triangles
|
||||
* per vertex - pass true.
|
||||
*/
|
||||
* a list containing the number of referenced triangles per vertex
|
||||
* per vertex - pass true. */
|
||||
VertexTriangleAdjacency(aiFace* pcFaces,unsigned int iNumFaces,
|
||||
unsigned int iNumVertices = 0,
|
||||
bool bComputeNumTriangles = true);
|
||||
|
||||
|
||||
/** @brief Destructor
|
||||
*/
|
||||
// ----------------------------------------------------------------------------
|
||||
/** @brief Destructor */
|
||||
~VertexTriangleAdjacency();
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** @brief Get all triangles adjacent to a vertex
|
||||
* @param iVertIndex Index of the vertex
|
||||
* @return A pointer to the adjacency list
|
||||
*/
|
||||
* @return A pointer to the adjacency list. */
|
||||
unsigned int* GetAdjacentTriangles(unsigned int iVertIndex) const
|
||||
{
|
||||
ai_assert(iVertIndex < iNumVertices);
|
||||
|
||||
const unsigned int ofs = mOffsetTable[iVertIndex];
|
||||
return &mAdjacencyTable[ofs];
|
||||
return &mAdjacencyTable[ mOffsetTable[iVertIndex]];
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** @brief Get the number of triangles that are referenced by
|
||||
* a vertex. This function returns a reference that can be modified
|
||||
* @param iVertIndex Index of the vertex
|
||||
* @return Number of referenced triangles
|
||||
*/
|
||||
* @return Number of referenced triangles */
|
||||
unsigned int& GetNumTrianglesPtr(unsigned int iVertIndex)
|
||||
{
|
||||
ai_assert(iVertIndex < iNumVertices && NULL != mLiveTriangles);
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (ASSIMP)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2008, ASSIMP Development Team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the following
|
||||
conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the ASSIMP team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the ASSIMP Development Team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
---------------------------------------------------------------------------
|
||||
*/
|
||||
/** @file aiColor4D.h
|
||||
* @brief RGBA color structure, including operators when compiling in C++
|
||||
*/
|
||||
#ifndef AI_COLOR4D_H_INC
|
||||
#define AI_COLOR4D_H_INC
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "./Compiler/pushpack1.h"
|
||||
// ----------------------------------------------------------------------------------
|
||||
/** Represents a color in Red-Green-Blue space including an
|
||||
* alpha component. Color values range from 0 to 1. */
|
||||
// ----------------------------------------------------------------------------------
|
||||
struct aiColor4D
|
||||
{
|
||||
#ifdef __cplusplus
|
||||
aiColor4D () : r(0.0f), g(0.0f), b(0.0f), a(0.0f) {}
|
||||
aiColor4D (float _r, float _g, float _b, float _a)
|
||||
: r(_r), g(_g), b(_b), a(_a) {}
|
||||
aiColor4D (const aiColor4D& o)
|
||||
: r(o.r), g(o.g), b(o.b), a(o.a) {}
|
||||
|
||||
// combined operators
|
||||
const aiColor4D& operator += (const aiColor4D& o);
|
||||
const aiColor4D& operator -= (const aiColor4D& o);
|
||||
const aiColor4D& operator *= (float f);
|
||||
const aiColor4D& operator /= (float f);
|
||||
|
||||
// comparison
|
||||
bool operator == (const aiColor4D& other) const;
|
||||
bool operator != (const aiColor4D& other) const;
|
||||
|
||||
// color tuple access, rgba order
|
||||
inline float operator[](unsigned int i) const;
|
||||
inline float& operator[](unsigned int i);
|
||||
|
||||
/** check whether a color is (close to) black */
|
||||
inline bool IsBlack() const;
|
||||
|
||||
#endif // !__cplusplus
|
||||
|
||||
// Red, green, blue and alpha color values
|
||||
float r, g, b, a;
|
||||
} PACK_STRUCT; // !struct aiColor4D
|
||||
|
||||
#include "./Compiler/poppack1.h"
|
||||
#ifdef __cplusplus
|
||||
} // end extern "C"
|
||||
|
||||
#endif // __cplusplus
|
||||
#endif // AI_VECTOR3D_H_INC
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (ASSIMP)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2008, ASSIMP Development Team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the following
|
||||
conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the ASSIMP team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the ASSIMP Development Team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file aiColor4D.inl
|
||||
* @brief Inline implementation of aiColor4D operators
|
||||
*/
|
||||
#ifndef AI_COLOR4D_INL_INC
|
||||
#define AI_COLOR4D_INL_INC
|
||||
|
||||
#include "aiColor4D.h"
|
||||
#ifdef __cplusplus
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AI_FORCE_INLINE const aiColor4D& aiColor4D::operator += (const aiColor4D& o) {
|
||||
r += o.r; g += o.g; b += o.b; a += o.a; return *this;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AI_FORCE_INLINE const aiColor4D& aiColor4D::operator -= (const aiColor4D& o) {
|
||||
r -= o.r; g -= o.g; b -= o.b; a -= o.a; return *this;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AI_FORCE_INLINE const aiColor4D& aiColor4D::operator *= (float f) {
|
||||
r *= f; g *= f; b *= f; a *= f; return *this;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AI_FORCE_INLINE const aiColor4D& aiColor4D::operator /= (float f) {
|
||||
r /= f; g /= f; b /= f; a /= f; return *this;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AI_FORCE_INLINE float aiColor4D::operator[](unsigned int i) const {
|
||||
return *(&r + i);
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AI_FORCE_INLINE float& aiColor4D::operator[](unsigned int i) {
|
||||
return *(&r + i);
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AI_FORCE_INLINE bool aiColor4D::operator== (const aiColor4D& other) const {
|
||||
return r == other.r && g == other.g && b == other.b && a == other.a;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AI_FORCE_INLINE bool aiColor4D::operator!= (const aiColor4D& other) const {
|
||||
return r != other.r || g != other.g || b != other.b || a != other.a;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AI_FORCE_INLINE aiColor4D operator + (const aiColor4D& v1, const aiColor4D& v2) {
|
||||
return aiColor4D( v1.r + v2.r, v1.g + v2.g, v1.b + v2.b, v1.a + v2.a);
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AI_FORCE_INLINE aiColor4D operator - (const aiColor4D& v1, const aiColor4D& v2) {
|
||||
return aiColor4D( v1.r - v2.r, v1.g - v2.g, v1.b - v2.b, v1.a - v2.a);
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AI_FORCE_INLINE aiColor4D operator * (const aiColor4D& v1, const aiColor4D& v2) {
|
||||
return aiColor4D( v1.r * v2.r, v1.g * v2.g, v1.b * v2.b, v1.a * v2.a);
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AI_FORCE_INLINE aiColor4D operator / (const aiColor4D& v1, const aiColor4D& v2) {
|
||||
return aiColor4D( v1.r / v2.r, v1.g / v2.g, v1.b / v2.b, v1.a / v2.a);
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AI_FORCE_INLINE aiColor4D operator * ( float f, const aiColor4D& v) {
|
||||
return aiColor4D( f*v.r, f*v.g, f*v.b, f*v.a);
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AI_FORCE_INLINE aiColor4D operator * ( const aiColor4D& v, float f) {
|
||||
return aiColor4D( f*v.r, f*v.g, f*v.b, f*v.a);
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AI_FORCE_INLINE aiColor4D operator / ( const aiColor4D& v, float f) {
|
||||
return v * (1/f);
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AI_FORCE_INLINE aiColor4D operator / ( float f,const aiColor4D& v) {
|
||||
return aiColor4D(f,f,f,f)/v;
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AI_FORCE_INLINE aiColor4D operator + ( const aiColor4D& v, float f) {
|
||||
return aiColor4D( f+v.r, f+v.g, f+v.b, f+v.a);
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AI_FORCE_INLINE aiColor4D operator - ( const aiColor4D& v, float f) {
|
||||
return aiColor4D( v.r-f, v.g-f, v.b-f, v.a-f);
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AI_FORCE_INLINE aiColor4D operator + ( float f, const aiColor4D& v) {
|
||||
return aiColor4D( f+v.r, f+v.g, f+v.b, f+v.a);
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AI_FORCE_INLINE aiColor4D operator - ( float f, const aiColor4D& v) {
|
||||
return aiColor4D( f-v.r, f-v.g, f-v.b, f-v.a);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
inline bool aiColor4D :: IsBlack() const {
|
||||
// The alpha component doesn't care here. black is black.
|
||||
static const float epsilon = 10e-3f;
|
||||
return fabs( r ) < epsilon && fabs( g ) < epsilon && fabs( b ) < epsilon;
|
||||
}
|
||||
|
||||
#endif // __cplusplus
|
||||
#endif // AI_VECTOR3D_INL_INC
|
|
@ -428,6 +428,17 @@ enum aiComponent
|
|||
#define AI_CONFIG_IMPORT_AC_SEPARATE_BFCULL \
|
||||
"IMPORT_AC_SEPARATE_BFCULL"
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** @brief Configures whether the AC loader evaluates subdivision surfaces (
|
||||
* indicated by the presence of the 'subdiv' attribute in the file). By
|
||||
* default, Assimp performs the subdivision using the standard
|
||||
* Catmull-Clark algorithm
|
||||
*
|
||||
* Property type: integer (0: false; !0: true). Default value: true.
|
||||
*/
|
||||
#define AI_CONFIG_IMPORT_AC_EVAL_SUBDIVISION \
|
||||
"IMPORT_AC_EVAL_SUBDIVISION"
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** @brief Configures the UNREAL 3D loader to separate faces with different
|
||||
* surface flags (e.g. two-sided vs. single-sided).
|
||||
|
|
|
@ -57,6 +57,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
// Some types moved to separate header due to size of operators
|
||||
#include "aiVector3D.h"
|
||||
#include "aiVector2D.h"
|
||||
#include "aiColor4D.h"
|
||||
#include "aiMatrix3x3.h"
|
||||
#include "aiMatrix4x4.h"
|
||||
#include "aiQuaternion.h"
|
||||
|
@ -205,55 +206,6 @@ struct aiColor3D
|
|||
//! Red, green and blue color values
|
||||
float r, g, b;
|
||||
} PACK_STRUCT; // !struct aiColor3D
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
/** Represents a color in Red-Green-Blue space including an
|
||||
* alpha component.
|
||||
*/
|
||||
struct aiColor4D
|
||||
{
|
||||
#ifdef __cplusplus
|
||||
aiColor4D () : r(0.0f), g(0.0f), b(0.0f), a(0.0f) {}
|
||||
aiColor4D (float _r, float _g, float _b, float _a)
|
||||
: r(_r), g(_g), b(_b), a(_a) {}
|
||||
aiColor4D (const aiColor4D& o)
|
||||
: r(o.r), g(o.g), b(o.b), a(o.a) {}
|
||||
|
||||
/** Component-wise comparison */
|
||||
// TODO: add epsilon?
|
||||
bool operator == (const aiColor4D& other) const {
|
||||
return r == other.r && g == other.g && b == other.b && a == other.a;
|
||||
}
|
||||
|
||||
/** Component-wise inverse comparison */
|
||||
// TODO: add epsilon?
|
||||
bool operator != (const aiColor4D& other) const {
|
||||
return r != other.r || g != other.g || b != other.b || a != other.a;
|
||||
}
|
||||
|
||||
/** Access a specific color component */
|
||||
inline float operator[](unsigned int i) const {
|
||||
return *(&r + i);
|
||||
}
|
||||
/** Access a specific color component */
|
||||
inline float& operator[](unsigned int i) {
|
||||
return *(&r + i);
|
||||
}
|
||||
|
||||
/** Check whether a color is black */
|
||||
inline bool IsBlack() const
|
||||
{
|
||||
// The alpha component doesn't care here. black is black.
|
||||
static const float epsilon = 10e-3f;
|
||||
return fabs( r ) < epsilon && fabs( g ) < epsilon && fabs( b ) < epsilon;
|
||||
}
|
||||
|
||||
#endif // !__cplusplus
|
||||
|
||||
//! Red, green, blue and alpha color values
|
||||
float r, g, b, a;
|
||||
} PACK_STRUCT; // !struct aiColor4D
|
||||
#include "./Compiler/poppack1.h"
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
@ -524,6 +476,7 @@ struct aiMemoryInfo
|
|||
|
||||
// Include implementations
|
||||
#include "aiVector3D.inl"
|
||||
#include "aiColor4D.inl"
|
||||
#include "aiMatrix3x3.inl"
|
||||
#include "aiMatrix4x4.inl"
|
||||
#endif //!! include guard
|
||||
#endif
|
||||
|
|
|
@ -90,32 +90,27 @@ public:
|
|||
/** @brief Set the components of a vector
|
||||
* @param pX X component
|
||||
* @param pY Y component
|
||||
* @param pZ Z component
|
||||
*/
|
||||
* @param pZ Z component */
|
||||
void Set( float pX, float pY, float pZ = 0.f);
|
||||
|
||||
/** @brief Get the squared length of the vector
|
||||
* @return Square length
|
||||
*/
|
||||
* @return Square length */
|
||||
float SquareLength() const;
|
||||
|
||||
|
||||
/** @brief Get the length of the vector
|
||||
* @return length
|
||||
*/
|
||||
* @return length */
|
||||
float Length() const;
|
||||
|
||||
|
||||
/** @brief Normalize the vector
|
||||
*/
|
||||
/** @brief Normalize the vector */
|
||||
aiVector3D& Normalize();
|
||||
|
||||
|
||||
/** @brief Componentwise multiplication of two vectors
|
||||
*
|
||||
* Note that vec*vec yields the dot product.
|
||||
* @param o Second factor
|
||||
*/
|
||||
* @param o Second factor */
|
||||
const aiVector3D SymMul(const aiVector3D& o);
|
||||
|
||||
#endif // __cplusplus
|
||||
|
|
|
@ -46,7 +46,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#define AI_VECTOR3D_INL_INC
|
||||
|
||||
#include "aiVector3D.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
|
|
@ -1 +1 @@
|
|||
#define SVNRevision 501
|
||||
#define SVNRevision 526
|
||||
|
|
|
@ -8,6 +8,7 @@ loc 0.000424567 -0.0127304 0
|
|||
kids 0
|
||||
OBJECT poly
|
||||
name "sphere"
|
||||
subdiv 3
|
||||
loc -0.0624103 -0.012381 0.0558408
|
||||
texture "./../LWO/LWO2/MappingModes/earthSpherical.jpg"
|
||||
crease 45.000000
|
||||
|
|
|
@ -8,6 +8,7 @@ loc 0.000424567 -0.0127304 0
|
|||
kids 0
|
||||
OBJECT poly
|
||||
name "sphere"
|
||||
subdiv 4
|
||||
loc -0.0624103 -0.012381 0.0558408
|
||||
texture "./../LWO/LWO2/MappingModes/earthSpherical.jpg"
|
||||
texrep 1.9 2.5
|
||||
|
|
|
@ -0,0 +1,266 @@
|
|||
AC3Db
|
||||
MATERIAL "ac3dmat1" rgb 1 1 1 amb 0.2 0.2 0.2 emis 0 0 0 spec 0.2 0.2 0.2 shi 128 trans 0
|
||||
OBJECT world
|
||||
kids 1
|
||||
OBJECT poly
|
||||
name "cylinder"
|
||||
loc 0.08 0.0994955 -0.103419
|
||||
crease 45.000000
|
||||
subdiv 6
|
||||
numvert 26
|
||||
-1.11759e-007 -5.96046e-008 1.4975
|
||||
-1.11759e-007 -5.96046e-008 -1.4975
|
||||
0.76 -5.36442e-007 1.4975
|
||||
0.658179 -0.3625 1.4975
|
||||
0.38 -0.627869 1.4975
|
||||
-3.50177e-007 -0.725 1.4975
|
||||
-0.38 -0.627868 1.4975
|
||||
-0.658179 -0.3625 1.4975
|
||||
-0.76 1.19209e-007 1.4975
|
||||
-0.658179 0.3625 1.4975
|
||||
-0.38 0.627868 1.4975
|
||||
-2.98023e-008 0.725 1.4975
|
||||
0.38 0.627868 1.4975
|
||||
0.658179 0.3625 1.4975
|
||||
0.76 -5.36442e-007 -1.4975
|
||||
0.658179 -0.3625 -1.4975
|
||||
0.38 -0.627869 -1.4975
|
||||
-3.50177e-007 -0.725 -1.4975
|
||||
-0.38 -0.627868 -1.4975
|
||||
-0.658179 -0.3625 -1.4975
|
||||
-0.76 1.19209e-007 -1.4975
|
||||
-0.658179 0.3625 -1.4975
|
||||
-0.38 0.627868 -1.4975
|
||||
-2.98023e-008 0.725 -1.4975
|
||||
0.38 0.627868 -1.4975
|
||||
0.658179 0.3625 -1.4975
|
||||
numsurf 36
|
||||
SURF 0x10
|
||||
mat 0
|
||||
refs 3
|
||||
0 0 0
|
||||
2 0 0
|
||||
13 0 0
|
||||
SURF 0x10
|
||||
mat 0
|
||||
refs 3
|
||||
0 0 0
|
||||
3 0 0
|
||||
2 0 0
|
||||
SURF 0x10
|
||||
mat 0
|
||||
refs 3
|
||||
0 0 0
|
||||
4 0 0
|
||||
3 0 0
|
||||
SURF 0x10
|
||||
mat 0
|
||||
refs 3
|
||||
0 0 0
|
||||
5 0 0
|
||||
4 0 0
|
||||
SURF 0x10
|
||||
mat 0
|
||||
refs 3
|
||||
0 0 0
|
||||
6 0 0
|
||||
5 0 0
|
||||
SURF 0x10
|
||||
mat 0
|
||||
refs 3
|
||||
0 0 0
|
||||
7 0 0
|
||||
6 0 0
|
||||
SURF 0x10
|
||||
mat 0
|
||||
refs 3
|
||||
0 0 0
|
||||
8 0 0
|
||||
7 0 0
|
||||
SURF 0x10
|
||||
mat 0
|
||||
refs 3
|
||||
0 0 0
|
||||
9 0 0
|
||||
8 0 0
|
||||
SURF 0x10
|
||||
mat 0
|
||||
refs 3
|
||||
0 0 0
|
||||
10 0 0
|
||||
9 0 0
|
||||
SURF 0x10
|
||||
mat 0
|
||||
refs 3
|
||||
0 0 0
|
||||
11 0 0
|
||||
10 0 0
|
||||
SURF 0x10
|
||||
mat 0
|
||||
refs 3
|
||||
0 0 0
|
||||
12 0 0
|
||||
11 0 0
|
||||
SURF 0x10
|
||||
mat 0
|
||||
refs 3
|
||||
0 0 0
|
||||
13 0 0
|
||||
12 0 0
|
||||
SURF 0x10
|
||||
mat 0
|
||||
refs 3
|
||||
1 0 0
|
||||
25 0 0
|
||||
14 0 0
|
||||
SURF 0x10
|
||||
mat 0
|
||||
refs 3
|
||||
1 0 0
|
||||
14 0 0
|
||||
15 0 0
|
||||
SURF 0x10
|
||||
mat 0
|
||||
refs 3
|
||||
1 0 0
|
||||
15 0 0
|
||||
16 0 0
|
||||
SURF 0x10
|
||||
mat 0
|
||||
refs 3
|
||||
1 0 0
|
||||
16 0 0
|
||||
17 0 0
|
||||
SURF 0x10
|
||||
mat 0
|
||||
refs 3
|
||||
1 0 0
|
||||
17 0 0
|
||||
18 0 0
|
||||
SURF 0x10
|
||||
mat 0
|
||||
refs 3
|
||||
1 0 0
|
||||
18 0 0
|
||||
19 0 0
|
||||
SURF 0x10
|
||||
mat 0
|
||||
refs 3
|
||||
1 0 0
|
||||
19 0 0
|
||||
20 0 0
|
||||
SURF 0x10
|
||||
mat 0
|
||||
refs 3
|
||||
1 0 0
|
||||
20 0 0
|
||||
21 0 0
|
||||
SURF 0x10
|
||||
mat 0
|
||||
refs 3
|
||||
1 0 0
|
||||
21 0 0
|
||||
22 0 0
|
||||
SURF 0x10
|
||||
mat 0
|
||||
refs 3
|
||||
1 0 0
|
||||
22 0 0
|
||||
23 0 0
|
||||
SURF 0x10
|
||||
mat 0
|
||||
refs 3
|
||||
1 0 0
|
||||
23 0 0
|
||||
24 0 0
|
||||
SURF 0x10
|
||||
mat 0
|
||||
refs 3
|
||||
1 0 0
|
||||
24 0 0
|
||||
25 0 0
|
||||
SURF 0x10
|
||||
mat 0
|
||||
refs 4
|
||||
25 0 1
|
||||
13 0 0
|
||||
2 0.0833333 0
|
||||
14 0.0833333 1
|
||||
SURF 0x10
|
||||
mat 0
|
||||
refs 4
|
||||
14 0.0833333 1
|
||||
2 0.0833333 0
|
||||
3 0.166667 0
|
||||
15 0.166667 1
|
||||
SURF 0x10
|
||||
mat 0
|
||||
refs 4
|
||||
15 0.166667 1
|
||||
3 0.166667 0
|
||||
4 0.25 0
|
||||
16 0.25 1
|
||||
SURF 0x10
|
||||
mat 0
|
||||
refs 4
|
||||
16 0.25 1
|
||||
4 0.25 0
|
||||
5 0.333333 0
|
||||
17 0.333333 1
|
||||
SURF 0x10
|
||||
mat 0
|
||||
refs 4
|
||||
17 0.333333 1
|
||||
5 0.333333 0
|
||||
6 0.416667 0
|
||||
18 0.416667 1
|
||||
SURF 0x10
|
||||
mat 0
|
||||
refs 4
|
||||
18 0.416667 1
|
||||
6 0.416667 0
|
||||
7 0.5 0
|
||||
19 0.5 1
|
||||
SURF 0x10
|
||||
mat 0
|
||||
refs 4
|
||||
19 0.5 1
|
||||
7 0.5 0
|
||||
8 0.583333 0
|
||||
20 0.583333 1
|
||||
SURF 0x10
|
||||
mat 0
|
||||
refs 4
|
||||
20 0.583333 1
|
||||
8 0.583333 0
|
||||
9 0.666667 0
|
||||
21 0.666667 1
|
||||
SURF 0x10
|
||||
mat 0
|
||||
refs 4
|
||||
21 0.666667 1
|
||||
9 0.666667 0
|
||||
10 0.75 0
|
||||
22 0.75 1
|
||||
SURF 0x10
|
||||
mat 0
|
||||
refs 4
|
||||
22 0.75 1
|
||||
10 0.75 0
|
||||
11 0.833333 0
|
||||
23 0.833333 1
|
||||
SURF 0x10
|
||||
mat 0
|
||||
refs 4
|
||||
23 0.833333 1
|
||||
11 0.833333 0
|
||||
12 0.916667 0
|
||||
24 0.916667 1
|
||||
SURF 0x10
|
||||
mat 0
|
||||
refs 4
|
||||
24 0.916667 1
|
||||
12 0.916667 0
|
||||
13 1 0
|
||||
25 1 1
|
||||
kids 0
|
|
@ -2,7 +2,6 @@
|
|||
#include "UnitTestPCH.h"
|
||||
#include "utJoinVertices.h"
|
||||
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION (JoinVerticesTest);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -87,3 +86,4 @@ void JoinVerticesTest :: testProcess(void)
|
|||
}
|
||||
CPPUNIT_ASSERT(fSum == 150.f*299.f*3.f); // gaussian sum equation
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
using namespace std;
|
||||
using namespace Assimp;
|
||||
|
||||
namespace Assimp {
|
||||
class JoinVerticesTest : public CPPUNIT_NS :: TestFixture
|
||||
{
|
||||
CPPUNIT_TEST_SUITE (JoinVerticesTest);
|
||||
|
@ -32,5 +32,5 @@ class JoinVerticesTest : public CPPUNIT_NS :: TestFixture
|
|||
aiMesh* pcMesh;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -818,7 +818,7 @@ std::string g_szMaterialShader = std::string(
|
|||
"#endif \n"
|
||||
"float3 ViewDir = normalize(IN.ViewDir);\n"
|
||||
"#ifdef AV_SPECULAR_COMPONENT\n"
|
||||
"float3 Reflect = -normalize(reflect (ViewDir,Normal));\n"
|
||||
"float3 Reflect = normalize(reflect (-ViewDir,Normal));\n"
|
||||
"#endif // !AV_SPECULAR_COMPONENT\n"
|
||||
|
||||
"{\n"
|
||||
|
|
|
@ -1097,6 +1097,8 @@ int CreateDevice (bool p_bMultiSample,bool p_bSuperSample,bool bHW /*= true*/)
|
|||
if( g_sCaps.PixelShaderVersion < D3DPS_VERSION(2,0))
|
||||
g_piNormalsEffect->SetTechnique( "RenderNormals_FF");
|
||||
|
||||
g_piDevice->SetRenderState(D3DRS_DITHERENABLE,TRUE);
|
||||
|
||||
// create the texture for the HUD
|
||||
CreateHUDTexture();
|
||||
CBackgroundPainter::Instance().RecreateNativeResource();
|
||||
|
|
|
@ -493,6 +493,7 @@
|
|||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
OutputFile="$(OutDir)\Assimp32d.dll"
|
||||
GenerateDebugInformation="true"
|
||||
ImportLibrary="$(SolutionDir)..\..\lib\$(ProjectName)_$(ConfigurationName)_$(PlatformName)\assimp.lib"
|
||||
/>
|
||||
<Tool
|
||||
|
@ -1259,6 +1260,14 @@
|
|||
RelativePath="..\..\include\aiCamera.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\include\aiColor4D.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\include\aiColor4D.inl"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\include\aiConfig.h"
|
||||
>
|
||||
|
@ -2367,6 +2376,10 @@
|
|||
RelativePath="..\..\code\StringComparison.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\code\Vertex.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="extern"
|
||||
|
@ -3571,6 +3584,14 @@
|
|||
RelativePath="..\..\code\StandardShapes.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\code\Subdivision.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\code\Subdivision.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\code\TargetAnimation.cpp"
|
||||
>
|
||||
|
|
|
@ -2403,6 +2403,14 @@
|
|||
RelativePath="..\..\code\StandardShapes.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\code\Subdivision.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\code\Subdivision.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\code\TargetAnimation.cpp"
|
||||
>
|
||||
|
@ -3535,6 +3543,10 @@
|
|||
RelativePath="..\..\code\StringComparison.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\code\Vertex.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Filter>
|
||||
<Filter
|
||||
|
|
Loading…
Reference in New Issue