- Bugfix: ColladaLoader node rotation was miscalculated
- ColladaLoader now supports more primitive types - ColladaLoader now honours the up-vector specification - moved Collada temporary structures to separate Helper header - fast_atof_move() now also eats localized numbers with comma separator (e.g. 0,3210) correctly git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@251 67173fc5-114c-0410-ac8e-9d2fd5bffc1fpull/1/head
parent
edc8eda808
commit
85a487f6b8
|
@ -0,0 +1,172 @@
|
||||||
|
/** Helper structures for the Collada loader */
|
||||||
|
|
||||||
|
/*
|
||||||
|
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.
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef AI_COLLADAHELPER_H_INC
|
||||||
|
#define AI_COLLADAHELPER_H_INC
|
||||||
|
|
||||||
|
namespace Assimp
|
||||||
|
{
|
||||||
|
namespace Collada
|
||||||
|
{
|
||||||
|
|
||||||
|
/** Transformation types that can be applied to a node */
|
||||||
|
enum TransformType
|
||||||
|
{
|
||||||
|
TF_LOOKAT,
|
||||||
|
TF_ROTATE,
|
||||||
|
TF_TRANSLATE,
|
||||||
|
TF_SCALE,
|
||||||
|
TF_SKEW,
|
||||||
|
TF_MATRIX
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Contains all data for one of the different transformation types */
|
||||||
|
struct Transform
|
||||||
|
{
|
||||||
|
TransformType mType;
|
||||||
|
float f[16]; ///< Interpretation of data depends on the type of the transformation
|
||||||
|
};
|
||||||
|
|
||||||
|
/** A node in a scene hierarchy */
|
||||||
|
struct Node
|
||||||
|
{
|
||||||
|
std::string mName;
|
||||||
|
std::string mID;
|
||||||
|
Node* mParent;
|
||||||
|
std::vector<Node*> mChildren;
|
||||||
|
|
||||||
|
/** Operations in order to calculate the resulting transformation to parent. */
|
||||||
|
std::vector<Transform> mTransforms;
|
||||||
|
|
||||||
|
std::vector<std::string> mMeshes; ///< Meshes at this node
|
||||||
|
|
||||||
|
Node() { mParent = NULL; }
|
||||||
|
~Node() { for( std::vector<Node*>::iterator it = mChildren.begin(); it != mChildren.end(); ++it) delete *it; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Data source array */
|
||||||
|
struct Data
|
||||||
|
{
|
||||||
|
std::vector<float> mValues;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Accessor to a data array */
|
||||||
|
struct Accessor
|
||||||
|
{
|
||||||
|
size_t mCount; // in number of objects
|
||||||
|
size_t mOffset; // in number of values
|
||||||
|
size_t mStride; // Stride in number of values
|
||||||
|
std::vector<std::string> mParams; // names of the data streams in the accessors. Empty string tells to ignore.
|
||||||
|
size_t mSubOffset[4]; // Suboffset inside the object for the common 4 elements. For a vector, thats XYZ, for a color RGBA and so on.
|
||||||
|
// For example, SubOffset[0] denotes which of the values inside the object is the vector X component.
|
||||||
|
std::string mSource; // URL of the source array
|
||||||
|
mutable const Data* mData; // Pointer to the source array, if resolved. NULL else
|
||||||
|
|
||||||
|
Accessor()
|
||||||
|
{
|
||||||
|
mCount = 0; mOffset = 0; mStride = 0; mData = NULL;
|
||||||
|
mSubOffset[0] = mSubOffset[1] = mSubOffset[2] = mSubOffset[3] = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** A single face in a mesh */
|
||||||
|
struct Face
|
||||||
|
{
|
||||||
|
std::vector<size_t> mIndices;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Different types of input data to a vertex or face */
|
||||||
|
enum InputType
|
||||||
|
{
|
||||||
|
IT_Invalid,
|
||||||
|
IT_Vertex, // special type for per-index data referring to the <vertices> element carrying the per-vertex data.
|
||||||
|
IT_Position,
|
||||||
|
IT_Normal,
|
||||||
|
IT_Texcoord,
|
||||||
|
IT_Color
|
||||||
|
};
|
||||||
|
|
||||||
|
/** An input channel for mesh data, referring to a single accessor */
|
||||||
|
struct InputChannel
|
||||||
|
{
|
||||||
|
InputType mType; // Type of the data
|
||||||
|
size_t mIndex; // Optional index, if multiple sets of the same data type are given
|
||||||
|
size_t mOffset; // Index offset in the indices array of per-face indices. Don't ask, can't explain that any better.
|
||||||
|
std::string mAccessor; // ID of the accessor where to read the actual values from.
|
||||||
|
mutable const Accessor* mResolved; // Pointer to the accessor, if resolved. NULL else
|
||||||
|
|
||||||
|
InputChannel() { mType = IT_Invalid; mIndex = 0; mOffset = 0; mResolved = NULL; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Contains data for a single mesh */
|
||||||
|
struct Mesh
|
||||||
|
{
|
||||||
|
std::string mVertexID; // just to check if there's some sophisticated addressing involved... which we don't support, and therefore should warn about.
|
||||||
|
std::vector<InputChannel> mPerVertexData; // Vertex data addressed by vertex indices
|
||||||
|
|
||||||
|
// actual mesh data, assembled on encounter of a <p> element. Verbose format, not indexed
|
||||||
|
std::vector<aiVector3D> mPositions;
|
||||||
|
std::vector<aiVector3D> mNormals;
|
||||||
|
std::vector<aiVector2D> mTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS];
|
||||||
|
std::vector<aiColor4D> mColors[AI_MAX_NUMBER_OF_COLOR_SETS];
|
||||||
|
|
||||||
|
// Faces. Stored are only the number of vertices for each face. 1 == point, 2 == line, 3 == triangle, 4+ == poly
|
||||||
|
std::vector<size_t> mFaceSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Which type of primitives the ReadPrimitives() function is going to read */
|
||||||
|
enum PrimitiveType
|
||||||
|
{
|
||||||
|
Prim_Invalid,
|
||||||
|
Prim_Lines,
|
||||||
|
Prim_LineStrip,
|
||||||
|
Prim_Triangles,
|
||||||
|
Prim_TriStrips,
|
||||||
|
Prim_TriFans,
|
||||||
|
Prim_Polylist,
|
||||||
|
Prim_Polygon
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end of namespace Collada
|
||||||
|
} // end of namespace Assimp
|
||||||
|
|
||||||
|
#endif // AI_COLLADAHELPER_H_INC
|
|
@ -90,6 +90,21 @@ void ColladaLoader::InternReadFile( const std::string& pFile, aiScene* pScene, I
|
||||||
// build the node hierarchy from it
|
// build the node hierarchy from it
|
||||||
pScene->mRootNode = BuildHierarchy( parser, parser.mRootNode);
|
pScene->mRootNode = BuildHierarchy( parser, parser.mRootNode);
|
||||||
|
|
||||||
|
// Convert to Z_UP, if different orientation
|
||||||
|
if( parser.mUpDirection == ColladaParser::UP_X)
|
||||||
|
pScene->mRootNode->mTransformation *= aiMatrix4x4(
|
||||||
|
0, -1, 0, 0,
|
||||||
|
0, 0, -1, 0,
|
||||||
|
1, 0, 0, 0,
|
||||||
|
0, 0, 0, 1);
|
||||||
|
else if( parser.mUpDirection == ColladaParser::UP_Y)
|
||||||
|
pScene->mRootNode->mTransformation *= aiMatrix4x4(
|
||||||
|
1, 0, 0, 0,
|
||||||
|
0, 0, -1, 0,
|
||||||
|
0, 1, 0, 0,
|
||||||
|
0, 0, 0, 1);
|
||||||
|
|
||||||
|
|
||||||
// store all meshes
|
// store all meshes
|
||||||
StoreSceneMeshes( pScene);
|
StoreSceneMeshes( pScene);
|
||||||
|
|
||||||
|
@ -113,7 +128,7 @@ void ColladaLoader::InternReadFile( const std::string& pFile, aiScene* pScene, I
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Recursively constructs a scene node for the given parser node and returns it.
|
// Recursively constructs a scene node for the given parser node and returns it.
|
||||||
aiNode* ColladaLoader::BuildHierarchy( const ColladaParser& pParser, const ColladaParser::Node* pNode)
|
aiNode* ColladaLoader::BuildHierarchy( const ColladaParser& pParser, const Collada::Node* pNode)
|
||||||
{
|
{
|
||||||
// create a node for it
|
// create a node for it
|
||||||
aiNode* node = new aiNode( pNode->mName);
|
aiNode* node = new aiNode( pNode->mName);
|
||||||
|
@ -138,7 +153,7 @@ aiNode* ColladaLoader::BuildHierarchy( const ColladaParser& pParser, const Colla
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Builds meshes for the given node and references them
|
// Builds meshes for the given node and references them
|
||||||
void ColladaLoader::BuildMeshesForNode( const ColladaParser& pParser, const ColladaParser::Node* pNode, aiNode* pTarget)
|
void ColladaLoader::BuildMeshesForNode( const ColladaParser& pParser, const Collada::Node* pNode, aiNode* pTarget)
|
||||||
{
|
{
|
||||||
// accumulated mesh references by this node
|
// accumulated mesh references by this node
|
||||||
std::vector<size_t> newMeshRefs;
|
std::vector<size_t> newMeshRefs;
|
||||||
|
@ -163,7 +178,7 @@ void ColladaLoader::BuildMeshesForNode( const ColladaParser& pParser, const Coll
|
||||||
{
|
{
|
||||||
// else we have to add the mesh to the collection and store its newly assigned index at the node
|
// else we have to add the mesh to the collection and store its newly assigned index at the node
|
||||||
aiMesh* dstMesh = new aiMesh;
|
aiMesh* dstMesh = new aiMesh;
|
||||||
const ColladaParser::Mesh* srcMesh = srcMeshIt->second;
|
const Collada::Mesh* srcMesh = srcMeshIt->second;
|
||||||
|
|
||||||
// copy positions
|
// copy positions
|
||||||
dstMesh->mNumVertices = srcMesh->mPositions.size();
|
dstMesh->mNumVertices = srcMesh->mPositions.size();
|
||||||
|
|
|
@ -83,10 +83,10 @@ protected:
|
||||||
void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler);
|
void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler);
|
||||||
|
|
||||||
/** Recursively constructs a scene node for the given parser node and returns it. */
|
/** Recursively constructs a scene node for the given parser node and returns it. */
|
||||||
aiNode* BuildHierarchy( const ColladaParser& pParser, const ColladaParser::Node* pNode);
|
aiNode* BuildHierarchy( const ColladaParser& pParser, const Collada::Node* pNode);
|
||||||
|
|
||||||
/** Builds meshes for the given node and references them */
|
/** Builds meshes for the given node and references them */
|
||||||
void BuildMeshesForNode( const ColladaParser& pParser, const ColladaParser::Node* pNode, aiNode* pTarget);
|
void BuildMeshesForNode( const ColladaParser& pParser, const Collada::Node* pNode, aiNode* pTarget);
|
||||||
|
|
||||||
/** Stores all meshes in the given scene */
|
/** Stores all meshes in the given scene */
|
||||||
void StoreSceneMeshes( aiScene* pScene);
|
void StoreSceneMeshes( aiScene* pScene);
|
||||||
|
|
|
@ -46,6 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "ParsingUtils.h"
|
#include "ParsingUtils.h"
|
||||||
|
|
||||||
using namespace Assimp;
|
using namespace Assimp;
|
||||||
|
using namespace Assimp::Collada;
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Constructor to be privately used by Importer
|
// Constructor to be privately used by Importer
|
||||||
|
@ -253,7 +254,8 @@ void ColladaParser::ReadMesh( Mesh* pMesh)
|
||||||
// read per-vertex mesh data
|
// read per-vertex mesh data
|
||||||
ReadVertexData( pMesh);
|
ReadVertexData( pMesh);
|
||||||
}
|
}
|
||||||
else if( IsElement( "polylist") || IsElement( "triangles"))
|
else if( IsElement( "triangles") || IsElement( "lines") || IsElement( "linestrips")
|
||||||
|
|| IsElement( "polygons") || IsElement( "polylist") || IsElement( "trifans") || IsElement( "tristrips"))
|
||||||
{
|
{
|
||||||
// read per-index mesh data and faces setup
|
// read per-index mesh data and faces setup
|
||||||
ReadIndexData( pMesh);
|
ReadIndexData( pMesh);
|
||||||
|
@ -438,7 +440,23 @@ void ColladaParser::ReadIndexData( Mesh* pMesh)
|
||||||
|
|
||||||
// distinguish between polys and triangles
|
// distinguish between polys and triangles
|
||||||
std::string elementName = mReader->getNodeName();
|
std::string elementName = mReader->getNodeName();
|
||||||
bool isPolylist = IsElement( "polylist");
|
PrimitiveType primType = Prim_Invalid;
|
||||||
|
if( IsElement( "lines"))
|
||||||
|
primType = Prim_Lines;
|
||||||
|
else if( IsElement( "linestrips"))
|
||||||
|
primType = Prim_LineStrip;
|
||||||
|
else if( IsElement( "polygons"))
|
||||||
|
primType = Prim_Polygon;
|
||||||
|
else if( IsElement( "polylist"))
|
||||||
|
primType = Prim_Polylist;
|
||||||
|
else if( IsElement( "triangles"))
|
||||||
|
primType = Prim_Triangles;
|
||||||
|
else if( IsElement( "trifans"))
|
||||||
|
primType = Prim_TriFans;
|
||||||
|
else if( IsElement( "tristrips"))
|
||||||
|
primType = Prim_TriStrips;
|
||||||
|
|
||||||
|
assert( primType != Prim_Invalid);
|
||||||
|
|
||||||
// also a number of <input> elements, but in addition a <p> primitive collection and propably index counts for all primitives
|
// also a number of <input> elements, but in addition a <p> primitive collection and propably index counts for all primitives
|
||||||
while( mReader->read())
|
while( mReader->read())
|
||||||
|
@ -469,7 +487,7 @@ void ColladaParser::ReadIndexData( Mesh* pMesh)
|
||||||
else if( IsElement( "p"))
|
else if( IsElement( "p"))
|
||||||
{
|
{
|
||||||
// now here the actual fun starts - these are the indices to construct the mesh data from
|
// now here the actual fun starts - these are the indices to construct the mesh data from
|
||||||
ReadPrimitives( pMesh, perIndexData, numPrimitives, vcount, isPolylist);
|
ReadPrimitives( pMesh, perIndexData, numPrimitives, vcount, primType);
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
ThrowException( "Unexpected sub element in tag \"vertices\".");
|
ThrowException( "Unexpected sub element in tag \"vertices\".");
|
||||||
|
@ -519,7 +537,7 @@ void ColladaParser::ReadInputChannel( std::vector<InputChannel>& poChannels)
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Reads a <p> primitive index list and assembles the mesh data into the given mesh
|
// Reads a <p> primitive index list and assembles the mesh data into the given mesh
|
||||||
void ColladaParser::ReadPrimitives( Mesh* pMesh, std::vector<InputChannel>& pPerIndexChannels,
|
void ColladaParser::ReadPrimitives( Mesh* pMesh, std::vector<InputChannel>& pPerIndexChannels,
|
||||||
size_t pNumPrimitives, const std::vector<size_t>& pVCount, bool pIsPolylist)
|
size_t pNumPrimitives, const std::vector<size_t>& pVCount, PrimitiveType pPrimType)
|
||||||
{
|
{
|
||||||
// determine number of indices coming per vertex
|
// determine number of indices coming per vertex
|
||||||
// find the offset index for all per-vertex channels
|
// find the offset index for all per-vertex channels
|
||||||
|
@ -534,32 +552,52 @@ void ColladaParser::ReadPrimitives( Mesh* pMesh, std::vector<InputChannel>& pPer
|
||||||
|
|
||||||
// determine the expected number of indices
|
// determine the expected number of indices
|
||||||
size_t expectedPointCount = 0;
|
size_t expectedPointCount = 0;
|
||||||
if( pIsPolylist)
|
switch( pPrimType)
|
||||||
{
|
{
|
||||||
BOOST_FOREACH( size_t i, pVCount)
|
case Prim_Polylist:
|
||||||
expectedPointCount += i;
|
{
|
||||||
} else
|
BOOST_FOREACH( size_t i, pVCount)
|
||||||
{
|
expectedPointCount += i;
|
||||||
// everything triangles
|
break;
|
||||||
expectedPointCount = 3 * pNumPrimitives;
|
}
|
||||||
|
case Prim_Lines:
|
||||||
|
expectedPointCount = 2 * pNumPrimitives;
|
||||||
|
break;
|
||||||
|
case Prim_Triangles:
|
||||||
|
expectedPointCount = 3 * pNumPrimitives;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// other primitive types don't state the index count upfront... we need to guess
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// and read all indices into a temporary array
|
// and read all indices into a temporary array
|
||||||
std::vector<size_t> indices( expectedPointCount * numOffsets);
|
std::vector<size_t> indices;
|
||||||
|
if( expectedPointCount > 0)
|
||||||
|
indices.reserve( expectedPointCount * numOffsets);
|
||||||
|
|
||||||
const char* content = GetTextContent();
|
const char* content = GetTextContent();
|
||||||
BOOST_FOREACH( size_t& value, indices)
|
while( *content != 0)
|
||||||
{
|
{
|
||||||
if( *content == 0)
|
// read a value
|
||||||
ThrowException( "Expected more values while reading primitive indices.");
|
unsigned int value = strtol10( content, &content);
|
||||||
// read a value in place
|
indices.push_back( size_t( value));
|
||||||
value = strtol10( content, &content);
|
|
||||||
// skip whitespace after it
|
// skip whitespace after it
|
||||||
SkipSpacesAndLineEnd( &content);
|
SkipSpacesAndLineEnd( &content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// complain if the index count doesn't fit
|
||||||
|
if( expectedPointCount > 0 && indices.size() != expectedPointCount * numOffsets)
|
||||||
|
ThrowException( "Expected different index count in <p> element.");
|
||||||
|
else if( expectedPointCount == 0 && (indices.size() % numOffsets) != 0)
|
||||||
|
ThrowException( "Expected different index count in <p> element.");
|
||||||
|
|
||||||
// find the data for all sources
|
// find the data for all sources
|
||||||
BOOST_FOREACH( InputChannel& input, pMesh->mPerVertexData)
|
BOOST_FOREACH( InputChannel& input, pMesh->mPerVertexData)
|
||||||
{
|
{
|
||||||
|
if( input.mResolved)
|
||||||
|
continue;
|
||||||
|
|
||||||
// find accessor
|
// find accessor
|
||||||
input.mResolved = &ResolveLibraryReference( mAccessorLibrary, input.mAccessor);
|
input.mResolved = &ResolveLibraryReference( mAccessorLibrary, input.mAccessor);
|
||||||
// resolve accessor's data pointer as well, if neccessary
|
// resolve accessor's data pointer as well, if neccessary
|
||||||
|
@ -570,6 +608,9 @@ void ColladaParser::ReadPrimitives( Mesh* pMesh, std::vector<InputChannel>& pPer
|
||||||
// and the same for the per-index channels
|
// and the same for the per-index channels
|
||||||
BOOST_FOREACH( InputChannel& input, pPerIndexChannels)
|
BOOST_FOREACH( InputChannel& input, pPerIndexChannels)
|
||||||
{
|
{
|
||||||
|
if( input.mResolved)
|
||||||
|
continue;
|
||||||
|
|
||||||
// ignore vertex pointer, it doesn't refer to an accessor
|
// ignore vertex pointer, it doesn't refer to an accessor
|
||||||
if( input.mType == IT_Vertex)
|
if( input.mType == IT_Vertex)
|
||||||
{
|
{
|
||||||
|
@ -590,12 +631,28 @@ void ColladaParser::ReadPrimitives( Mesh* pMesh, std::vector<InputChannel>& pPer
|
||||||
|
|
||||||
// now assemble vertex data according to those indices
|
// now assemble vertex data according to those indices
|
||||||
std::vector<size_t>::const_iterator idx = indices.begin();
|
std::vector<size_t>::const_iterator idx = indices.begin();
|
||||||
for( size_t a = 0; a < pNumPrimitives; a++)
|
|
||||||
|
// For continued primitives, the given count does not come all in one <p>, but only one primitive per <p>
|
||||||
|
size_t numPrimitives = pNumPrimitives;
|
||||||
|
if( pPrimType == Prim_TriFans || pPrimType == Prim_Polygon)
|
||||||
|
numPrimitives = 1;
|
||||||
|
|
||||||
|
for( size_t a = 0; a < numPrimitives; a++)
|
||||||
{
|
{
|
||||||
// determine number of points for this primitive
|
// determine number of points for this primitive
|
||||||
size_t numPoints = 3;
|
size_t numPoints = 0;
|
||||||
if( pIsPolylist)
|
switch( pPrimType)
|
||||||
numPoints = pVCount[a];
|
{
|
||||||
|
case Prim_Lines: numPoints = 2; break;
|
||||||
|
case Prim_Triangles: numPoints = 3; break;
|
||||||
|
case Prim_Polylist: numPoints = pVCount[a]; break;
|
||||||
|
case Prim_TriFans:
|
||||||
|
case Prim_Polygon: numPoints = indices.size() / numOffsets; break;
|
||||||
|
default:
|
||||||
|
// LineStrip and TriStrip not supported due to expected index unmangling
|
||||||
|
ThrowException( "Unsupported primitive type.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// store the face size to later reconstruct the face from
|
// store the face size to later reconstruct the face from
|
||||||
pMesh->mFaceSize.push_back( numPoints);
|
pMesh->mFaceSize.push_back( numPoints);
|
||||||
|
@ -618,7 +675,7 @@ void ColladaParser::ReadPrimitives( Mesh* pMesh, std::vector<InputChannel>& pPer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if I ever get my hands on that guy how invented this steaming pile of indirection...
|
// if I ever get my hands on that guy who invented this steaming pile of indirection...
|
||||||
TestClosing( "p");
|
TestClosing( "p");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -979,7 +1036,9 @@ aiMatrix4x4 ColladaParser::CalculateResultTransform( const std::vector<Transform
|
||||||
case TF_ROTATE:
|
case TF_ROTATE:
|
||||||
{
|
{
|
||||||
aiMatrix4x4 rot;
|
aiMatrix4x4 rot;
|
||||||
aiMatrix4x4::Rotation( tf.f[3], aiVector3D( tf.f[0], tf.f[1], tf.f[2]), rot);
|
float angle = tf.f[3] * float( AI_MATH_PI) / 180.0f;
|
||||||
|
aiVector3D axis( tf.f[0], tf.f[1], tf.f[2]);
|
||||||
|
aiMatrix4x4::Rotation( angle, axis, rot);
|
||||||
res *= rot;
|
res *= rot;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1019,7 +1078,7 @@ aiMatrix4x4 ColladaParser::CalculateResultTransform( const std::vector<Transform
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Determines the input data type for the given semantic string
|
// Determines the input data type for the given semantic string
|
||||||
ColladaParser::InputType ColladaParser::GetTypeForSemantic( const std::string& pSemantic)
|
Collada::InputType ColladaParser::GetTypeForSemantic( const std::string& pSemantic)
|
||||||
{
|
{
|
||||||
if( pSemantic == "POSITION")
|
if( pSemantic == "POSITION")
|
||||||
return IT_Position;
|
return IT_Position;
|
||||||
|
|
|
@ -44,6 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#define AI_COLLADAPARSER_H_INC
|
#define AI_COLLADAPARSER_H_INC
|
||||||
|
|
||||||
#include "./irrXML/irrXMLWrapper.h"
|
#include "./irrXML/irrXMLWrapper.h"
|
||||||
|
#include "ColladaHelper.h"
|
||||||
|
|
||||||
namespace Assimp
|
namespace Assimp
|
||||||
{
|
{
|
||||||
|
@ -54,111 +55,6 @@ namespace Assimp
|
||||||
class ColladaParser
|
class ColladaParser
|
||||||
{
|
{
|
||||||
friend class ColladaLoader;
|
friend class ColladaLoader;
|
||||||
public:
|
|
||||||
/** Transformation types that can be applied to a node */
|
|
||||||
enum TransformType
|
|
||||||
{
|
|
||||||
TF_LOOKAT,
|
|
||||||
TF_ROTATE,
|
|
||||||
TF_TRANSLATE,
|
|
||||||
TF_SCALE,
|
|
||||||
TF_SKEW,
|
|
||||||
TF_MATRIX
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Contains all data for one of the different transformation types */
|
|
||||||
struct Transform
|
|
||||||
{
|
|
||||||
TransformType mType;
|
|
||||||
float f[16]; ///< Interpretation of data depends on the type of the transformation
|
|
||||||
};
|
|
||||||
|
|
||||||
/** A node in a scene hierarchy */
|
|
||||||
struct Node
|
|
||||||
{
|
|
||||||
std::string mName;
|
|
||||||
std::string mID;
|
|
||||||
Node* mParent;
|
|
||||||
std::vector<Node*> mChildren;
|
|
||||||
|
|
||||||
/** Operations in order to calculate the resulting transformation to parent. */
|
|
||||||
std::vector<Transform> mTransforms;
|
|
||||||
|
|
||||||
std::vector<std::string> mMeshes; ///< Meshes at this node
|
|
||||||
|
|
||||||
Node() { mParent = NULL; }
|
|
||||||
~Node() { for( std::vector<Node*>::iterator it = mChildren.begin(); it != mChildren.end(); ++it) delete *it; }
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Data source array */
|
|
||||||
struct Data
|
|
||||||
{
|
|
||||||
std::vector<float> mValues;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Accessor to a data array */
|
|
||||||
struct Accessor
|
|
||||||
{
|
|
||||||
size_t mCount; // in number of objects
|
|
||||||
size_t mOffset; // in number of values
|
|
||||||
size_t mStride; // Stride in number of values
|
|
||||||
std::vector<std::string> mParams; // names of the data streams in the accessors. Empty string tells to ignore.
|
|
||||||
size_t mSubOffset[4]; // Suboffset inside the object for the common 4 elements. For a vector, thats XYZ, for a color RGBA and so on.
|
|
||||||
// For example, SubOffset[0] denotes which of the values inside the object is the vector X component.
|
|
||||||
std::string mSource; // URL of the source array
|
|
||||||
mutable const Data* mData; // Pointer to the source array, if resolved. NULL else
|
|
||||||
|
|
||||||
Accessor()
|
|
||||||
{
|
|
||||||
mCount = 0; mOffset = 0; mStride = 0; mData = NULL;
|
|
||||||
mSubOffset[0] = mSubOffset[1] = mSubOffset[2] = mSubOffset[3] = 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/** A single face in a mesh */
|
|
||||||
struct Face
|
|
||||||
{
|
|
||||||
std::vector<size_t> mIndices;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Different types of input data to a vertex or face */
|
|
||||||
enum InputType
|
|
||||||
{
|
|
||||||
IT_Invalid,
|
|
||||||
IT_Vertex, // special type for per-index data referring to the <vertices> element carrying the per-vertex data.
|
|
||||||
IT_Position,
|
|
||||||
IT_Normal,
|
|
||||||
IT_Texcoord,
|
|
||||||
IT_Color
|
|
||||||
};
|
|
||||||
|
|
||||||
/** An input channel for mesh data, referring to a single accessor */
|
|
||||||
struct InputChannel
|
|
||||||
{
|
|
||||||
InputType mType; // Type of the data
|
|
||||||
size_t mIndex; // Optional index, if multiple sets of the same data type are given
|
|
||||||
size_t mOffset; // Index offset in the indices array of per-face indices. Don't ask, can't explain that any better.
|
|
||||||
std::string mAccessor; // ID of the accessor where to read the actual values from.
|
|
||||||
mutable const Accessor* mResolved; // Pointer to the accessor, if resolved. NULL else
|
|
||||||
|
|
||||||
InputChannel() { mType = IT_Invalid; mIndex = 0; mOffset = 0; mResolved = NULL; }
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Contains data for a single mesh */
|
|
||||||
struct Mesh
|
|
||||||
{
|
|
||||||
std::string mVertexID; // just to check if there's some sophisticated addressing involved... which we don't support, and therefore should warn about.
|
|
||||||
std::vector<InputChannel> mPerVertexData; // Vertex data addressed by vertex indices
|
|
||||||
|
|
||||||
// actual mesh data, assembled on encounter of a <p> element. Verbose format, not indexed
|
|
||||||
std::vector<aiVector3D> mPositions;
|
|
||||||
std::vector<aiVector3D> mNormals;
|
|
||||||
std::vector<aiVector2D> mTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS];
|
|
||||||
std::vector<aiColor4D> mColors[AI_MAX_NUMBER_OF_COLOR_SETS];
|
|
||||||
|
|
||||||
// Faces. Stored are only the number of vertices for each face. 1 == point, 2 == line, 3 == triangle, 4+ == poly
|
|
||||||
std::vector<size_t> mFaceSize;
|
|
||||||
};
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/** Constructor from XML file */
|
/** Constructor from XML file */
|
||||||
|
@ -180,7 +76,7 @@ protected:
|
||||||
void ReadGeometryLibrary();
|
void ReadGeometryLibrary();
|
||||||
|
|
||||||
/** Reads a mesh from the geometry library */
|
/** Reads a mesh from the geometry library */
|
||||||
void ReadMesh( Mesh* pMesh);
|
void ReadMesh( Collada::Mesh* pMesh);
|
||||||
|
|
||||||
/** Reads a data array holding a number of floats, and stores it in the global library */
|
/** Reads a data array holding a number of floats, and stores it in the global library */
|
||||||
void ReadFloatArray();
|
void ReadFloatArray();
|
||||||
|
@ -191,32 +87,32 @@ protected:
|
||||||
void ReadAccessor( const std::string& pID);
|
void ReadAccessor( const std::string& pID);
|
||||||
|
|
||||||
/** Reads input declarations of per-vertex mesh data into the given mesh */
|
/** Reads input declarations of per-vertex mesh data into the given mesh */
|
||||||
void ReadVertexData( Mesh* pMesh);
|
void ReadVertexData( Collada::Mesh* pMesh);
|
||||||
|
|
||||||
/** Reads input declarations of per-index mesh data into the given mesh */
|
/** Reads input declarations of per-index mesh data into the given mesh */
|
||||||
void ReadIndexData( Mesh* pMesh);
|
void ReadIndexData( Collada::Mesh* pMesh);
|
||||||
|
|
||||||
/** Reads a single input channel element and stores it in the given array, if valid */
|
/** Reads a single input channel element and stores it in the given array, if valid */
|
||||||
void ReadInputChannel( std::vector<InputChannel>& poChannels);
|
void ReadInputChannel( std::vector<Collada::InputChannel>& poChannels);
|
||||||
|
|
||||||
/** Reads a <p> primitive index list and assembles the mesh data into the given mesh */
|
/** Reads a <p> primitive index list and assembles the mesh data into the given mesh */
|
||||||
void ReadPrimitives( Mesh* pMesh, std::vector<InputChannel>& pPerIndexChannels,
|
void ReadPrimitives( Collada::Mesh* pMesh, std::vector<Collada::InputChannel>& pPerIndexChannels,
|
||||||
size_t pNumPrimitives, const std::vector<size_t>& pVCount, bool pIsPolylist);
|
size_t pNumPrimitives, const std::vector<size_t>& pVCount, Collada::PrimitiveType pPrimType);
|
||||||
|
|
||||||
/** Extracts a single object from an input channel and stores it in the appropriate mesh data array */
|
/** Extracts a single object from an input channel and stores it in the appropriate mesh data array */
|
||||||
void ExtractDataObjectFromChannel( const InputChannel& pInput, size_t pLocalIndex, Mesh* pMesh);
|
void ExtractDataObjectFromChannel( const Collada::InputChannel& pInput, size_t pLocalIndex, Collada::Mesh* pMesh);
|
||||||
|
|
||||||
/** Reads the library of node hierarchies and scene parts */
|
/** Reads the library of node hierarchies and scene parts */
|
||||||
void ReadSceneLibrary();
|
void ReadSceneLibrary();
|
||||||
|
|
||||||
/** Reads a scene node's contents including children and stores it in the given node */
|
/** Reads a scene node's contents including children and stores it in the given node */
|
||||||
void ReadSceneNode( Node* pNode);
|
void ReadSceneNode( Collada::Node* pNode);
|
||||||
|
|
||||||
/** Reads a node transformation entry of the given type and adds it to the given node's transformation list. */
|
/** Reads a node transformation entry of the given type and adds it to the given node's transformation list. */
|
||||||
void ReadNodeTransformation( Node* pNode, TransformType pType);
|
void ReadNodeTransformation( Collada::Node* pNode, Collada::TransformType pType);
|
||||||
|
|
||||||
/** Reads a mesh reference in a node and adds it to the node's mesh list */
|
/** Reads a mesh reference in a node and adds it to the node's mesh list */
|
||||||
void ReadNodeGeometry( Node* pNode);
|
void ReadNodeGeometry( Collada::Node* pNode);
|
||||||
|
|
||||||
/** Reads the collada scene */
|
/** Reads the collada scene */
|
||||||
void ReadScene();
|
void ReadScene();
|
||||||
|
@ -247,10 +143,10 @@ protected:
|
||||||
const char* GetTextContent();
|
const char* GetTextContent();
|
||||||
|
|
||||||
/** Calculates the resulting transformation fromm all the given transform steps */
|
/** Calculates the resulting transformation fromm all the given transform steps */
|
||||||
aiMatrix4x4 CalculateResultTransform( const std::vector<Transform>& pTransforms) const;
|
aiMatrix4x4 CalculateResultTransform( const std::vector<Collada::Transform>& pTransforms) const;
|
||||||
|
|
||||||
/** Determines the input data type for the given semantic string */
|
/** Determines the input data type for the given semantic string */
|
||||||
InputType GetTypeForSemantic( const std::string& pSemantic);
|
Collada::InputType GetTypeForSemantic( const std::string& pSemantic);
|
||||||
|
|
||||||
/** Finds the item in the given library by its reference, throws if not found */
|
/** Finds the item in the given library by its reference, throws if not found */
|
||||||
template <typename Type> const Type& ResolveLibraryReference( const std::map<std::string, Type>& pLibrary, const std::string& pURL) const;
|
template <typename Type> const Type& ResolveLibraryReference( const std::map<std::string, Type>& pLibrary, const std::string& pURL) const;
|
||||||
|
@ -263,23 +159,23 @@ protected:
|
||||||
irr::io::IrrXMLReader* mReader;
|
irr::io::IrrXMLReader* mReader;
|
||||||
|
|
||||||
/** All data arrays found in the file by ID. Might be referred to by actually everyone. Collada, you are a steaming pile of indirection. */
|
/** All data arrays found in the file by ID. Might be referred to by actually everyone. Collada, you are a steaming pile of indirection. */
|
||||||
typedef std::map<std::string, Data> DataLibrary;
|
typedef std::map<std::string, Collada::Data> DataLibrary;
|
||||||
DataLibrary mDataLibrary;
|
DataLibrary mDataLibrary;
|
||||||
|
|
||||||
/** Same for accessors which define how the data in a data array is accessed. */
|
/** Same for accessors which define how the data in a data array is accessed. */
|
||||||
typedef std::map<std::string, Accessor> AccessorLibrary;
|
typedef std::map<std::string, Collada::Accessor> AccessorLibrary;
|
||||||
AccessorLibrary mAccessorLibrary;
|
AccessorLibrary mAccessorLibrary;
|
||||||
|
|
||||||
/** Mesh library: mesh by ID */
|
/** Mesh library: mesh by ID */
|
||||||
typedef std::map<std::string, Mesh*> MeshLibrary;
|
typedef std::map<std::string, Collada::Mesh*> MeshLibrary;
|
||||||
MeshLibrary mMeshLibrary;
|
MeshLibrary mMeshLibrary;
|
||||||
|
|
||||||
/** node library: root node of the hierarchy part by ID */
|
/** node library: root node of the hierarchy part by ID */
|
||||||
typedef std::map<std::string, Node*> NodeLibrary;
|
typedef std::map<std::string, Collada::Node*> NodeLibrary;
|
||||||
NodeLibrary mNodeLibrary;
|
NodeLibrary mNodeLibrary;
|
||||||
|
|
||||||
/** Pointer to the root node. Don't delete, it just points to one of the nodes in the node library. */
|
/** Pointer to the root node. Don't delete, it just points to one of the nodes in the node library. */
|
||||||
Node* mRootNode;
|
Collada::Node* mRootNode;
|
||||||
|
|
||||||
/** Size unit: how large compared to a meter */
|
/** Size unit: how large compared to a meter */
|
||||||
float mUnitSize;
|
float mUnitSize;
|
||||||
|
|
|
@ -194,7 +194,7 @@ inline const char* fast_atof_move( const char* c, float& out)
|
||||||
else if (*c=='+')++c;
|
else if (*c=='+')++c;
|
||||||
|
|
||||||
f = (float) strtol10_64 ( c, &c );
|
f = (float) strtol10_64 ( c, &c );
|
||||||
if (*c == '.')
|
if (*c == '.' || (c[0] == ',' && isdigit( c[1])))
|
||||||
{
|
{
|
||||||
++c;
|
++c;
|
||||||
|
|
||||||
|
|
|
@ -1437,6 +1437,10 @@
|
||||||
<Filter
|
<Filter
|
||||||
Name="Collada"
|
Name="Collada"
|
||||||
>
|
>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\code\ColladaHelper.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\code\ColladaLoader.cpp"
|
RelativePath="..\..\code\ColladaLoader.cpp"
|
||||||
>
|
>
|
||||||
|
|
Loading…
Reference in New Issue