|
@@ -73,7 +73,7 @@ static const aiImporterDesc desc = {
|
|
// ------------------------------------------------------------------------------------------------
|
|
// ------------------------------------------------------------------------------------------------
|
|
// Constructor to be privately used by Importer
|
|
// Constructor to be privately used by Importer
|
|
ColladaLoader::ColladaLoader()
|
|
ColladaLoader::ColladaLoader()
|
|
-: noSkeletonMesh(), ignoreUpDirection(false), mNodeNameCounter()
|
|
|
|
|
|
+ : noSkeletonMesh(), ignoreUpDirection(false), mNodeNameCounter()
|
|
{}
|
|
{}
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
// ------------------------------------------------------------------------------------------------
|
|
@@ -87,16 +87,16 @@ bool ColladaLoader::CanRead( const std::string& pFile, IOSystem* pIOHandler, boo
|
|
{
|
|
{
|
|
// check file extension
|
|
// check file extension
|
|
std::string extension = GetExtension(pFile);
|
|
std::string extension = GetExtension(pFile);
|
|
-
|
|
|
|
|
|
+
|
|
if( extension == "dae")
|
|
if( extension == "dae")
|
|
return true;
|
|
return true;
|
|
|
|
|
|
// XML - too generic, we need to open the file and search for typical keywords
|
|
// XML - too generic, we need to open the file and search for typical keywords
|
|
if( extension == "xml" || !extension.length() || checkSig) {
|
|
if( extension == "xml" || !extension.length() || checkSig) {
|
|
/* If CanRead() is called in order to check whether we
|
|
/* If CanRead() is called in order to check whether we
|
|
- * support a specific file extension in general pIOHandler
|
|
|
|
- * might be NULL and it's our duty to return true here.
|
|
|
|
- */
|
|
|
|
|
|
+ * support a specific file extension in general pIOHandler
|
|
|
|
+ * might be NULL and it's our duty to return true here.
|
|
|
|
+ */
|
|
if (!pIOHandler)return true;
|
|
if (!pIOHandler)return true;
|
|
const char* tokens[] = {"collada"};
|
|
const char* tokens[] = {"collada"};
|
|
return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
|
|
return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
|
|
@@ -157,26 +157,26 @@ void ColladaLoader::InternReadFile( const std::string& pFile, aiScene* pScene, I
|
|
// ... then fill the materials with the now adjusted settings
|
|
// ... then fill the materials with the now adjusted settings
|
|
FillMaterials(parser, pScene);
|
|
FillMaterials(parser, pScene);
|
|
|
|
|
|
- // Apply unitsize scale calculation
|
|
|
|
- pScene->mRootNode->mTransformation *= aiMatrix4x4(parser.mUnitSize, 0, 0, 0,
|
|
|
|
- 0, parser.mUnitSize, 0, 0,
|
|
|
|
- 0, 0, parser.mUnitSize, 0,
|
|
|
|
- 0, 0, 0, 1);
|
|
|
|
- if( !ignoreUpDirection ) {
|
|
|
|
- // Convert to Y_UP, if different orientation
|
|
|
|
|
|
+ // Apply unitsize scale calculation
|
|
|
|
+ pScene->mRootNode->mTransformation *= aiMatrix4x4(parser.mUnitSize, 0, 0, 0,
|
|
|
|
+ 0, parser.mUnitSize, 0, 0,
|
|
|
|
+ 0, 0, parser.mUnitSize, 0,
|
|
|
|
+ 0, 0, 0, 1);
|
|
|
|
+ if( !ignoreUpDirection ) {
|
|
|
|
+ // Convert to Y_UP, if different orientation
|
|
if( parser.mUpDirection == ColladaParser::UP_X)
|
|
if( parser.mUpDirection == ColladaParser::UP_X)
|
|
pScene->mRootNode->mTransformation *= aiMatrix4x4(
|
|
pScene->mRootNode->mTransformation *= aiMatrix4x4(
|
|
- 0, -1, 0, 0,
|
|
|
|
- 1, 0, 0, 0,
|
|
|
|
- 0, 0, 1, 0,
|
|
|
|
- 0, 0, 0, 1);
|
|
|
|
|
|
+ 0, -1, 0, 0,
|
|
|
|
+ 1, 0, 0, 0,
|
|
|
|
+ 0, 0, 1, 0,
|
|
|
|
+ 0, 0, 0, 1);
|
|
else if( parser.mUpDirection == ColladaParser::UP_Z)
|
|
else if( parser.mUpDirection == ColladaParser::UP_Z)
|
|
pScene->mRootNode->mTransformation *= aiMatrix4x4(
|
|
pScene->mRootNode->mTransformation *= aiMatrix4x4(
|
|
- 1, 0, 0, 0,
|
|
|
|
- 0, 0, 1, 0,
|
|
|
|
- 0, -1, 0, 0,
|
|
|
|
- 0, 0, 0, 1);
|
|
|
|
- }
|
|
|
|
|
|
+ 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);
|
|
|
|
|
|
@@ -195,7 +195,7 @@ void ColladaLoader::InternReadFile( const std::string& pFile, aiScene* pScene, I
|
|
|
|
|
|
// If no meshes have been loaded, it's probably just an animated skeleton.
|
|
// If no meshes have been loaded, it's probably just an animated skeleton.
|
|
if (!pScene->mNumMeshes) {
|
|
if (!pScene->mNumMeshes) {
|
|
-
|
|
|
|
|
|
+
|
|
if (!noSkeletonMesh) {
|
|
if (!noSkeletonMesh) {
|
|
SkeletonMeshBuilder hero(pScene);
|
|
SkeletonMeshBuilder hero(pScene);
|
|
}
|
|
}
|
|
@@ -251,14 +251,14 @@ aiNode* ColladaLoader::BuildHierarchy( const ColladaParser& pParser, const Colla
|
|
// ------------------------------------------------------------------------------------------------
|
|
// ------------------------------------------------------------------------------------------------
|
|
// Resolve node instances
|
|
// Resolve node instances
|
|
void ColladaLoader::ResolveNodeInstances( const ColladaParser& pParser, const Collada::Node* pNode,
|
|
void ColladaLoader::ResolveNodeInstances( const ColladaParser& pParser, const Collada::Node* pNode,
|
|
- std::vector<const Collada::Node*>& resolved)
|
|
|
|
|
|
+ std::vector<const Collada::Node*>& resolved)
|
|
{
|
|
{
|
|
// reserve enough storage
|
|
// reserve enough storage
|
|
resolved.reserve(pNode->mNodeInstances.size());
|
|
resolved.reserve(pNode->mNodeInstances.size());
|
|
|
|
|
|
// ... and iterate through all nodes to be instanced as children of pNode
|
|
// ... and iterate through all nodes to be instanced as children of pNode
|
|
for (std::vector<Collada::NodeInstance>::const_iterator it = pNode->mNodeInstances.begin(),
|
|
for (std::vector<Collada::NodeInstance>::const_iterator it = pNode->mNodeInstances.begin(),
|
|
- end = pNode->mNodeInstances.end(); it != end; ++it)
|
|
|
|
|
|
+ end = pNode->mNodeInstances.end(); it != end; ++it)
|
|
{
|
|
{
|
|
// find the corresponding node in the library
|
|
// find the corresponding node in the library
|
|
const ColladaParser::NodeLibrary::const_iterator itt = pParser.mNodeLibrary.find((*it).mNode);
|
|
const ColladaParser::NodeLibrary::const_iterator itt = pParser.mNodeLibrary.find((*it).mNode);
|
|
@@ -272,7 +272,7 @@ void ColladaLoader::ResolveNodeInstances( const ColladaParser& pParser, const Co
|
|
}
|
|
}
|
|
if (!nd)
|
|
if (!nd)
|
|
DefaultLogger::get()->error("Collada: Unable to resolve reference to instanced node " + (*it).mNode);
|
|
DefaultLogger::get()->error("Collada: Unable to resolve reference to instanced node " + (*it).mNode);
|
|
-
|
|
|
|
|
|
+
|
|
else {
|
|
else {
|
|
// attach this node to the list of children
|
|
// attach this node to the list of children
|
|
resolved.push_back(nd);
|
|
resolved.push_back(nd);
|
|
@@ -283,7 +283,7 @@ void ColladaLoader::ResolveNodeInstances( const ColladaParser& pParser, const Co
|
|
// ------------------------------------------------------------------------------------------------
|
|
// ------------------------------------------------------------------------------------------------
|
|
// Resolve UV channels
|
|
// Resolve UV channels
|
|
void ColladaLoader::ApplyVertexToEffectSemanticMapping(Collada::Sampler& sampler,
|
|
void ColladaLoader::ApplyVertexToEffectSemanticMapping(Collada::Sampler& sampler,
|
|
- const Collada::SemanticMappingTable& table)
|
|
|
|
|
|
+ const Collada::SemanticMappingTable& table)
|
|
{
|
|
{
|
|
std::map<std::string, Collada::InputSemanticMapEntry>::const_iterator it = table.mMap.find(sampler.mUVChannel);
|
|
std::map<std::string, Collada::InputSemanticMapEntry>::const_iterator it = table.mMap.find(sampler.mUVChannel);
|
|
if (it != table.mMap.end()) {
|
|
if (it != table.mMap.end()) {
|
|
@@ -308,7 +308,7 @@ void ColladaLoader::BuildLightsForNode( const ColladaParser& pParser, const Coll
|
|
continue;
|
|
continue;
|
|
}
|
|
}
|
|
const Collada::Light* srcLight = &srcLightIt->second;
|
|
const Collada::Light* srcLight = &srcLightIt->second;
|
|
-
|
|
|
|
|
|
+
|
|
// now fill our ai data structure
|
|
// now fill our ai data structure
|
|
aiLight* out = new aiLight();
|
|
aiLight* out = new aiLight();
|
|
out->mName = pTarget->mName;
|
|
out->mName = pTarget->mName;
|
|
@@ -326,7 +326,7 @@ void ColladaLoader::BuildLightsForNode( const ColladaParser& pParser, const Coll
|
|
|
|
|
|
// convert falloff angle and falloff exponent in our representation, if given
|
|
// convert falloff angle and falloff exponent in our representation, if given
|
|
if (out->mType == aiLightSource_SPOT) {
|
|
if (out->mType == aiLightSource_SPOT) {
|
|
-
|
|
|
|
|
|
+
|
|
out->mAngleInnerCone = AI_DEG_TO_RAD( srcLight->mFalloffAngle );
|
|
out->mAngleInnerCone = AI_DEG_TO_RAD( srcLight->mFalloffAngle );
|
|
|
|
|
|
// ... some extension magic.
|
|
// ... some extension magic.
|
|
@@ -387,7 +387,7 @@ void ColladaLoader::BuildCamerasForNode( const ColladaParser& pParser, const Col
|
|
|
|
|
|
// ... but for the rest some values are optional
|
|
// ... but for the rest some values are optional
|
|
// and we need to compute the others in any combination.
|
|
// and we need to compute the others in any combination.
|
|
- if (srcCamera->mAspect != 10e10f)
|
|
|
|
|
|
+ if (srcCamera->mAspect != 10e10f)
|
|
out->mAspect = srcCamera->mAspect;
|
|
out->mAspect = srcCamera->mAspect;
|
|
|
|
|
|
if (srcCamera->mHorFov != 10e10f) {
|
|
if (srcCamera->mHorFov != 10e10f) {
|
|
@@ -395,12 +395,12 @@ void ColladaLoader::BuildCamerasForNode( const ColladaParser& pParser, const Col
|
|
|
|
|
|
if (srcCamera->mVerFov != 10e10f && srcCamera->mAspect == 10e10f) {
|
|
if (srcCamera->mVerFov != 10e10f && srcCamera->mAspect == 10e10f) {
|
|
out->mAspect = tan(AI_DEG_TO_RAD(srcCamera->mHorFov)) /
|
|
out->mAspect = tan(AI_DEG_TO_RAD(srcCamera->mHorFov)) /
|
|
- tan(AI_DEG_TO_RAD(srcCamera->mVerFov));
|
|
|
|
|
|
+ tan(AI_DEG_TO_RAD(srcCamera->mVerFov));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (srcCamera->mAspect != 10e10f && srcCamera->mVerFov != 10e10f) {
|
|
else if (srcCamera->mAspect != 10e10f && srcCamera->mVerFov != 10e10f) {
|
|
out->mHorizontalFOV = 2.0f * AI_RAD_TO_DEG(atan(srcCamera->mAspect *
|
|
out->mHorizontalFOV = 2.0f * AI_RAD_TO_DEG(atan(srcCamera->mAspect *
|
|
- tan(AI_DEG_TO_RAD(srcCamera->mVerFov) * 0.5f)));
|
|
|
|
|
|
+ tan(AI_DEG_TO_RAD(srcCamera->mVerFov) * 0.5f)));
|
|
}
|
|
}
|
|
|
|
|
|
// Collada uses degrees, we use radians
|
|
// Collada uses degrees, we use radians
|
|
@@ -518,11 +518,11 @@ void ColladaLoader::BuildMeshesForNode( const ColladaParser& pParser, const Coll
|
|
|
|
|
|
// assign the material index
|
|
// assign the material index
|
|
dstMesh->mMaterialIndex = matIdx;
|
|
dstMesh->mMaterialIndex = matIdx;
|
|
- if(dstMesh->mName.length == 0)
|
|
|
|
- {
|
|
|
|
- dstMesh->mName = mid.mMeshOrController;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ if(dstMesh->mName.length == 0)
|
|
|
|
+ {
|
|
|
|
+ dstMesh->mName = mid.mMeshOrController;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -538,11 +538,11 @@ void ColladaLoader::BuildMeshesForNode( const ColladaParser& pParser, const Coll
|
|
// ------------------------------------------------------------------------------------------------
|
|
// ------------------------------------------------------------------------------------------------
|
|
// Creates a mesh for the given ColladaMesh face subset and returns the newly created mesh
|
|
// Creates a mesh for the given ColladaMesh face subset and returns the newly created mesh
|
|
aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada::Mesh* pSrcMesh, const Collada::SubMesh& pSubMesh,
|
|
aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada::Mesh* pSrcMesh, const Collada::SubMesh& pSubMesh,
|
|
- const Collada::Controller* pSrcController, size_t pStartVertex, size_t pStartFace)
|
|
|
|
|
|
+ const Collada::Controller* pSrcController, size_t pStartVertex, size_t pStartFace)
|
|
{
|
|
{
|
|
aiMesh* dstMesh = new aiMesh;
|
|
aiMesh* dstMesh = new aiMesh;
|
|
-
|
|
|
|
- dstMesh->mName = pSrcMesh->mName;
|
|
|
|
|
|
+
|
|
|
|
+ dstMesh->mName = pSrcMesh->mName;
|
|
|
|
|
|
// count the vertices addressed by its faces
|
|
// count the vertices addressed by its faces
|
|
const size_t numVertices = std::accumulate( pSrcMesh->mFaceSize.begin() + pStartFace,
|
|
const size_t numVertices = std::accumulate( pSrcMesh->mFaceSize.begin() + pStartFace,
|
|
@@ -589,7 +589,7 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada::
|
|
dstMesh->mTextureCoords[real] = new aiVector3D[numVertices];
|
|
dstMesh->mTextureCoords[real] = new aiVector3D[numVertices];
|
|
for( size_t b = 0; b < numVertices; ++b)
|
|
for( size_t b = 0; b < numVertices; ++b)
|
|
dstMesh->mTextureCoords[real][b] = pSrcMesh->mTexCoords[a][pStartVertex+b];
|
|
dstMesh->mTextureCoords[real][b] = pSrcMesh->mTexCoords[a][pStartVertex+b];
|
|
-
|
|
|
|
|
|
+
|
|
dstMesh->mNumUVComponents[real] = pSrcMesh->mNumUVComponents[a];
|
|
dstMesh->mNumUVComponents[real] = pSrcMesh->mNumUVComponents[a];
|
|
++real;
|
|
++real;
|
|
}
|
|
}
|
|
@@ -624,8 +624,8 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada::
|
|
if( pSrcController)
|
|
if( pSrcController)
|
|
{
|
|
{
|
|
// refuse if the vertex count does not match
|
|
// refuse if the vertex count does not match
|
|
-// if( pSrcController->mWeightCounts.size() != dstMesh->mNumVertices)
|
|
|
|
-// throw DeadlyImportError( "Joint Controller vertex count does not match mesh vertex count");
|
|
|
|
|
|
+ // if( pSrcController->mWeightCounts.size() != dstMesh->mNumVertices)
|
|
|
|
+ // throw DeadlyImportError( "Joint Controller vertex count does not match mesh vertex count");
|
|
|
|
|
|
// resolve references - joint names
|
|
// resolve references - joint names
|
|
const Collada::Accessor& jointNamesAcc = pParser.ResolveLibraryReference( pParser.mAccessorLibrary, pSrcController->mJointNameSource);
|
|
const Collada::Accessor& jointNamesAcc = pParser.ResolveLibraryReference( pParser.mAccessorLibrary, pSrcController->mJointNameSource);
|
|
@@ -937,7 +937,7 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
|
|
|
|
|
|
// find the collada node corresponding to the aiNode
|
|
// find the collada node corresponding to the aiNode
|
|
const Collada::Node* srcNode = FindNode( pParser.mRootNode, nodeName);
|
|
const Collada::Node* srcNode = FindNode( pParser.mRootNode, nodeName);
|
|
-// ai_assert( srcNode != NULL);
|
|
|
|
|
|
+ // ai_assert( srcNode != NULL);
|
|
if( !srcNode)
|
|
if( !srcNode)
|
|
continue;
|
|
continue;
|
|
|
|
|
|
@@ -990,7 +990,7 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
|
|
{
|
|
{
|
|
entry.mTransformId = srcChannel.mTarget.substr(slashPos + 1, bracketPos - slashPos - 1);
|
|
entry.mTransformId = srcChannel.mTarget.substr(slashPos + 1, bracketPos - slashPos - 1);
|
|
std::string subElement = srcChannel.mTarget.substr(bracketPos);
|
|
std::string subElement = srcChannel.mTarget.substr(bracketPos);
|
|
-
|
|
|
|
|
|
+
|
|
if (subElement == "(0)(0)")
|
|
if (subElement == "(0)(0)")
|
|
entry.mSubElement = 0;
|
|
entry.mSubElement = 0;
|
|
else if (subElement == "(1)(0)")
|
|
else if (subElement == "(1)(0)")
|
|
@@ -1058,134 +1058,134 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
|
|
if( e.mTimeAccessor->mCount != e.mValueAccessor->mCount)
|
|
if( e.mTimeAccessor->mCount != e.mValueAccessor->mCount)
|
|
throw DeadlyImportError( boost::str( boost::format( "Time count / value count mismatch in animation channel \"%s\".") % e.mChannel->mTarget));
|
|
throw DeadlyImportError( boost::str( boost::format( "Time count / value count mismatch in animation channel \"%s\".") % e.mChannel->mTarget));
|
|
|
|
|
|
- if( e.mTimeAccessor->mCount > 0 )
|
|
|
|
- {
|
|
|
|
- // find bounding times
|
|
|
|
- startTime = std::min( startTime, ReadFloat( *e.mTimeAccessor, *e.mTimeData, 0, 0));
|
|
|
|
- endTime = std::max( endTime, ReadFloat( *e.mTimeAccessor, *e.mTimeData, e.mTimeAccessor->mCount-1, 0));
|
|
|
|
- }
|
|
|
|
|
|
+ if( e.mTimeAccessor->mCount > 0 )
|
|
|
|
+ {
|
|
|
|
+ // find bounding times
|
|
|
|
+ startTime = std::min( startTime, ReadFloat( *e.mTimeAccessor, *e.mTimeData, 0, 0));
|
|
|
|
+ endTime = std::max( endTime, ReadFloat( *e.mTimeAccessor, *e.mTimeData, e.mTimeAccessor->mCount-1, 0));
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
- std::vector<aiMatrix4x4> resultTrafos;
|
|
|
|
- if( !entries.empty() && entries.front().mTimeAccessor->mCount > 0 )
|
|
|
|
- {
|
|
|
|
- // create a local transformation chain of the node's transforms
|
|
|
|
- std::vector<Collada::Transform> transforms = srcNode->mTransforms;
|
|
|
|
-
|
|
|
|
- // now for every unique point in time, find or interpolate the key values for that time
|
|
|
|
- // and apply them to the transform chain. Then the node's present transformation can be calculated.
|
|
|
|
- float time = startTime;
|
|
|
|
- while( 1)
|
|
|
|
- {
|
|
|
|
- for( std::vector<Collada::ChannelEntry>::iterator it = entries.begin(); it != entries.end(); ++it)
|
|
|
|
- {
|
|
|
|
- Collada::ChannelEntry& e = *it;
|
|
|
|
-
|
|
|
|
- // find the keyframe behind the current point in time
|
|
|
|
- size_t pos = 0;
|
|
|
|
- float postTime = 0.f;
|
|
|
|
- while( 1)
|
|
|
|
- {
|
|
|
|
- if( pos >= e.mTimeAccessor->mCount)
|
|
|
|
- break;
|
|
|
|
- postTime = ReadFloat( *e.mTimeAccessor, *e.mTimeData, pos, 0);
|
|
|
|
- if( postTime >= time)
|
|
|
|
- break;
|
|
|
|
- ++pos;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- pos = std::min( pos, e.mTimeAccessor->mCount-1);
|
|
|
|
-
|
|
|
|
- // read values from there
|
|
|
|
- float temp[16];
|
|
|
|
- for( size_t c = 0; c < e.mValueAccessor->mSize; ++c)
|
|
|
|
- temp[c] = ReadFloat( *e.mValueAccessor, *e.mValueData, pos, c);
|
|
|
|
-
|
|
|
|
- // if not exactly at the key time, interpolate with previous value set
|
|
|
|
- if( postTime > time && pos > 0)
|
|
|
|
- {
|
|
|
|
- float preTime = ReadFloat( *e.mTimeAccessor, *e.mTimeData, pos-1, 0);
|
|
|
|
- float factor = (time - postTime) / (preTime - postTime);
|
|
|
|
-
|
|
|
|
- for( size_t c = 0; c < e.mValueAccessor->mSize; ++c)
|
|
|
|
- {
|
|
|
|
- float v = ReadFloat( *e.mValueAccessor, *e.mValueData, pos-1, c);
|
|
|
|
- temp[c] += (v - temp[c]) * factor;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // Apply values to current transformation
|
|
|
|
- std::copy( temp, temp + e.mValueAccessor->mSize, transforms[e.mTransformIndex].f + e.mSubElement);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // Calculate resulting transformation
|
|
|
|
- aiMatrix4x4 mat = pParser.CalculateResultTransform( transforms);
|
|
|
|
-
|
|
|
|
- // out of lazyness: we store the time in matrix.d4
|
|
|
|
- mat.d4 = time;
|
|
|
|
- resultTrafos.push_back( mat);
|
|
|
|
-
|
|
|
|
- // find next point in time to evaluate. That's the closest frame larger than the current in any channel
|
|
|
|
- float nextTime = 1e20f;
|
|
|
|
- for( std::vector<Collada::ChannelEntry>::iterator it = entries.begin(); it != entries.end(); ++it)
|
|
|
|
- {
|
|
|
|
- Collada::ChannelEntry& e = *it;
|
|
|
|
-
|
|
|
|
- // find the next time value larger than the current
|
|
|
|
- size_t pos = 0;
|
|
|
|
- while( pos < e.mTimeAccessor->mCount)
|
|
|
|
- {
|
|
|
|
- float t = ReadFloat( *e.mTimeAccessor, *e.mTimeData, pos, 0);
|
|
|
|
- if( t > time)
|
|
|
|
- {
|
|
|
|
- nextTime = std::min( nextTime, t);
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- ++pos;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // no more keys on any channel after the current time -> we're done
|
|
|
|
- if( nextTime > 1e19)
|
|
|
|
- break;
|
|
|
|
-
|
|
|
|
- // else construct next keyframe at this following time point
|
|
|
|
- time = nextTime;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ std::vector<aiMatrix4x4> resultTrafos;
|
|
|
|
+ if( !entries.empty() && entries.front().mTimeAccessor->mCount > 0 )
|
|
|
|
+ {
|
|
|
|
+ // create a local transformation chain of the node's transforms
|
|
|
|
+ std::vector<Collada::Transform> transforms = srcNode->mTransforms;
|
|
|
|
+
|
|
|
|
+ // now for every unique point in time, find or interpolate the key values for that time
|
|
|
|
+ // and apply them to the transform chain. Then the node's present transformation can be calculated.
|
|
|
|
+ float time = startTime;
|
|
|
|
+ while( 1)
|
|
|
|
+ {
|
|
|
|
+ for( std::vector<Collada::ChannelEntry>::iterator it = entries.begin(); it != entries.end(); ++it)
|
|
|
|
+ {
|
|
|
|
+ Collada::ChannelEntry& e = *it;
|
|
|
|
+
|
|
|
|
+ // find the keyframe behind the current point in time
|
|
|
|
+ size_t pos = 0;
|
|
|
|
+ float postTime = 0.f;
|
|
|
|
+ while( 1)
|
|
|
|
+ {
|
|
|
|
+ if( pos >= e.mTimeAccessor->mCount)
|
|
|
|
+ break;
|
|
|
|
+ postTime = ReadFloat( *e.mTimeAccessor, *e.mTimeData, pos, 0);
|
|
|
|
+ if( postTime >= time)
|
|
|
|
+ break;
|
|
|
|
+ ++pos;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pos = std::min( pos, e.mTimeAccessor->mCount-1);
|
|
|
|
+
|
|
|
|
+ // read values from there
|
|
|
|
+ float temp[16];
|
|
|
|
+ for( size_t c = 0; c < e.mValueAccessor->mSize; ++c)
|
|
|
|
+ temp[c] = ReadFloat( *e.mValueAccessor, *e.mValueData, pos, c);
|
|
|
|
+
|
|
|
|
+ // if not exactly at the key time, interpolate with previous value set
|
|
|
|
+ if( postTime > time && pos > 0)
|
|
|
|
+ {
|
|
|
|
+ float preTime = ReadFloat( *e.mTimeAccessor, *e.mTimeData, pos-1, 0);
|
|
|
|
+ float factor = (time - postTime) / (preTime - postTime);
|
|
|
|
+
|
|
|
|
+ for( size_t c = 0; c < e.mValueAccessor->mSize; ++c)
|
|
|
|
+ {
|
|
|
|
+ float v = ReadFloat( *e.mValueAccessor, *e.mValueData, pos-1, c);
|
|
|
|
+ temp[c] += (v - temp[c]) * factor;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Apply values to current transformation
|
|
|
|
+ std::copy( temp, temp + e.mValueAccessor->mSize, transforms[e.mTransformIndex].f + e.mSubElement);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Calculate resulting transformation
|
|
|
|
+ aiMatrix4x4 mat = pParser.CalculateResultTransform( transforms);
|
|
|
|
+
|
|
|
|
+ // out of lazyness: we store the time in matrix.d4
|
|
|
|
+ mat.d4 = time;
|
|
|
|
+ resultTrafos.push_back( mat);
|
|
|
|
+
|
|
|
|
+ // find next point in time to evaluate. That's the closest frame larger than the current in any channel
|
|
|
|
+ float nextTime = 1e20f;
|
|
|
|
+ for( std::vector<Collada::ChannelEntry>::iterator it = entries.begin(); it != entries.end(); ++it)
|
|
|
|
+ {
|
|
|
|
+ Collada::ChannelEntry& e = *it;
|
|
|
|
+
|
|
|
|
+ // find the next time value larger than the current
|
|
|
|
+ size_t pos = 0;
|
|
|
|
+ while( pos < e.mTimeAccessor->mCount)
|
|
|
|
+ {
|
|
|
|
+ float t = ReadFloat( *e.mTimeAccessor, *e.mTimeData, pos, 0);
|
|
|
|
+ if( t > time)
|
|
|
|
+ {
|
|
|
|
+ nextTime = std::min( nextTime, t);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ ++pos;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // no more keys on any channel after the current time -> we're done
|
|
|
|
+ if( nextTime > 1e19)
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ // else construct next keyframe at this following time point
|
|
|
|
+ time = nextTime;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
// there should be some keyframes, but we aren't that fixated on valid input data
|
|
// there should be some keyframes, but we aren't that fixated on valid input data
|
|
-// ai_assert( resultTrafos.size() > 0);
|
|
|
|
|
|
+ // ai_assert( resultTrafos.size() > 0);
|
|
|
|
|
|
// build an animation channel for the given node out of these trafo keys
|
|
// build an animation channel for the given node out of these trafo keys
|
|
- if( !resultTrafos.empty() )
|
|
|
|
- {
|
|
|
|
- aiNodeAnim* dstAnim = new aiNodeAnim;
|
|
|
|
- dstAnim->mNodeName = nodeName;
|
|
|
|
- dstAnim->mNumPositionKeys = resultTrafos.size();
|
|
|
|
- dstAnim->mNumRotationKeys= resultTrafos.size();
|
|
|
|
- dstAnim->mNumScalingKeys = resultTrafos.size();
|
|
|
|
- dstAnim->mPositionKeys = new aiVectorKey[resultTrafos.size()];
|
|
|
|
- dstAnim->mRotationKeys = new aiQuatKey[resultTrafos.size()];
|
|
|
|
- dstAnim->mScalingKeys = new aiVectorKey[resultTrafos.size()];
|
|
|
|
-
|
|
|
|
- for( size_t a = 0; a < resultTrafos.size(); ++a)
|
|
|
|
- {
|
|
|
|
- aiMatrix4x4 mat = resultTrafos[a];
|
|
|
|
- double time = double( mat.d4); // remember? time is stored in mat.d4
|
|
|
|
- mat.d4 = 1.0f;
|
|
|
|
-
|
|
|
|
- dstAnim->mPositionKeys[a].mTime = time;
|
|
|
|
- dstAnim->mRotationKeys[a].mTime = time;
|
|
|
|
- dstAnim->mScalingKeys[a].mTime = time;
|
|
|
|
- mat.Decompose( dstAnim->mScalingKeys[a].mValue, dstAnim->mRotationKeys[a].mValue, dstAnim->mPositionKeys[a].mValue);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- anims.push_back( dstAnim);
|
|
|
|
- } else
|
|
|
|
- {
|
|
|
|
- DefaultLogger::get()->warn( "Collada loader: found empty animation channel, ignored. Please check your exporter.");
|
|
|
|
- }
|
|
|
|
|
|
+ if( !resultTrafos.empty() )
|
|
|
|
+ {
|
|
|
|
+ aiNodeAnim* dstAnim = new aiNodeAnim;
|
|
|
|
+ dstAnim->mNodeName = nodeName;
|
|
|
|
+ dstAnim->mNumPositionKeys = resultTrafos.size();
|
|
|
|
+ dstAnim->mNumRotationKeys= resultTrafos.size();
|
|
|
|
+ dstAnim->mNumScalingKeys = resultTrafos.size();
|
|
|
|
+ dstAnim->mPositionKeys = new aiVectorKey[resultTrafos.size()];
|
|
|
|
+ dstAnim->mRotationKeys = new aiQuatKey[resultTrafos.size()];
|
|
|
|
+ dstAnim->mScalingKeys = new aiVectorKey[resultTrafos.size()];
|
|
|
|
+
|
|
|
|
+ for( size_t a = 0; a < resultTrafos.size(); ++a)
|
|
|
|
+ {
|
|
|
|
+ aiMatrix4x4 mat = resultTrafos[a];
|
|
|
|
+ double time = double( mat.d4); // remember? time is stored in mat.d4
|
|
|
|
+ mat.d4 = 1.0f;
|
|
|
|
+
|
|
|
|
+ dstAnim->mPositionKeys[a].mTime = time;
|
|
|
|
+ dstAnim->mRotationKeys[a].mTime = time;
|
|
|
|
+ dstAnim->mScalingKeys[a].mTime = time;
|
|
|
|
+ mat.Decompose( dstAnim->mScalingKeys[a].mValue, dstAnim->mRotationKeys[a].mValue, dstAnim->mPositionKeys[a].mValue);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ anims.push_back( dstAnim);
|
|
|
|
+ } else
|
|
|
|
+ {
|
|
|
|
+ DefaultLogger::get()->warn( "Collada loader: found empty animation channel, ignored. Please check your exporter.");
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
if( !anims.empty())
|
|
if( !anims.empty())
|
|
@@ -1210,9 +1210,9 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
|
|
// ------------------------------------------------------------------------------------------------
|
|
// ------------------------------------------------------------------------------------------------
|
|
// Add a texture to a material structure
|
|
// Add a texture to a material structure
|
|
void ColladaLoader::AddTexture ( aiMaterial& mat, const ColladaParser& pParser,
|
|
void ColladaLoader::AddTexture ( aiMaterial& mat, const ColladaParser& pParser,
|
|
- const Collada::Effect& effect,
|
|
|
|
- const Collada::Sampler& sampler,
|
|
|
|
- aiTextureType type, unsigned int idx)
|
|
|
|
|
|
+ const Collada::Effect& effect,
|
|
|
|
+ const Collada::Sampler& sampler,
|
|
|
|
+ aiTextureType type, unsigned int idx)
|
|
{
|
|
{
|
|
// first of all, basic file name
|
|
// first of all, basic file name
|
|
const aiString name = FindFilenameForEffectTexture( pParser, effect, sampler.mName );
|
|
const aiString name = FindFilenameForEffectTexture( pParser, effect, sampler.mName );
|
|
@@ -1339,8 +1339,8 @@ void ColladaLoader::FillMaterials( const ColladaParser& pParser, aiScene* /*pSce
|
|
|
|
|
|
// add textures, if given
|
|
// add textures, if given
|
|
if( !effect.mTexAmbient.mName.empty())
|
|
if( !effect.mTexAmbient.mName.empty())
|
|
- /* It is merely a lightmap */
|
|
|
|
- AddTexture( mat, pParser, effect, effect.mTexAmbient, aiTextureType_LIGHTMAP);
|
|
|
|
|
|
+ /* It is merely a lightmap */
|
|
|
|
+ AddTexture( mat, pParser, effect, effect.mTexAmbient, aiTextureType_LIGHTMAP);
|
|
|
|
|
|
if( !effect.mTexEmissive.mName.empty())
|
|
if( !effect.mTexEmissive.mName.empty())
|
|
AddTexture( mat, pParser, effect, effect.mTexEmissive, aiTextureType_EMISSIVE);
|
|
AddTexture( mat, pParser, effect, effect.mTexEmissive, aiTextureType_EMISSIVE);
|
|
@@ -1411,7 +1411,7 @@ void ColladaLoader::BuildMaterials( ColladaParser& pParser, aiScene* /*pScene*/)
|
|
// ------------------------------------------------------------------------------------------------
|
|
// ------------------------------------------------------------------------------------------------
|
|
// Resolves the texture name for the given effect texture entry
|
|
// Resolves the texture name for the given effect texture entry
|
|
aiString ColladaLoader::FindFilenameForEffectTexture( const ColladaParser& pParser,
|
|
aiString ColladaLoader::FindFilenameForEffectTexture( const ColladaParser& pParser,
|
|
- const Collada::Effect& pEffect, const std::string& pName)
|
|
|
|
|
|
+ const Collada::Effect& pEffect, const std::string& pName)
|
|
{
|
|
{
|
|
// recurse through the param references until we end up at an image
|
|
// recurse through the param references until we end up at an image
|
|
std::string name = pName;
|
|
std::string name = pName;
|
|
@@ -1488,35 +1488,35 @@ void ColladaLoader::ConvertPath (aiString& ss)
|
|
ss.data[ss.length] = '\0';
|
|
ss.data[ss.length] = '\0';
|
|
}
|
|
}
|
|
|
|
|
|
- // Maxon Cinema Collada Export writes "file:///C:\andsoon" with three slashes...
|
|
|
|
- // I need to filter it without destroying linux paths starting with "/somewhere"
|
|
|
|
- if( ss.data[0] == '/' && isalpha( ss.data[1]) && ss.data[2] == ':' )
|
|
|
|
- {
|
|
|
|
- ss.length--;
|
|
|
|
- memmove( ss.data, ss.data+1, ss.length);
|
|
|
|
- ss.data[ss.length] = 0;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // find and convert all %xy special chars
|
|
|
|
- char* out = ss.data;
|
|
|
|
- for( const char* it = ss.data; it != ss.data + ss.length; /**/ )
|
|
|
|
- {
|
|
|
|
- if( *it == '%' && (it + 3) < ss.data + ss.length )
|
|
|
|
- {
|
|
|
|
- // separate the number to avoid dragging in chars from behind into the parsing
|
|
|
|
- char mychar[3] = { it[1], it[2], 0 };
|
|
|
|
- size_t nbr = strtoul16( mychar);
|
|
|
|
- it += 3;
|
|
|
|
- *out++ = (char)(nbr & 0xFF);
|
|
|
|
- } else
|
|
|
|
- {
|
|
|
|
- *out++ = *it++;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // adjust length and terminator of the shortened string
|
|
|
|
- *out = 0;
|
|
|
|
- ss.length = (ptrdiff_t) (out - ss.data);
|
|
|
|
|
|
+ // Maxon Cinema Collada Export writes "file:///C:\andsoon" with three slashes...
|
|
|
|
+ // I need to filter it without destroying linux paths starting with "/somewhere"
|
|
|
|
+ if( ss.data[0] == '/' && isalpha( ss.data[1]) && ss.data[2] == ':' )
|
|
|
|
+ {
|
|
|
|
+ ss.length--;
|
|
|
|
+ memmove( ss.data, ss.data+1, ss.length);
|
|
|
|
+ ss.data[ss.length] = 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // find and convert all %xy special chars
|
|
|
|
+ char* out = ss.data;
|
|
|
|
+ for( const char* it = ss.data; it != ss.data + ss.length; /**/ )
|
|
|
|
+ {
|
|
|
|
+ if( *it == '%' && (it + 3) < ss.data + ss.length )
|
|
|
|
+ {
|
|
|
|
+ // separate the number to avoid dragging in chars from behind into the parsing
|
|
|
|
+ char mychar[3] = { it[1], it[2], 0 };
|
|
|
|
+ size_t nbr = strtoul16( mychar);
|
|
|
|
+ it += 3;
|
|
|
|
+ *out++ = (char)(nbr & 0xFF);
|
|
|
|
+ } else
|
|
|
|
+ {
|
|
|
|
+ *out++ = *it++;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // adjust length and terminator of the shortened string
|
|
|
|
+ *out = 0;
|
|
|
|
+ ss.length = (ptrdiff_t) (out - ss.data);
|
|
}
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
// ------------------------------------------------------------------------------------------------
|
|
@@ -1569,17 +1569,17 @@ const Collada::Node* ColladaLoader::FindNode( const Collada::Node* pNode, const
|
|
// Finds a node in the collada scene by the given SID
|
|
// Finds a node in the collada scene by the given SID
|
|
const Collada::Node* ColladaLoader::FindNodeBySID( const Collada::Node* pNode, const std::string& pSID) const
|
|
const Collada::Node* ColladaLoader::FindNodeBySID( const Collada::Node* pNode, const std::string& pSID) const
|
|
{
|
|
{
|
|
- if( pNode->mSID == pSID)
|
|
|
|
- return pNode;
|
|
|
|
|
|
+ if( pNode->mSID == pSID)
|
|
|
|
+ return pNode;
|
|
|
|
|
|
- for( size_t a = 0; a < pNode->mChildren.size(); ++a)
|
|
|
|
- {
|
|
|
|
- const Collada::Node* node = FindNodeBySID( pNode->mChildren[a], pSID);
|
|
|
|
- if( node)
|
|
|
|
- return node;
|
|
|
|
- }
|
|
|
|
|
|
+ for( size_t a = 0; a < pNode->mChildren.size(); ++a)
|
|
|
|
+ {
|
|
|
|
+ const Collada::Node* node = FindNodeBySID( pNode->mChildren[a], pSID);
|
|
|
|
+ if( node)
|
|
|
|
+ return node;
|
|
|
|
+ }
|
|
|
|
|
|
- return NULL;
|
|
|
|
|
|
+ return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
// ------------------------------------------------------------------------------------------------
|
|
@@ -1593,12 +1593,12 @@ std::string ColladaLoader::FindNameForNode( const Collada::Node* pNode)
|
|
else if (!pNode->mID.empty())
|
|
else if (!pNode->mID.empty())
|
|
return pNode->mID;
|
|
return pNode->mID;
|
|
else if (!pNode->mSID.empty())
|
|
else if (!pNode->mSID.empty())
|
|
- return pNode->mSID;
|
|
|
|
- else
|
|
|
|
|
|
+ return pNode->mSID;
|
|
|
|
+ else
|
|
{
|
|
{
|
|
// No need to worry. Unnamed nodes are no problem at all, except
|
|
// No need to worry. Unnamed nodes are no problem at all, except
|
|
// if cameras or lights need to be assigned to them.
|
|
// if cameras or lights need to be assigned to them.
|
|
- return boost::str( boost::format( "$ColladaAutoName$_%d") % mNodeNameCounter++);
|
|
|
|
|
|
+ return boost::str( boost::format( "$ColladaAutoName$_%d") % mNodeNameCounter++);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|