Merge branch 'master' into ColladaAnimationFix

This commit is contained in:
Kim Kulling
2021-02-07 17:45:10 +01:00
committed by GitHub
44 changed files with 2135 additions and 895 deletions

View File

@@ -48,7 +48,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/material.h>
#include <assimp/mesh.h>
#include <stdint.h>
#include <cstdint>
#include <map>
#include <set>
#include <vector>
@@ -206,7 +206,8 @@ struct SemanticMappingTable {
std::string mMatName;
/// List of semantic map commands, grouped by effect semantic name
std::map<std::string, InputSemanticMapEntry> mMap;
using InputSemanticMap = std::map<std::string, InputSemanticMapEntry>;
InputSemanticMap mMap;
/// For std::find
bool operator==(const std::string &s) const {

View File

@@ -63,6 +63,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace Assimp {
using namespace Assimp::Formatter;
using namespace Assimp::Collada;
static const aiImporterDesc desc = {
"Collada Importer",
@@ -271,7 +272,7 @@ aiNode *ColladaLoader::BuildHierarchy(const ColladaParser &pParser, const Collad
node->mTransformation = pParser.CalculateResultTransform(pNode->mTransforms);
// now resolve node instances
std::vector<const Collada::Node *> instances;
std::vector<const Node*> instances;
ResolveNodeInstances(pParser, pNode, instances);
// add children. first the *real* ones
@@ -298,8 +299,8 @@ aiNode *ColladaLoader::BuildHierarchy(const ColladaParser &pParser, const Collad
// ------------------------------------------------------------------------------------------------
// Resolve node instances
void ColladaLoader::ResolveNodeInstances(const ColladaParser &pParser, const Collada::Node *pNode,
std::vector<const Collada::Node *> &resolved) {
void ColladaLoader::ResolveNodeInstances(const ColladaParser &pParser, const Node *pNode,
std::vector<const Node*> &resolved) {
// reserve enough storage
resolved.reserve(pNode->mNodeInstances.size());
@@ -307,7 +308,7 @@ void ColladaLoader::ResolveNodeInstances(const ColladaParser &pParser, const Col
for (const auto &nodeInst : pNode->mNodeInstances) {
// find the corresponding node in the library
const ColladaParser::NodeLibrary::const_iterator itt = pParser.mNodeLibrary.find(nodeInst.mNode);
const Collada::Node *nd = itt == pParser.mNodeLibrary.end() ? nullptr : (*itt).second;
const Node *nd = itt == pParser.mNodeLibrary.end() ? nullptr : (*itt).second;
// FIX for http://sourceforge.net/tracker/?func=detail&aid=3054873&group_id=226462&atid=1067632
// need to check for both name and ID to catch all. To avoid breaking valid files,
@@ -326,13 +327,13 @@ void ColladaLoader::ResolveNodeInstances(const ColladaParser &pParser, const Col
// ------------------------------------------------------------------------------------------------
// Resolve UV channels
void ColladaLoader::ApplyVertexToEffectSemanticMapping(Collada::Sampler &sampler, const Collada::SemanticMappingTable &table) {
std::map<std::string, Collada::InputSemanticMapEntry>::const_iterator it = table.mMap.find(sampler.mUVChannel);
void ColladaLoader::ApplyVertexToEffectSemanticMapping(Sampler &sampler, const SemanticMappingTable &table) {
SemanticMappingTable::InputSemanticMap::const_iterator it = table.mMap.find(sampler.mUVChannel);
if (it == table.mMap.end()) {
return;
}
if (it->second.mType != Collada::IT_Texcoord) {
if (it->second.mType != IT_Texcoord) {
ASSIMP_LOG_ERROR("Collada: Unexpected effect input mapping");
}
@@ -341,8 +342,8 @@ void ColladaLoader::ApplyVertexToEffectSemanticMapping(Collada::Sampler &sampler
// ------------------------------------------------------------------------------------------------
// Builds lights for the given node and references them
void ColladaLoader::BuildLightsForNode(const ColladaParser &pParser, const Collada::Node *pNode, aiNode *pTarget) {
for (const Collada::LightInstance &lid : pNode->mLights) {
void ColladaLoader::BuildLightsForNode(const ColladaParser &pParser, const Node *pNode, aiNode *pTarget) {
for (const LightInstance &lid : pNode->mLights) {
// find the referred light
ColladaParser::LightLibrary::const_iterator srcLightIt = pParser.mLightLibrary.find(lid.mLight);
if (srcLightIt == pParser.mLightLibrary.end()) {
@@ -406,8 +407,8 @@ void ColladaLoader::BuildLightsForNode(const ColladaParser &pParser, const Colla
// ------------------------------------------------------------------------------------------------
// Builds cameras for the given node and references them
void ColladaLoader::BuildCamerasForNode(const ColladaParser &pParser, const Collada::Node *pNode, aiNode *pTarget) {
for (const Collada::CameraInstance &cid : pNode->mCameras) {
void ColladaLoader::BuildCamerasForNode(const ColladaParser &pParser, const Node *pNode, aiNode *pTarget) {
for (const CameraInstance &cid : pNode->mCameras) {
// find the referred light
ColladaParser::CameraLibrary::const_iterator srcCameraIt = pParser.mCameraLibrary.find(cid.mCamera);
if (srcCameraIt == pParser.mCameraLibrary.end()) {
@@ -461,15 +462,15 @@ void ColladaLoader::BuildCamerasForNode(const ColladaParser &pParser, const Coll
// ------------------------------------------------------------------------------------------------
// Builds meshes for the given node and references them
void ColladaLoader::BuildMeshesForNode(const ColladaParser &pParser, const Collada::Node *pNode, aiNode *pTarget) {
void ColladaLoader::BuildMeshesForNode(const ColladaParser &pParser, const Node *pNode, aiNode *pTarget) {
// accumulated mesh references by this node
std::vector<size_t> newMeshRefs;
newMeshRefs.reserve(pNode->mMeshes.size());
// add a mesh for each subgroup in each collada mesh
for (const Collada::MeshInstance &mid : pNode->mMeshes) {
const Collada::Mesh *srcMesh = nullptr;
const Collada::Controller *srcController = nullptr;
for (const MeshInstance &mid : pNode->mMeshes) {
const Mesh *srcMesh = nullptr;
const Controller *srcController = nullptr;
// find the referred mesh
ColladaParser::MeshLibrary::const_iterator srcMeshIt = pParser.mMeshLibrary.find(mid.mMeshOrController);
@@ -503,7 +504,7 @@ void ColladaLoader::BuildMeshesForNode(const ColladaParser &pParser, const Colla
// find material assigned to this submesh
std::string meshMaterial;
std::map<std::string, Collada::SemanticMappingTable>::const_iterator meshMatIt = mid.mMaterials.find(submesh.mMaterial);
std::map<std::string, SemanticMappingTable>::const_iterator meshMatIt = mid.mMaterials.find(submesh.mMaterial);
const Collada::SemanticMappingTable *table = nullptr;
if (meshMatIt != mid.mMaterials.end()) {
@@ -591,15 +592,15 @@ aiMesh *ColladaLoader::findMesh(const std::string &meshid) {
return nullptr;
}
for (unsigned int i = 0; i < mMeshes.size(); ++i) {
if (std::string(mMeshes[i]->mName.data) == meshid) {
return mMeshes[i];
for (auto & mMeshe : mMeshes) {
if (std::string(mMeshe->mName.data) == meshid) {
return mMeshe;
}
}
for (unsigned int i = 0; i < mTargetMeshes.size(); ++i) {
if (std::string(mTargetMeshes[i]->mName.data) == meshid) {
return mTargetMeshes[i];
for (auto & mTargetMeshe : mTargetMeshes) {
if (std::string(mTargetMeshe->mName.data) == meshid) {
return mTargetMeshe;
}
}
@@ -608,8 +609,8 @@ aiMesh *ColladaLoader::findMesh(const std::string &meshid) {
// ------------------------------------------------------------------------------------------------
// 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,
const Collada::Controller *pSrcController, size_t pStartVertex, size_t pStartFace) {
aiMesh *ColladaLoader::CreateMesh(const ColladaParser &pParser, const Mesh *pSrcMesh, const SubMesh &pSubMesh,
const Controller *pSrcController, size_t pStartVertex, size_t pStartFace) {
std::unique_ptr<aiMesh> dstMesh(new aiMesh);
if (useColladaName) {
@@ -647,7 +648,7 @@ aiMesh *ColladaLoader::CreateMesh(const ColladaParser &pParser, const Collada::M
std::copy(pSrcMesh->mBitangents.begin() + pStartVertex, pSrcMesh->mBitangents.begin() + pStartVertex + numVertices, dstMesh->mBitangents);
}
// same for texturecoords, as many as we have
// same for texture coords, as many as we have
// empty slots are not allowed, need to pack and adjust UV indexes accordingly
for (size_t a = 0, real = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) {
if (pSrcMesh->mTexCoords[a].size() >= pStartVertex + numVertices) {
@@ -687,11 +688,11 @@ aiMesh *ColladaLoader::CreateMesh(const ColladaParser &pParser, const Collada::M
// create morph target meshes if any
std::vector<aiMesh *> targetMeshes;
std::vector<float> targetWeights;
Collada::MorphMethod method = Collada::Normalized;
Collada::MorphMethod method = Normalized;
for (std::map<std::string, Collada::Controller>::const_iterator it = pParser.mControllerLibrary.begin();
for (std::map<std::string, Controller>::const_iterator it = pParser.mControllerLibrary.begin();
it != pParser.mControllerLibrary.end(); ++it) {
const Collada::Controller &c = it->second;
const Controller &c = it->second;
const Collada::Mesh *baseMesh = pParser.ResolveLibraryReference(pParser.mMeshLibrary, c.mMeshId);
if (c.mType == Collada::Morph && baseMesh->mName == pSrcMesh->mName) {
@@ -710,8 +711,8 @@ aiMesh *ColladaLoader::CreateMesh(const ColladaParser &pParser, const Collada::M
throw DeadlyImportError("target weight data must not be textual ");
}
for (unsigned int i = 0; i < targetData.mStrings.size(); ++i) {
const Collada::Mesh *targetMesh = pParser.ResolveLibraryReference(pParser.mMeshLibrary, targetData.mStrings.at(i));
for (const auto & mString : targetData.mStrings) {
const Mesh *targetMesh = pParser.ResolveLibraryReference(pParser.mMeshLibrary, mString);
aiMesh *aimesh = findMesh(useColladaName ? targetMesh->mName : targetMesh->mId);
if (!aimesh) {
@@ -723,12 +724,12 @@ aiMesh *ColladaLoader::CreateMesh(const ColladaParser &pParser, const Collada::M
}
targetMeshes.push_back(aimesh);
}
for (unsigned int i = 0; i < weightData.mValues.size(); ++i) {
targetWeights.push_back(weightData.mValues.at(i));
for (float mValue : weightData.mValues) {
targetWeights.push_back(mValue);
}
}
}
if (targetMeshes.size() > 0 && targetWeights.size() == targetMeshes.size()) {
if (!targetMeshes.empty() && targetWeights.size() == targetMeshes.size()) {
std::vector<aiAnimMesh *> animMeshes;
for (unsigned int i = 0; i < targetMeshes.size(); ++i) {
aiMesh *targetMesh = targetMeshes.at(i);
@@ -738,7 +739,7 @@ aiMesh *ColladaLoader::CreateMesh(const ColladaParser &pParser, const Collada::M
animMesh->mName = targetMesh->mName;
animMeshes.push_back(animMesh);
}
dstMesh->mMethod = (method == Collada::Relative) ? aiMorphingMethod_MORPH_RELATIVE : aiMorphingMethod_MORPH_NORMALIZED;
dstMesh->mMethod = (method == Relative) ? aiMorphingMethod_MORPH_RELATIVE : aiMorphingMethod_MORPH_NORMALIZED;
dstMesh->mAnimMeshes = new aiAnimMesh *[animMeshes.size()];
dstMesh->mNumAnimMeshes = static_cast<unsigned int>(animMeshes.size());
for (unsigned int i = 0; i < animMeshes.size(); ++i) {
@@ -762,18 +763,20 @@ aiMesh *ColladaLoader::CreateMesh(const ColladaParser &pParser, const Collada::M
const Collada::Accessor &weightsAcc = pParser.ResolveLibraryReference(pParser.mAccessorLibrary, pSrcController->mWeightInputWeights.mAccessor);
const Collada::Data &weights = pParser.ResolveLibraryReference(pParser.mDataLibrary, weightsAcc.mSource);
if (!jointNames.mIsStringArray || jointMatrices.mIsStringArray || weights.mIsStringArray)
if (!jointNames.mIsStringArray || jointMatrices.mIsStringArray || weights.mIsStringArray) {
throw DeadlyImportError("Data type mismatch while resolving mesh joints");
}
// sanity check: we rely on the vertex weights always coming as pairs of BoneIndex-WeightIndex
if (pSrcController->mWeightInputJoints.mOffset != 0 || pSrcController->mWeightInputWeights.mOffset != 1)
if (pSrcController->mWeightInputJoints.mOffset != 0 || pSrcController->mWeightInputWeights.mOffset != 1) {
throw DeadlyImportError("Unsupported vertex_weight addressing scheme. ");
}
// create containers to collect the weights for each bone
size_t numBones = jointNames.mStrings.size();
std::vector<std::vector<aiVertexWeight>> dstBones(numBones);
// build a temporary array of pointers to the start of each vertex's weights
typedef std::vector<std::pair<size_t, size_t>> IndexPairVector;
using IndexPairVector = std::vector<std::pair<size_t, size_t>>;
std::vector<IndexPairVector::const_iterator> weightStartPerVertex;
weightStartPerVertex.resize(pSrcController->mWeightCounts.size(), pSrcController->mWeights.end());
@@ -812,8 +815,8 @@ aiMesh *ColladaLoader::CreateMesh(const ColladaParser &pParser, const Collada::M
// count the number of bones which influence vertices of the current submesh
size_t numRemainingBones = 0;
for (std::vector<std::vector<aiVertexWeight>>::const_iterator it = dstBones.begin(); it != dstBones.end(); ++it) {
if (it->size() > 0) {
for (const auto & dstBone : dstBones) {
if (!dstBone.empty()) {
++numRemainingBones;
}
}
@@ -872,12 +875,12 @@ aiMesh *ColladaLoader::CreateMesh(const ColladaParser &pParser, const Collada::M
// and replace the bone's name by the node's name so that the user can use the standard
// find-by-name method to associate nodes with bones.
const Collada::Node *bnode = FindNode(pParser.mRootNode, bone->mName.data);
if (!bnode) {
if (nullptr == bnode) {
bnode = FindNodeBySID(pParser.mRootNode, bone->mName.data);
}
// assign the name that we would have assigned for the source node
if (bnode) {
if (nullptr != bnode) {
bone->mName.Set(FindNameForNode(bnode));
} else {
ASSIMP_LOG_WARN_F("ColladaLoader::CreateMesh(): could not find corresponding node for joint \"", bone->mName.data, "\".");
@@ -978,8 +981,8 @@ void ColladaLoader::StoreAnimations(aiScene *pScene, const ColladaParser &pParse
std::set<std::string> animTargets;
animTargets.insert(templateAnim->mChannels[0]->mNodeName.C_Str());
bool collectedAnimationsHaveDifferentChannels = true;
for (size_t b = 0; b < collectedAnimIndices.size(); ++b) {
aiAnimation *srcAnimation = mAnims[collectedAnimIndices[b]];
for (unsigned long long collectedAnimIndice : collectedAnimIndices) {
aiAnimation *srcAnimation = mAnims[collectedAnimIndice];
std::string channelName = std::string(srcAnimation->mChannels[0]->mNodeName.C_Str());
if (animTargets.find(channelName) == animTargets.end()) {
animTargets.insert(channelName);
@@ -989,8 +992,9 @@ void ColladaLoader::StoreAnimations(aiScene *pScene, const ColladaParser &pParse
}
}
if (!collectedAnimationsHaveDifferentChannels)
if (!collectedAnimationsHaveDifferentChannels) {
continue;
}
// if there are other animations which fit the template anim, combine all channels into a single anim
if (!collectedAnimIndices.empty()) {
@@ -1037,16 +1041,18 @@ void ColladaLoader::StoreAnimations(aiScene *pScene, const ColladaParser &pParse
// ------------------------------------------------------------------------------------------------
// Constructs the animations for the given source anim
void ColladaLoader::StoreAnimations(aiScene *pScene, const ColladaParser &pParser, const Collada::Animation *pSrcAnim, const std::string &pPrefix) {
void ColladaLoader::StoreAnimations(aiScene *pScene, const ColladaParser &pParser, const Animation *pSrcAnim, const std::string &pPrefix) {
std::string animName = pPrefix.empty() ? pSrcAnim->mName : pPrefix + "_" + pSrcAnim->mName;
// create nested animations, if given
for (std::vector<Collada::Animation *>::const_iterator it = pSrcAnim->mSubAnims.begin(); it != pSrcAnim->mSubAnims.end(); ++it)
StoreAnimations(pScene, pParser, *it, animName);
for (auto mSubAnim : pSrcAnim->mSubAnims) {
StoreAnimations(pScene, pParser, mSubAnim, animName);
}
// create animation channels, if any
if (!pSrcAnim->mChannels.empty())
if (!pSrcAnim->mChannels.empty()) {
CreateAnimation(pScene, pParser, pSrcAnim, animName);
}
}
struct MorphTimeValues {
@@ -1062,7 +1068,7 @@ void insertMorphTimeValue(std::vector<MorphTimeValues> &values, float time, floa
MorphTimeValues::key k;
k.mValue = value;
k.mWeight = weight;
if (values.size() == 0 || time < values[0].mTime) {
if (values.empty() || time < values[0].mTime) {
MorphTimeValues val;
val.mTime = time;
val.mKeys.push_back(k);
@@ -1088,13 +1094,13 @@ void insertMorphTimeValue(std::vector<MorphTimeValues> &values, float time, floa
return;
}
}
// should not get here
}
float getWeightAtKey(const std::vector<MorphTimeValues> &values, int key, unsigned int value) {
for (unsigned int i = 0; i < values[key].mKeys.size(); i++) {
if (values[key].mKeys[i].mValue == value)
return values[key].mKeys[i].mWeight;
static float getWeightAtKey(const std::vector<MorphTimeValues> &values, int key, unsigned int value) {
for (auto mKey : values[key].mKeys) {
if (mKey.mValue == value) {
return mKey.mWeight;
}
}
// no value at key found, try to interpolate if present at other keys. if not, return zero
// TODO: interpolation
@@ -1103,7 +1109,7 @@ float getWeightAtKey(const std::vector<MorphTimeValues> &values, int key, unsign
// ------------------------------------------------------------------------------------------------
// Constructs the animation for the given source anim
void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParser, const Collada::Animation *pSrcAnim, const std::string &pName) {
void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParser, const Animation *pSrcAnim, const std::string &pName) {
// collect a list of animatable nodes
std::vector<const aiNode *> nodes;
CollectNodes(pScene->mRootNode, nodes);
@@ -1111,23 +1117,23 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
std::vector<aiNodeAnim *> anims;
std::vector<aiMeshMorphAnim *> morphAnims;
for (std::vector<const aiNode *>::const_iterator nit = nodes.begin(); nit != nodes.end(); ++nit) {
for (auto node : nodes) {
// find all the collada anim channels which refer to the current node
std::vector<Collada::ChannelEntry> entries;
std::string nodeName = (*nit)->mName.data;
std::vector<ChannelEntry> entries;
std::string nodeName = node->mName.data;
// find the collada node corresponding to the aiNode
const Collada::Node *srcNode = FindNode(pParser.mRootNode, nodeName);
const Node *srcNode = FindNode(pParser.mRootNode, nodeName);
if (!srcNode) {
continue;
}
// now check all channels if they affect the current node
std::string targetID, subElement;
for (std::vector<Collada::AnimationChannel>::const_iterator cit = pSrcAnim->mChannels.begin();
for (std::vector<AnimationChannel>::const_iterator cit = pSrcAnim->mChannels.begin();
cit != pSrcAnim->mChannels.end(); ++cit) {
const Collada::AnimationChannel &srcChannel = *cit;
Collada::ChannelEntry entry;
const AnimationChannel &srcChannel = *cit;
ChannelEntry entry;
// we expect the animation target to be of type "nodeName/transformID.subElement". Ignore all others
// find the slash that separates the node name - there should be only one
@@ -1142,24 +1148,28 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
entry.mChannel = &(*cit);
entry.mTargetId = srcChannel.mTarget.substr(targetPos + pSrcAnim->mName.length(),
srcChannel.mTarget.length() - targetPos - pSrcAnim->mName.length());
if (entry.mTargetId.front() == '-')
if (entry.mTargetId.front() == '-') {
entry.mTargetId = entry.mTargetId.substr(1);
}
entries.push_back(entry);
continue;
}
if (srcChannel.mTarget.find('/', slashPos + 1) != std::string::npos)
if (srcChannel.mTarget.find('/', slashPos + 1) != std::string::npos) {
continue;
}
targetID.clear();
targetID = srcChannel.mTarget.substr(0, slashPos);
if (targetID != srcNode->mID)
if (targetID != srcNode->mID) {
continue;
}
// find the dot that separates the transformID - there should be only one or zero
std::string::size_type dotPos = srcChannel.mTarget.find('.');
if (dotPos != std::string::npos) {
if (srcChannel.mTarget.find('.', dotPos + 1) != std::string::npos)
if (srcChannel.mTarget.find('.', dotPos + 1) != std::string::npos) {
continue;
}
entry.mTransformId = srcChannel.mTarget.substr(slashPos + 1, dotPos - slashPos - 1);
@@ -1176,7 +1186,7 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
else
ASSIMP_LOG_WARN_F("Unknown anim subelement <", subElement, ">. Ignoring");
} else {
// no subelement following, transformId is remaining string
// no sub-element following, transformId is remaining string
entry.mTransformId = srcChannel.mTarget.substr(slashPos + 1);
}
@@ -1227,11 +1237,11 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
entry.mTransformIndex = a;
if (entry.mTransformIndex == SIZE_MAX) {
if (entry.mTransformId.find("morph-weights") != std::string::npos) {
entry.mTargetId = entry.mTransformId;
entry.mTransformId = "";
} else
if (entry.mTransformId.find("morph-weights") == std::string::npos) {
continue;
}
entry.mTargetId = entry.mTransformId;
entry.mTransformId = "";
}
entry.mChannel = &(*cit);
@@ -1239,21 +1249,22 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
}
// if there's no channel affecting the current node, we skip it
if (entries.empty())
if (entries.empty()) {
continue;
}
// resolve the data pointers for all anim channels. Find the minimum time while we're at it
ai_real startTime = ai_real(1e20), endTime = ai_real(-1e20);
for (std::vector<Collada::ChannelEntry>::iterator it = entries.begin(); it != entries.end(); ++it) {
Collada::ChannelEntry &e = *it;
for (ChannelEntry & e : entries) {
e.mTimeAccessor = &pParser.ResolveLibraryReference(pParser.mAccessorLibrary, e.mChannel->mSourceTimes);
e.mTimeData = &pParser.ResolveLibraryReference(pParser.mDataLibrary, e.mTimeAccessor->mSource);
e.mValueAccessor = &pParser.ResolveLibraryReference(pParser.mAccessorLibrary, e.mChannel->mSourceValues);
e.mValueData = &pParser.ResolveLibraryReference(pParser.mDataLibrary, e.mValueAccessor->mSource);
// time count and value count must match
if (e.mTimeAccessor->mCount != e.mValueAccessor->mCount)
if (e.mTimeAccessor->mCount != e.mValueAccessor->mCount) {
throw DeadlyImportError("Time count / value count mismatch in animation channel \"", e.mChannel->mTarget, "\".");
}
if (e.mTimeAccessor->mCount > 0) {
// find bounding times
@@ -1271,18 +1282,18 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
// and apply them to the transform chain. Then the node's present transformation can be calculated.
ai_real time = startTime;
while (1) {
for (std::vector<Collada::ChannelEntry>::iterator it = entries.begin(); it != entries.end(); ++it) {
Collada::ChannelEntry &e = *it;
for (ChannelEntry & e : entries) {
// find the keyframe behind the current point in time
size_t pos = 0;
ai_real postTime = 0.0;
while (1) {
if (pos >= e.mTimeAccessor->mCount)
if (pos >= e.mTimeAccessor->mCount) {
break;
}
postTime = ReadFloat(*e.mTimeAccessor, *e.mTimeData, pos, 0);
if (postTime >= time)
if (postTime >= time) {
break;
}
++pos;
}
@@ -1290,8 +1301,9 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
// read values from there
ai_real temp[16];
for (size_t c = 0; c < e.mValueAccessor->mSize; ++c)
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) {
@@ -1317,9 +1329,7 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
// find next point in time to evaluate. That's the closest frame larger than the current in any channel
ai_real nextTime = ai_real(1e20);
for (std::vector<Collada::ChannelEntry>::iterator it = entries.begin(); it != entries.end(); ++it) {
Collada::ChannelEntry &channelElement = *it;
for (ChannelEntry & channelElement : entries) {
// find the next time value larger than the current
size_t pos = 0;
while (pos < channelElement.mTimeAccessor->mCount) {
@@ -1334,7 +1344,7 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
// https://github.com/assimp/assimp/issues/458
// Sub-sample axis-angle channels if the delta between two consecutive
// key-frame angles is >= 180 degrees.
if (transforms[channelElement.mTransformIndex].mType == Collada::TF_ROTATE && channelElement.mSubElement == 3 && pos > 0 && pos < channelElement.mTimeAccessor->mCount) {
if (transforms[channelElement.mTransformIndex].mType == TF_ROTATE && channelElement.mSubElement == 3 && pos > 0 && pos < channelElement.mTimeAccessor->mCount) {
const ai_real cur_key_angle = ReadFloat(*channelElement.mValueAccessor, *channelElement.mValueData, pos, 0);
const ai_real last_key_angle = ReadFloat(*channelElement.mValueAccessor, *channelElement.mValueData, pos - 1, 0);
const ai_real cur_key_time = ReadFloat(*channelElement.mTimeAccessor, *channelElement.mTimeData, pos, 0);
@@ -1352,17 +1362,15 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
}
// no more keys on any channel after the current time -> we're done
if (nextTime > 1e19)
if (nextTime > 1e19) {
break;
}
// else construct next keyframe at this following time point
// else construct next key-frame at this following time point
time = nextTime;
}
}
// there should be some keyframes, but we aren't that fixated on valid input data
// ai_assert( resultTrafos.size() > 0);
// build an animation channel for the given node out of these trafo keys
if (!resultTrafos.empty()) {
aiNodeAnim *dstAnim = new aiNodeAnim;
@@ -1391,16 +1399,16 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
}
if (!entries.empty() && entries.front().mTimeAccessor->mCount > 0) {
std::vector<Collada::ChannelEntry> morphChannels;
for (std::vector<Collada::ChannelEntry>::iterator it = entries.begin(); it != entries.end(); ++it) {
Collada::ChannelEntry &e = *it;
std::vector<ChannelEntry> morphChannels;
for (ChannelEntry & e : entries) {
// skip non-transform types
if (e.mTargetId.empty())
if (e.mTargetId.empty()) {
continue;
}
if (e.mTargetId.find("morph-weights") != std::string::npos)
if (e.mTargetId.find("morph-weights") != std::string::npos) {
morphChannels.push_back(e);
}
}
if (!morphChannels.empty()) {
// either 1) morph weight animation count should contain morph target count channels
@@ -1412,13 +1420,14 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
std::vector<MorphTimeValues> morphTimeValues;
int morphAnimChannelIndex = 0;
for (std::vector<Collada::ChannelEntry>::iterator it = morphChannels.begin(); it != morphChannels.end(); ++it) {
Collada::ChannelEntry &e = *it;
for (ChannelEntry & e : morphChannels) {
std::string::size_type apos = e.mTargetId.find('(');
std::string::size_type bpos = e.mTargetId.find(')');
if (apos == std::string::npos || bpos == std::string::npos)
// unknown way to specify weight -> ignore this animation
// If unknown way to specify weight -> ignore this animation
if (apos == std::string::npos || bpos == std::string::npos) {
continue;
}
// weight target can be in format Weight_M_N, Weight_N, WeightN, or some other way
// we ignore the name and just assume the channels are in the right order
@@ -1462,13 +1471,13 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
std::copy(morphAnims.begin(), morphAnims.end(), anim->mMorphMeshChannels);
}
anim->mDuration = 0.0f;
for (size_t a = 0; a < anims.size(); ++a) {
anim->mDuration = std::max(anim->mDuration, anims[a]->mPositionKeys[anims[a]->mNumPositionKeys - 1].mTime);
anim->mDuration = std::max(anim->mDuration, anims[a]->mRotationKeys[anims[a]->mNumRotationKeys - 1].mTime);
anim->mDuration = std::max(anim->mDuration, anims[a]->mScalingKeys[anims[a]->mNumScalingKeys - 1].mTime);
for (auto & a : anims) {
anim->mDuration = std::max(anim->mDuration, a->mPositionKeys[a->mNumPositionKeys - 1].mTime);
anim->mDuration = std::max(anim->mDuration, a->mRotationKeys[a->mNumRotationKeys - 1].mTime);
anim->mDuration = std::max(anim->mDuration, a->mScalingKeys[a->mNumScalingKeys - 1].mTime);
}
for (size_t a = 0; a < morphAnims.size(); ++a) {
anim->mDuration = std::max(anim->mDuration, morphAnims[a]->mKeys[morphAnims[a]->mNumKeys - 1].mTime);
for (auto & morphAnim : morphAnims) {
anim->mDuration = std::max(anim->mDuration, morphAnim->mKeys[morphAnim->mNumKeys - 1].mTime);
}
anim->mTicksPerSecond = 1000.0;
mAnims.push_back(anim);
@@ -1477,10 +1486,12 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
// ------------------------------------------------------------------------------------------------
// Add a texture to a material structure
void ColladaLoader::AddTexture(aiMaterial &mat, const ColladaParser &pParser,
const Collada::Effect &effect,
const Collada::Sampler &sampler,
aiTextureType type, unsigned int idx) {
void ColladaLoader::AddTexture(aiMaterial &mat,
const ColladaParser &pParser,
const Effect &effect,
const Sampler &sampler,
aiTextureType type,
unsigned int idx) {
// first of all, basic file name
const aiString name = FindFilenameForEffectTexture(pParser, effect, sampler.mName);
mat.AddProperty(&name, _AI_MATKEY_TEXTURE_BASE, type, idx);
@@ -1579,7 +1590,7 @@ void ColladaLoader::FillMaterials(const ColladaParser &pParser, aiScene * /*pSce
shadeMode = effect.mDoubleSided;
mat.AddProperty<int>(&shadeMode, 1, AI_MATKEY_TWOSIDED);
// wireframe?
// wire-frame?
shadeMode = effect.mWireframe;
mat.AddProperty<int>(&shadeMode, 1, AI_MATKEY_ENABLE_WIREFRAME);
@@ -1657,12 +1668,12 @@ void ColladaLoader::BuildMaterials(ColladaParser &pParser, aiScene * /*pScene*/)
for (ColladaParser::MaterialLibrary::const_iterator matIt = pParser.mMaterialLibrary.begin();
matIt != pParser.mMaterialLibrary.end(); ++matIt) {
const Collada::Material &material = matIt->second;
const Material &material = matIt->second;
// a material is only a reference to an effect
ColladaParser::EffectLibrary::iterator effIt = pParser.mEffectLibrary.find(material.mEffect);
if (effIt == pParser.mEffectLibrary.end())
continue;
Collada::Effect &effect = effIt->second;
Effect &effect = effIt->second;
// create material
aiMaterial *mat = new aiMaterial;
@@ -1671,7 +1682,7 @@ void ColladaLoader::BuildMaterials(ColladaParser &pParser, aiScene * /*pScene*/)
// store the material
mMaterialIndexByName[matIt->first] = newMats.size();
newMats.push_back(std::pair<Collada::Effect *, aiMaterial *>(&effect, mat));
newMats.push_back(std::pair<Effect *, aiMaterial *>(&effect, mat));
}
// ScenePreprocessor generates a default material automatically if none is there.
// All further code here in this loader works well without a valid material so
@@ -1679,17 +1690,16 @@ void ColladaLoader::BuildMaterials(ColladaParser &pParser, aiScene * /*pScene*/)
}
// ------------------------------------------------------------------------------------------------
// Resolves the texture name for the given effect texture entry
// and loads the texture data
// Resolves the texture name for the given effect texture entry and loads the texture data
aiString ColladaLoader::FindFilenameForEffectTexture(const ColladaParser &pParser,
const Collada::Effect &pEffect, const std::string &pName) {
const Effect &pEffect, const std::string &pName) {
aiString result;
// recurse through the param references until we end up at an image
std::string name = pName;
while (1) {
// the given string is a param entry. Find it
Collada::Effect::ParamLibrary::const_iterator it = pEffect.mParams.find(name);
Effect::ParamLibrary::const_iterator it = pEffect.mParams.find(name);
// if not found, we're at the end of the recursion. The resulting string should be the image ID
if (it == pEffect.mParams.end())
break;
@@ -1717,10 +1727,6 @@ aiString ColladaLoader::FindFilenameForEffectTexture(const ColladaParser &pParse
tex->mFilename.Set(imIt->second.mFileName.c_str());
result.Set(imIt->second.mFileName);
// TODO: check the possibility of using the flag "AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING"
// result.data[0] = '*';
// result.length = 1 + ASSIMP_itoa10(result.data + 1, static_cast<unsigned int>(MAXLEN - 1), static_cast<int32_t>(mTextures.size()));
// setup format hint
if (imIt->second.mEmbeddedFormat.length() >= HINTMAXTEXTURELEN) {
ASSIMP_LOG_WARN("Collada: texture format hint is too long, truncating to 3 characters");
@@ -1749,7 +1755,7 @@ aiString ColladaLoader::FindFilenameForEffectTexture(const ColladaParser &pParse
// ------------------------------------------------------------------------------------------------
// Reads a float value from an accessor and its data array.
ai_real ColladaLoader::ReadFloat(const Collada::Accessor &pAccessor, const Collada::Data &pData, size_t pIndex, size_t pOffset) const {
ai_real ColladaLoader::ReadFloat(const Accessor &pAccessor, const Data &pData, size_t pIndex, size_t pOffset) const {
size_t pos = pAccessor.mStride * pIndex + pAccessor.mOffset + pOffset;
ai_assert(pos < pData.mValues.size());
return pData.mValues[pos];
@@ -1757,7 +1763,7 @@ ai_real ColladaLoader::ReadFloat(const Collada::Accessor &pAccessor, const Colla
// ------------------------------------------------------------------------------------------------
// Reads a string value from an accessor and its data array.
const std::string &ColladaLoader::ReadString(const Collada::Accessor &pAccessor, const Collada::Data &pData, size_t pIndex) const {
const std::string &ColladaLoader::ReadString(const Accessor &pAccessor, const Data &pData, size_t pIndex) const {
size_t pos = pAccessor.mStride * pIndex + pAccessor.mOffset;
ai_assert(pos < pData.mStrings.size());
return pData.mStrings[pos];
@@ -1774,12 +1780,12 @@ void ColladaLoader::CollectNodes(const aiNode *pNode, std::vector<const aiNode *
// ------------------------------------------------------------------------------------------------
// Finds a node in the collada scene by the given name
const Collada::Node *ColladaLoader::FindNode(const Collada::Node *pNode, const std::string &pName) const {
const Node *ColladaLoader::FindNode(const Node *pNode, const std::string &pName) const {
if (pNode->mName == pName || pNode->mID == pName)
return pNode;
for (size_t a = 0; a < pNode->mChildren.size(); ++a) {
const Collada::Node *node = FindNode(pNode->mChildren[a], pName);
for (auto a : pNode->mChildren) {
const Collada::Node *node = FindNode(a, pName);
if (node) {
return node;
}
@@ -1790,7 +1796,7 @@ const Collada::Node *ColladaLoader::FindNode(const Collada::Node *pNode, const s
// ------------------------------------------------------------------------------------------------
// 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 Node *ColladaLoader::FindNodeBySID(const Node *pNode, const std::string &pSID) const {
if (nullptr == pNode) {
return nullptr;
}
@@ -1799,8 +1805,8 @@ const Collada::Node *ColladaLoader::FindNodeBySID(const Collada::Node *pNode, co
return pNode;
}
for (size_t a = 0; a < pNode->mChildren.size(); ++a) {
const Collada::Node *node = FindNodeBySID(pNode->mChildren[a], pSID);
for (auto a : pNode->mChildren) {
const Collada::Node *node = FindNodeBySID(a, pSID);
if (node) {
return node;
}
@@ -1812,7 +1818,7 @@ const Collada::Node *ColladaLoader::FindNodeBySID(const Collada::Node *pNode, co
// ------------------------------------------------------------------------------------------------
// Finds a proper unique name for a node derived from the collada-node's properties.
// The name must be unique for proper node-bone association.
std::string ColladaLoader::FindNameForNode(const Collada::Node *pNode) {
std::string ColladaLoader::FindNameForNode(const Node *pNode) {
// If explicitly requested, just use the collada name.
if (useColladaName) {
if (!pNode->mName.empty()) {

View File

@@ -4,7 +4,7 @@
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2020, assimp team
Copyright (c) 2006-2021, assimp team
All rights reserved.
@@ -45,8 +45,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef AI_COLLADALOADER_H_INC
#define AI_COLLADALOADER_H_INC
#include <assimp/BaseImporter.h>
#include "ColladaParser.h"
#include <assimp/BaseImporter.h>
struct aiNode;
struct aiCamera;
@@ -54,28 +54,24 @@ struct aiLight;
struct aiTexture;
struct aiAnimation;
namespace Assimp
{
namespace Assimp {
struct ColladaMeshIndex
{
struct ColladaMeshIndex {
std::string mMeshID;
size_t mSubMesh;
std::string mMaterial;
ColladaMeshIndex( const std::string& pMeshID, size_t pSubMesh, const std::string& pMaterial)
: mMeshID( pMeshID), mSubMesh( pSubMesh), mMaterial( pMaterial)
{ }
ColladaMeshIndex(const std::string &pMeshID, size_t pSubMesh, const std::string &pMaterial) :
mMeshID(pMeshID), mSubMesh(pSubMesh), mMaterial(pMaterial) {
ai_assert(!pMeshID.empty());
}
bool operator < (const ColladaMeshIndex& p) const
{
if( mMeshID == p.mMeshID)
{
if( mSubMesh == p.mSubMesh)
bool operator<(const ColladaMeshIndex &p) const {
if (mMeshID == p.mMeshID) {
if (mSubMesh == p.mSubMesh)
return mMaterial < p.mMaterial;
else
return mSubMesh < p.mSubMesh;
} else
{
} else {
return mMeshID < p.mMeshID;
}
}
@@ -84,105 +80,102 @@ struct ColladaMeshIndex
/** Loader class to read Collada scenes. Collada is over-engineered to death, with every new iteration bringing
* more useless stuff, so I limited the data to what I think is useful for games.
*/
class ColladaLoader : public BaseImporter
{
class ColladaLoader : public BaseImporter {
public:
/// The class constructor.
ColladaLoader();
~ColladaLoader();
/// The class destructor.
~ColladaLoader() override;
public:
/** Returns whether the class can handle the format of the given file.
* See BaseImporter::CanRead() for details. */
bool CanRead(const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const override;
/// Returns whether the class can handle the format of the given file.
/// @see BaseImporter::CanRead() for more details.
bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const override;
protected:
/** Return importer meta information.
* See #BaseImporter::GetInfo for the details
*/
const aiImporterDesc* GetInfo () const override;
/// See #BaseImporter::GetInfo for the details
const aiImporterDesc *GetInfo() const override;
void SetupProperties(const Importer* pImp) override;
/// See #BaseImporter::SetupProperties for the details
void SetupProperties(const Importer *pImp) override;
/** Imports the given file into the given scene structure.
* See BaseImporter::InternReadFile() for details
*/
void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) override;
/// See #BaseImporter::InternReadFile for the details
void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) override;
/** Recursively constructs a scene node for the given parser node and returns it. */
aiNode* BuildHierarchy( const ColladaParser& pParser, const Collada::Node* pNode);
aiNode *BuildHierarchy(const ColladaParser &pParser, const Collada::Node *pNode);
/** Resolve node instances */
void ResolveNodeInstances( const ColladaParser& pParser, const Collada::Node* pNode,
std::vector<const Collada::Node*>& resolved);
void ResolveNodeInstances(const ColladaParser &pParser, const Collada::Node *pNode,
std::vector<const Collada::Node *> &resolved);
/** Builds meshes for the given node and references them */
void BuildMeshesForNode( const ColladaParser& pParser, const Collada::Node* pNode,
aiNode* pTarget);
aiMesh *findMesh(const std::string& meshid);
void BuildMeshesForNode(const ColladaParser &pParser, const Collada::Node *pNode,
aiNode *pTarget);
aiMesh *findMesh(const std::string &meshid);
/** Creates a mesh for the given ColladaMesh face subset and returns the newly created mesh */
aiMesh* CreateMesh( const ColladaParser& pParser, const Collada::Mesh* pSrcMesh, const Collada::SubMesh& pSubMesh,
const Collada::Controller* pSrcController, size_t pStartVertex, size_t pStartFace);
aiMesh *CreateMesh(const ColladaParser &pParser, const Collada::Mesh *pSrcMesh, const Collada::SubMesh &pSubMesh,
const Collada::Controller *pSrcController, size_t pStartVertex, size_t pStartFace);
/** Builds cameras for the given node and references them */
void BuildCamerasForNode( const ColladaParser& pParser, const Collada::Node* pNode,
aiNode* pTarget);
void BuildCamerasForNode(const ColladaParser &pParser, const Collada::Node *pNode,
aiNode *pTarget);
/** Builds lights for the given node and references them */
void BuildLightsForNode( const ColladaParser& pParser, const Collada::Node* pNode,
aiNode* pTarget);
void BuildLightsForNode(const ColladaParser &pParser, const Collada::Node *pNode,
aiNode *pTarget);
/** Stores all meshes in the given scene */
void StoreSceneMeshes( aiScene* pScene);
void StoreSceneMeshes(aiScene *pScene);
/** Stores all materials in the given scene */
void StoreSceneMaterials( aiScene* pScene);
void StoreSceneMaterials(aiScene *pScene);
/** Stores all lights in the given scene */
void StoreSceneLights( aiScene* pScene);
void StoreSceneLights(aiScene *pScene);
/** Stores all cameras in the given scene */
void StoreSceneCameras( aiScene* pScene);
void StoreSceneCameras(aiScene *pScene);
/** Stores all textures in the given scene */
void StoreSceneTextures( aiScene* pScene);
void StoreSceneTextures(aiScene *pScene);
/** Stores all animations
* @param pScene target scene to store the anims
*/
void StoreAnimations( aiScene* pScene, const ColladaParser& pParser);
void StoreAnimations(aiScene *pScene, const ColladaParser &pParser);
/** Stores all animations for the given source anim and its nested child animations
* @param pScene target scene to store the anims
* @param pSrcAnim the source animation to process
* @param pPrefix Prefix to the name in case of nested animations
*/
void StoreAnimations( aiScene* pScene, const ColladaParser& pParser, const Collada::Animation* pSrcAnim, const std::string& pPrefix);
void StoreAnimations(aiScene *pScene, const ColladaParser &pParser, const Collada::Animation *pSrcAnim, const std::string &pPrefix);
/** Constructs the animation for the given source anim */
void CreateAnimation( aiScene* pScene, const ColladaParser& pParser, const Collada::Animation* pSrcAnim, const std::string& pName);
void CreateAnimation(aiScene *pScene, const ColladaParser &pParser, const Collada::Animation *pSrcAnim, const std::string &pName);
/** Constructs materials from the collada material definitions */
void BuildMaterials( ColladaParser& pParser, aiScene* pScene);
void BuildMaterials(ColladaParser &pParser, aiScene *pScene);
/** Fill materials from the collada material definitions */
void FillMaterials( const ColladaParser& pParser, aiScene* pScene);
void FillMaterials(const ColladaParser &pParser, aiScene *pScene);
/** Resolve UV channel mappings*/
void ApplyVertexToEffectSemanticMapping(Collada::Sampler& sampler,
const Collada::SemanticMappingTable& table);
void ApplyVertexToEffectSemanticMapping(Collada::Sampler &sampler,
const Collada::SemanticMappingTable &table);
/** Add a texture and all of its sampling properties to a material*/
void AddTexture ( aiMaterial& mat, const ColladaParser& pParser,
const Collada::Effect& effect,
const Collada::Sampler& sampler,
aiTextureType type, unsigned int idx = 0);
void AddTexture(aiMaterial &mat, const ColladaParser &pParser,
const Collada::Effect &effect,
const Collada::Sampler &sampler,
aiTextureType type, unsigned int idx = 0);
/** Resolves the texture name for the given effect texture entry */
aiString FindFilenameForEffectTexture( const ColladaParser& pParser,
const Collada::Effect& pEffect, const std::string& pName);
aiString FindFilenameForEffectTexture(const ColladaParser &pParser,
const Collada::Effect &pEffect, const std::string &pName);
/** Reads a float value from an accessor and its data array.
* @param pAccessor The accessor to use for reading
@@ -191,7 +184,7 @@ protected:
* @param pOffset Offset into the element, for multipart elements such as vectors or matrices
* @return the specified value
*/
ai_real ReadFloat( const Collada::Accessor& pAccessor, const Collada::Data& pData, size_t pIndex, size_t pOffset) const;
ai_real ReadFloat(const Collada::Accessor &pAccessor, const Collada::Data &pData, size_t pIndex, size_t pOffset) const;
/** Reads a string value from an accessor and its data array.
* @param pAccessor The accessor to use for reading
@@ -199,18 +192,18 @@ protected:
* @param pIndex The index of the element to retrieve
* @return the specified value
*/
const std::string& ReadString( const Collada::Accessor& pAccessor, const Collada::Data& pData, size_t pIndex) const;
const std::string &ReadString(const Collada::Accessor &pAccessor, const Collada::Data &pData, size_t pIndex) const;
/** Recursively collects all nodes into the given array */
void CollectNodes( const aiNode* pNode, std::vector<const aiNode*>& poNodes) const;
void CollectNodes(const aiNode *pNode, std::vector<const aiNode *> &poNodes) const;
/** Finds a node in the collada scene by the given name */
const Collada::Node* FindNode( const Collada::Node* pNode, const std::string& pName) const;
const Collada::Node *FindNode(const Collada::Node *pNode, const std::string &pName) const;
/** Finds a node in the collada scene by the given SID */
const Collada::Node* FindNodeBySID( const Collada::Node* pNode, const std::string& pSID) const;
const Collada::Node *FindNodeBySID(const Collada::Node *pNode, const std::string &pSID) const;
/** Finds a proper name for a node derived from the collada-node's properties */
std::string FindNameForNode( const Collada::Node* pNode);
std::string FindNameForNode(const Collada::Node *pNode);
protected:
/** Filename, for a verbose error message */
@@ -223,25 +216,25 @@ protected:
std::map<std::string, size_t> mMaterialIndexByName;
/** Accumulated meshes for the target scene */
std::vector<aiMesh*> mMeshes;
std::vector<aiMesh *> mMeshes;
/** Accumulated morph target meshes */
std::vector<aiMesh*> mTargetMeshes;
std::vector<aiMesh *> mTargetMeshes;
/** Temporary material list */
std::vector<std::pair<Collada::Effect*, aiMaterial*> > newMats;
std::vector<std::pair<Collada::Effect *, aiMaterial *>> newMats;
/** Temporary camera list */
std::vector<aiCamera*> mCameras;
std::vector<aiCamera *> mCameras;
/** Temporary light list */
std::vector<aiLight*> mLights;
std::vector<aiLight *> mLights;
/** Temporary texture list */
std::vector<aiTexture*> mTextures;
std::vector<aiTexture *> mTextures;
/** Accumulated animations for the target scene */
std::vector<aiAnimation*> mAnims;
std::vector<aiAnimation *> mAnims;
bool noSkeletonMesh;
bool ignoreUpDirection;

View File

@@ -54,6 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/light.h>
#include <assimp/DefaultLogger.hpp>
#include <assimp/IOSystem.hpp>
#include <memory>
using namespace Assimp;
using namespace Assimp::Collada;
@@ -158,9 +159,9 @@ ColladaParser::ColladaParser(IOSystem *pIOHandler, const std::string &pFile) :
if (colladaNode.empty()) {
return;
}
ReadContents(colladaNode);
// read embedded textures
// Read content and embedded textures
ReadContents(colladaNode);
if (zip_archive && zip_archive->isOpen()) {
ReadEmbeddedTextures(*zip_archive);
}
@@ -169,11 +170,11 @@ ColladaParser::ColladaParser(IOSystem *pIOHandler, const std::string &pFile) :
// ------------------------------------------------------------------------------------------------
// Destructor, private as well
ColladaParser::~ColladaParser() {
for (NodeLibrary::iterator it = mNodeLibrary.begin(); it != mNodeLibrary.end(); ++it) {
delete it->second;
for (auto & it : mNodeLibrary) {
delete it.second;
}
for (MeshLibrary::iterator it = mMeshLibrary.begin(); it != mMeshLibrary.end(); ++it) {
delete it->second;
for (auto & it : mMeshLibrary) {
delete it.second;
}
}
@@ -289,7 +290,7 @@ void ColladaParser::ReadContents(XmlNode &node) {
// Reads the structure of the file
void ColladaParser::ReadStructure(XmlNode &node) {
for (XmlNode &currentNode : node.children()) {
const std::string &currentName = std::string(currentNode.name());
const std::string &currentName = currentNode.name();
if (currentName == "asset") {
ReadAssetInfo(currentNode);
} else if (currentName == "library_animations") {
@@ -407,7 +408,7 @@ void ColladaParser::ReadAnimationClipLibrary(XmlNode &node) {
const std::string &currentName = currentNode.name();
if (currentName == "instance_animation") {
std::string url;
readUrlAttribute(node, url);
readUrlAttribute(currentNode, url);
clip.second.push_back(url);
}
@@ -419,8 +420,8 @@ void ColladaParser::ReadAnimationClipLibrary(XmlNode &node) {
void ColladaParser::PostProcessControllers() {
std::string meshId;
for (ControllerLibrary::iterator it = mControllerLibrary.begin(); it != mControllerLibrary.end(); ++it) {
meshId = it->second.mMeshId;
for (auto & it : mControllerLibrary) {
meshId = it.second.mMeshId;
if (meshId.empty()) {
continue;
}
@@ -431,7 +432,7 @@ void ColladaParser::PostProcessControllers() {
findItr = mControllerLibrary.find(meshId);
}
it->second.mMeshId = meshId;
it.second.mMeshId = meshId;
}
}
@@ -444,17 +445,15 @@ void ColladaParser::PostProcessRootAnimations() {
}
Animation temp;
for (AnimationClipLibrary::iterator it = mAnimationClipLibrary.begin(); it != mAnimationClipLibrary.end(); ++it) {
std::string clipName = it->first;
for (auto & it : mAnimationClipLibrary) {
std::string clipName = it.first;
Animation *clip = new Animation();
clip->mName = clipName;
temp.mSubAnims.push_back(clip);
for (std::vector<std::string>::iterator a = it->second.begin(); a != it->second.end(); ++a) {
std::string animationID = *a;
for (std::string animationID : it.second) {
AnimationLibrary::iterator animation = mAnimationLibrary.find(animationID);
if (animation != mAnimationLibrary.end()) {
@@ -494,7 +493,7 @@ void ColladaParser::ReadAnimation(XmlNode &node, Collada::Animation *pParent) {
// an <animation> element may be a container for grouping sub-elements or an animation channel
// this is the channel collection by ID, in case it has channels
using ChannelMap = std::map<std::string, AnimationChannel> ;
using ChannelMap = std::map<std::string, AnimationChannel>;
ChannelMap channels;
// this is the anim container in case we're a container
Animation *anim = nullptr;
@@ -553,8 +552,8 @@ void ColladaParser::ReadAnimation(XmlNode &node, Collada::Animation *pParent) {
pParent->mSubAnims.push_back(anim);
}
for (ChannelMap::const_iterator it = channels.begin(); it != channels.end(); ++it) {
anim->mChannels.push_back(it->second);
for (const auto & channel : channels) {
anim->mChannels.push_back(channel.second);
}
if (idAttr) {
@@ -609,50 +608,62 @@ void ColladaParser::ReadControllerLibrary(XmlNode &node) {
if (currentName != "controller") {
continue;
}
std::string id = node.attribute("id").as_string();
mControllerLibrary[id] = Controller();
ReadController(node, mControllerLibrary[id]);
std::string id;
if (XmlParser::getStdStrAttribute(currentNode, "id", id)) {
mControllerLibrary[id] = Controller();
ReadController(currentNode, mControllerLibrary[id]);
}
}
}
// ------------------------------------------------------------------------------------------------
// Reads a controller into the given mesh structure
void ColladaParser::ReadController(XmlNode &node, Collada::Controller &pController) {
void ColladaParser::ReadController(XmlNode &node, Collada::Controller &controller) {
// initial values
pController.mType = Skin;
pController.mMethod = Normalized;
for (XmlNode &currentNode : node.children()) {
controller.mType = Skin;
controller.mMethod = Normalized;
XmlNodeIterator xmlIt(node);
xmlIt.collectChildrenPreOrder(node);
XmlNode currentNode;
while (xmlIt.getNext(currentNode)) {
//for (XmlNode &currentNode : node.children()) {
const std::string &currentName = currentNode.name();
if (currentName == "morph") {
pController.mType = Morph;
pController.mMeshId = currentNode.attribute("source").as_string();
controller.mType = Morph;
controller.mMeshId = currentNode.attribute("source").as_string();
int methodIndex = currentNode.attribute("method").as_int();
if (methodIndex > 0) {
std::string method;
XmlParser::getValueAsString(currentNode, method);
if (method == "RELATIVE") {
pController.mMethod = Relative;
controller.mMethod = Relative;
}
}
} else if (currentName == "skin") {
pController.mMeshId = currentNode.attribute("source").as_string();
std::string id;
if (XmlParser::getStdStrAttribute(currentNode, "source", id)) {
controller.mMeshId = id.substr(1, id.size()-1);
}
} else if (currentName == "bind_shape_matrix") {
std::string v;
XmlParser::getValueAsString(currentNode, v);
const char *content = v.c_str();
for (unsigned int a = 0; a < 16; a++) {
SkipSpacesAndLineEnd(&content);
// read a number
content = fast_atoreal_move<ai_real>(content, pController.mBindShapeMatrix[a]);
content = fast_atoreal_move<ai_real>(content, controller.mBindShapeMatrix[a]);
// skip whitespace after it
SkipSpacesAndLineEnd(&content);
}
} else if (currentName == "source") {
ReadSource(currentNode);
} else if (currentName == "joints") {
ReadControllerJoints(currentNode, pController);
ReadControllerJoints(currentNode, controller);
} else if (currentName == "vertex_weights") {
ReadControllerWeights(currentNode, pController);
ReadControllerWeights(currentNode, controller);
} else if (currentName == "targets") {
for (XmlNode currentChildNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
const std::string &currentChildName = currentChildNode.name();
@@ -660,9 +671,9 @@ void ColladaParser::ReadController(XmlNode &node, Collada::Controller &pControll
const char *semantics = currentChildNode.attribute("semantic").as_string();
const char *source = currentChildNode.attribute("source").as_string();
if (strcmp(semantics, "MORPH_TARGET") == 0) {
pController.mMorphTarget = source + 1;
controller.mMorphTarget = source + 1;
} else if (strcmp(semantics, "MORPH_WEIGHT") == 0) {
pController.mMorphWeight = source + 1;
controller.mMorphWeight = source + 1;
}
}
}
@@ -700,6 +711,7 @@ void ColladaParser::ReadControllerWeights(XmlNode &node, Collada::Controller &pC
// Read vertex count from attributes and resize the array accordingly
int vertexCount=0;
XmlParser::getIntAttribute(node, "count", vertexCount);
pController.mWeightCounts.resize(vertexCount);
for (XmlNode &currentNode : node.children()) {
const std::string &currentName = currentNode.name();
@@ -725,7 +737,7 @@ void ColladaParser::ReadControllerWeights(XmlNode &node, Collada::Controller &pC
throw DeadlyImportError("Unknown semantic \"", attrSemantic, "\" in <vertex_weights> data <input> element");
}
} else if (currentName == "vcount" && vertexCount > 0) {
const char *text = currentNode.value();
const char *text = currentNode.text().as_string();
size_t numWeights = 0;
for (std::vector<size_t>::iterator it = pController.mWeightCounts.begin(); it != pController.mWeightCounts.end(); ++it) {
if (*text == 0) {
@@ -762,18 +774,15 @@ void ColladaParser::ReadControllerWeights(XmlNode &node, Collada::Controller &pC
// ------------------------------------------------------------------------------------------------
// Reads the image library contents
void ColladaParser::ReadImageLibrary(XmlNode &node) {
if (node.empty()) {
return;
}
for (XmlNode &currentNode : node.children()) {
const std::string &currentName = currentNode.name();
if (currentName == "image") {
std::string id = currentNode.attribute("id").as_string();
mImageLibrary[id] = Image();
// read on from there
ReadImage(currentNode, mImageLibrary[id]);
std::string id;
if (XmlParser::getStdStrAttribute( currentNode, "id", id )) {
mImageLibrary[id] = Image();
// read on from there
ReadImage(currentNode, mImageLibrary[id]);
}
}
}
}
@@ -792,7 +801,7 @@ void ColladaParser::ReadImage(XmlNode &node, Collada::Image &pImage) {
if (!currentNode.empty()) {
// element content is filename - hopefully
const char *sz = currentNode.text().as_string();
if (sz) {
if (nullptr != sz) {
aiString filepath(sz);
UriDecodePath(filepath);
pImage.mFileName = filepath.C_Str();
@@ -842,10 +851,6 @@ void ColladaParser::ReadImage(XmlNode &node, Collada::Image &pImage) {
// ------------------------------------------------------------------------------------------------
// Reads the material library
void ColladaParser::ReadMaterialLibrary(XmlNode &node) {
if (node.empty()) {
return;
}
std::map<std::string, int> names;
for (XmlNode &currentNode : node.children()) {
std::string id = currentNode.attribute("id").as_string();
@@ -872,10 +877,6 @@ void ColladaParser::ReadMaterialLibrary(XmlNode &node) {
// ------------------------------------------------------------------------------------------------
// Reads the light library
void ColladaParser::ReadLightLibrary(XmlNode &node) {
if (node.empty()) {
return;
}
for (XmlNode &currentNode : node.children()) {
const std::string &currentName = currentNode.name();
if (currentName == "light") {
@@ -890,10 +891,6 @@ void ColladaParser::ReadLightLibrary(XmlNode &node) {
// ------------------------------------------------------------------------------------------------
// Reads the camera library
void ColladaParser::ReadCameraLibrary(XmlNode &node) {
if (node.empty()) {
return;
}
for (XmlNode &currentNode : node.children()) {
const std::string &currentName = currentNode.name();
if (currentName == "camera") {

View File

@@ -571,7 +571,6 @@ namespace glTF2 {
inline void Write(Value& obj, Node& n, AssetWriter& w)
{
if (n.matrix.isPresent) {
Value val;
obj.AddMember("matrix", MakeValue(val, n.matrix.value, w.mAl).Move(), w.mAl);
@@ -597,14 +596,13 @@ namespace glTF2 {
obj.AddMember("mesh", n.meshes[0]->index, w.mAl);
}
AddRefsVector(obj, "skeletons", n.skeletons, w.mAl);
if (n.skin) {
obj.AddMember("skin", n.skin->index, w.mAl);
}
if (!n.jointName.empty()) {
obj.AddMember("jointName", n.jointName, w.mAl);
//gltf2 spec does not support "skeletons" under node
if(n.skeletons.size()) {
AddRefsVector(obj, "skeletons", n.skeletons, w.mAl);
}
}

View File

@@ -1095,6 +1095,7 @@ void glTF2Exporter::ExportMeshes()
//----------------------------------------
// Finish the skin
// Create the Accessor for skinRef->inverseBindMatrices
bool bAddCustomizedProperty = this->mProperties->HasPropertyBool("GLTF2_CUSTOMIZE_PROPERTY");
if (createSkin) {
mat4* invBindMatrixData = new mat4[inverseBindMatricesData.size()];
for ( unsigned int idx_joint = 0; idx_joint < inverseBindMatricesData.size(); ++idx_joint) {
@@ -1110,7 +1111,7 @@ void glTF2Exporter::ExportMeshes()
// Identity Matrix =====> skinRef->bindShapeMatrix
// Temporary. Hard-coded identity matrix here
skinRef->bindShapeMatrix.isPresent = true;
skinRef->bindShapeMatrix.isPresent = bAddCustomizedProperty;
IdentityMatrix4(skinRef->bindShapeMatrix.value);
// Find nodes that contain a mesh with bones and add "skeletons" and "skin" attributes to those nodes.
@@ -1131,7 +1132,8 @@ void glTF2Exporter::ExportMeshes()
std::string meshID = mesh->id;
FindMeshNode(rootNode, meshNode, meshID);
Ref<Node> rootJoint = FindSkeletonRootJoint(skinRef);
meshNode->skeletons.push_back(rootJoint);
if(bAddCustomizedProperty)
meshNode->skeletons.push_back(rootJoint);
meshNode->skin = skinRef;
}
delete[] invBindMatrixData;