Bugfix/ensure collada parsing works issue 1488 (#6087)
* Add text to ensure that float parsing in colladata works right
This commit is contained in:
@@ -89,6 +89,14 @@ inline void AddNodeMetaData(aiNode *node, const std::string &key, const T &value
|
||||
node->mMetaData->Add(key, value);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads a float value from an accessor and its data array.
|
||||
static ai_real ReadFloat(const Accessor &pAccessor, const Data &pData, size_t pIndex, size_t pOffset) {
|
||||
size_t pos = pAccessor.mStride * pIndex + pAccessor.mOffset + pOffset;
|
||||
ai_assert(pos < pData.mValues.size());
|
||||
return pData.mValues[pos];
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
ColladaLoader::ColladaLoader() :
|
||||
@@ -152,7 +160,7 @@ void ColladaLoader::InternReadFile(const std::string &pFile, aiScene *pScene, IO
|
||||
throw DeadlyImportError("Collada: File came out empty. Something is wrong here.");
|
||||
}
|
||||
|
||||
// reserve some storage to avoid unnecessary reallocs
|
||||
// reserve some storage to avoid unnecessary reallocates
|
||||
newMats.reserve(parser.mMaterialLibrary.size() * 2u);
|
||||
mMeshes.reserve(parser.mMeshLibrary.size() * 2u);
|
||||
|
||||
@@ -224,7 +232,7 @@ void ColladaLoader::InternReadFile(const std::string &pFile, aiScene *pScene, IO
|
||||
// Recursively constructs a scene node for the given parser node and returns it.
|
||||
aiNode *ColladaLoader::BuildHierarchy(const ColladaParser &pParser, const Collada::Node *pNode) {
|
||||
// create a node for it
|
||||
aiNode *node = new aiNode();
|
||||
auto *node = new aiNode();
|
||||
|
||||
// find a name for the new node. It's more complicated than you might think
|
||||
node->mName.Set(FindNameForNode(pNode));
|
||||
@@ -272,24 +280,24 @@ aiNode *ColladaLoader::BuildHierarchy(const ColladaParser &pParser, const Collad
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Resolve node instances
|
||||
void ColladaLoader::ResolveNodeInstances(const ColladaParser &pParser, const Node *pNode,
|
||||
std::vector<const Node*> &resolved) {
|
||||
std::vector<const Node*> &resolved) const {
|
||||
// reserve enough storage
|
||||
resolved.reserve(pNode->mNodeInstances.size());
|
||||
|
||||
// ... and iterate through all nodes to be instanced as children of pNode
|
||||
for (const auto &nodeInst : pNode->mNodeInstances) {
|
||||
for (const auto &[mNode] : pNode->mNodeInstances) {
|
||||
// find the corresponding node in the library
|
||||
const ColladaParser::NodeLibrary::const_iterator itt = pParser.mNodeLibrary.find(nodeInst.mNode);
|
||||
const auto itt = pParser.mNodeLibrary.find(mNode);
|
||||
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,
|
||||
// the workaround is only enabled when the first attempt to resolve the node has failed.
|
||||
if (nullptr == nd) {
|
||||
nd = FindNode(pParser.mRootNode, nodeInst.mNode);
|
||||
nd = FindNode(pParser.mRootNode, mNode);
|
||||
}
|
||||
if (nullptr == nd) {
|
||||
ASSIMP_LOG_ERROR("Collada: Unable to resolve reference to instanced node ", nodeInst.mNode);
|
||||
ASSIMP_LOG_ERROR("Collada: Unable to resolve reference to instanced node ", mNode);
|
||||
} else {
|
||||
// attach this node to the list of children
|
||||
resolved.push_back(nd);
|
||||
@@ -299,8 +307,8 @@ void ColladaLoader::ResolveNodeInstances(const ColladaParser &pParser, const Nod
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Resolve UV channels
|
||||
void ColladaLoader::ApplyVertexToEffectSemanticMapping(Sampler &sampler, const SemanticMappingTable &table) {
|
||||
SemanticMappingTable::InputSemanticMap::const_iterator it = table.mMap.find(sampler.mUVChannel);
|
||||
static void ApplyVertexToEffectSemanticMapping(Sampler &sampler, const SemanticMappingTable &table) {
|
||||
const auto it = table.mMap.find(sampler.mUVChannel);
|
||||
if (it == table.mMap.end()) {
|
||||
return;
|
||||
}
|
||||
@@ -317,7 +325,7 @@ void ColladaLoader::ApplyVertexToEffectSemanticMapping(Sampler &sampler, const S
|
||||
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);
|
||||
auto srcLightIt = pParser.mLightLibrary.find(lid.mLight);
|
||||
if (srcLightIt == pParser.mLightLibrary.end()) {
|
||||
ASSIMP_LOG_WARN("Collada: Unable to find light for ID \"", lid.mLight, "\". Skipping.");
|
||||
continue;
|
||||
@@ -325,7 +333,7 @@ void ColladaLoader::BuildLightsForNode(const ColladaParser &pParser, const Node
|
||||
const Collada::Light *srcLight = &srcLightIt->second;
|
||||
|
||||
// now fill our ai data structure
|
||||
aiLight *out = new aiLight();
|
||||
auto out = new aiLight();
|
||||
out->mName = pTarget->mName;
|
||||
out->mType = (aiLightSourceType)srcLight->mType;
|
||||
|
||||
@@ -382,7 +390,7 @@ void ColladaLoader::BuildLightsForNode(const ColladaParser &pParser, const Node
|
||||
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);
|
||||
auto srcCameraIt = pParser.mCameraLibrary.find(cid.mCamera);
|
||||
if (srcCameraIt == pParser.mCameraLibrary.end()) {
|
||||
ASSIMP_LOG_WARN("Collada: Unable to find camera for ID \"", cid.mCamera, "\". Skipping.");
|
||||
continue;
|
||||
@@ -395,7 +403,7 @@ void ColladaLoader::BuildCamerasForNode(const ColladaParser &pParser, const Node
|
||||
}
|
||||
|
||||
// now fill our ai data structure
|
||||
aiCamera *out = new aiCamera();
|
||||
auto *out = new aiCamera();
|
||||
out->mName = pTarget->mName;
|
||||
|
||||
// collada cameras point in -Z by default, rest is specified in node transform
|
||||
@@ -445,10 +453,10 @@ void ColladaLoader::BuildMeshesForNode(const ColladaParser &pParser, const Node
|
||||
const Controller *srcController = nullptr;
|
||||
|
||||
// find the referred mesh
|
||||
ColladaParser::MeshLibrary::const_iterator srcMeshIt = pParser.mMeshLibrary.find(mid.mMeshOrController);
|
||||
auto srcMeshIt = pParser.mMeshLibrary.find(mid.mMeshOrController);
|
||||
if (srcMeshIt == pParser.mMeshLibrary.end()) {
|
||||
// if not found in the mesh-library, it might also be a controller referring to a mesh
|
||||
ColladaParser::ControllerLibrary::const_iterator srcContrIt = pParser.mControllerLibrary.find(mid.mMeshOrController);
|
||||
auto srcContrIt = pParser.mControllerLibrary.find(mid.mMeshOrController);
|
||||
if (srcContrIt != pParser.mControllerLibrary.end()) {
|
||||
srcController = &srcContrIt->second;
|
||||
srcMeshIt = pParser.mMeshLibrary.find(srcController->mMeshId);
|
||||
@@ -462,7 +470,7 @@ void ColladaLoader::BuildMeshesForNode(const ColladaParser &pParser, const Node
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
// ID found in the mesh library -> direct reference to an unskinned mesh
|
||||
// ID found in the mesh library -> direct reference to a not skinned mesh
|
||||
srcMesh = srcMeshIt->second;
|
||||
}
|
||||
|
||||
@@ -476,7 +484,7 @@ void ColladaLoader::BuildMeshesForNode(const ColladaParser &pParser, const Node
|
||||
|
||||
// find material assigned to this submesh
|
||||
std::string meshMaterial;
|
||||
std::map<std::string, SemanticMappingTable>::const_iterator meshMatIt = mid.mMaterials.find(submesh.mMaterial);
|
||||
auto meshMatIt = mid.mMaterials.find(submesh.mMaterial);
|
||||
|
||||
const Collada::SemanticMappingTable *table = nullptr;
|
||||
if (meshMatIt != mid.mMaterials.end()) {
|
||||
@@ -492,7 +500,7 @@ void ColladaLoader::BuildMeshesForNode(const ColladaParser &pParser, const Node
|
||||
|
||||
// OK ... here the *real* fun starts ... we have the vertex-input-to-effect-semantic-table
|
||||
// given. The only mapping stuff which we do actually support is the UV channel.
|
||||
std::map<std::string, size_t>::const_iterator matIt = mMaterialIndexByName.find(meshMaterial);
|
||||
auto matIt = mMaterialIndexByName.find(meshMaterial);
|
||||
unsigned int matIdx = 0;
|
||||
if (matIt != mMaterialIndexByName.end()) {
|
||||
matIdx = static_cast<unsigned int>(matIt->second);
|
||||
@@ -515,7 +523,7 @@ void ColladaLoader::BuildMeshesForNode(const ColladaParser &pParser, const Node
|
||||
ColladaMeshIndex index(mid.mMeshOrController, sm, meshMaterial);
|
||||
|
||||
// if we already have the mesh at the library, just add its index to the node's array
|
||||
std::map<ColladaMeshIndex, size_t>::const_iterator dstMeshIt = mMeshIndexByID.find(index);
|
||||
auto dstMeshIt = mMeshIndexByID.find(index);
|
||||
if (dstMeshIt != mMeshIndexByID.end()) {
|
||||
newMeshRefs.push_back(dstMeshIt->second);
|
||||
} else {
|
||||
@@ -530,7 +538,7 @@ void ColladaLoader::BuildMeshesForNode(const ColladaParser &pParser, const Node
|
||||
faceStart += submesh.mNumFaces;
|
||||
|
||||
// assign the material index
|
||||
std::map<std::string, size_t>::const_iterator subMatIt = mMaterialIndexByName.find(submesh.mMaterial);
|
||||
auto subMatIt = mMaterialIndexByName.find(submesh.mMaterial);
|
||||
if (subMatIt != mMaterialIndexByName.end()) {
|
||||
dstMesh->mMaterialIndex = static_cast<unsigned int>(subMatIt->second);
|
||||
} else {
|
||||
@@ -618,7 +626,7 @@ aiMesh *ColladaLoader::CreateMesh(const ColladaParser &pParser, const Mesh *pSrc
|
||||
std::copy(pSrcMesh->mTangents.begin() + pStartVertex, pSrcMesh->mTangents.begin() + pStartVertex + numVertices, dstMesh->mTangents);
|
||||
}
|
||||
|
||||
// bitangents, if given.
|
||||
// bi-tangents, if given.
|
||||
if (pSrcMesh->mBitangents.size() >= pStartVertex + numVertices) {
|
||||
dstMesh->mBitangents = new aiVector3D[numVertices];
|
||||
std::copy(pSrcMesh->mBitangents.begin() + pStartVertex, pSrcMesh->mBitangents.begin() + pStartVertex + numVertices, dstMesh->mBitangents);
|
||||
@@ -664,7 +672,7 @@ aiMesh *ColladaLoader::CreateMesh(const ColladaParser &pParser, const Mesh *pSrc
|
||||
std::vector<float> targetWeights;
|
||||
Collada::MorphMethod method = Normalized;
|
||||
|
||||
for (std::map<std::string, Controller>::const_iterator it = pParser.mControllerLibrary.begin();
|
||||
for (auto it = pParser.mControllerLibrary.begin();
|
||||
it != pParser.mControllerLibrary.end(); ++it) {
|
||||
const Controller &c = it->second;
|
||||
const Collada::Mesh *baseMesh = pParser.ResolveLibraryReference(pParser.mMeshLibrary, c.mMeshId);
|
||||
@@ -754,7 +762,7 @@ aiMesh *ColladaLoader::CreateMesh(const ColladaParser &pParser, const Mesh *pSrc
|
||||
std::vector<IndexPairVector::const_iterator> weightStartPerVertex;
|
||||
weightStartPerVertex.resize(pSrcController->mWeightCounts.size(), pSrcController->mWeights.end());
|
||||
|
||||
IndexPairVector::const_iterator pit = pSrcController->mWeights.begin();
|
||||
auto pit = pSrcController->mWeights.begin();
|
||||
for (size_t a = 0; a < pSrcController->mWeightCounts.size(); ++a) {
|
||||
weightStartPerVertex[a] = pit;
|
||||
pit += pSrcController->mWeightCounts[a];
|
||||
@@ -766,7 +774,7 @@ aiMesh *ColladaLoader::CreateMesh(const ColladaParser &pParser, const Mesh *pSrc
|
||||
// the controller assigns the vertex weights
|
||||
size_t orgIndex = pSrcMesh->mFacePosIndices[a];
|
||||
// find the vertex weights for this vertex
|
||||
IndexPairVector::const_iterator iit = weightStartPerVertex[orgIndex];
|
||||
auto iit = weightStartPerVertex[orgIndex];
|
||||
size_t pairCount = pSrcController->mWeightCounts[orgIndex];
|
||||
|
||||
for (size_t b = 0; b < pairCount; ++b, ++iit) {
|
||||
@@ -807,7 +815,7 @@ aiMesh *ColladaLoader::CreateMesh(const ColladaParser &pParser, const Mesh *pSrc
|
||||
}
|
||||
|
||||
// create bone with its weights
|
||||
aiBone *bone = new aiBone;
|
||||
auto bone = new aiBone;
|
||||
bone->mName = ReadString(jointNamesAcc, jointNames, a);
|
||||
bone->mOffsetMatrix.a1 = ReadFloat(jointMatrixAcc, jointMatrices, a, 0);
|
||||
bone->mOffsetMatrix.a2 = ReadFloat(jointMatrixAcc, jointMatrices, a, 1);
|
||||
@@ -973,7 +981,7 @@ void ColladaLoader::StoreAnimations(aiScene *pScene, const ColladaParser &pParse
|
||||
|
||||
// if there are other animations which fit the template anim, combine all channels into a single anim
|
||||
if (!collectedAnimIndices.empty()) {
|
||||
aiAnimation *combinedAnim = new aiAnimation();
|
||||
auto *combinedAnim = new aiAnimation();
|
||||
combinedAnim->mName = aiString(std::string("combinedAnim_") + char('0' + a));
|
||||
combinedAnim->mDuration = templateAnim->mDuration;
|
||||
combinedAnim->mTicksPerSecond = templateAnim->mTicksPerSecond;
|
||||
@@ -1040,7 +1048,7 @@ struct MorphTimeValues {
|
||||
};
|
||||
|
||||
void insertMorphTimeValue(std::vector<MorphTimeValues> &values, float time, float weight, unsigned int value) {
|
||||
MorphTimeValues::key k;
|
||||
MorphTimeValues::key k{};
|
||||
k.mValue = value;
|
||||
k.mWeight = weight;
|
||||
if (values.empty() || time < values[0].mTime) {
|
||||
@@ -1106,7 +1114,7 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
|
||||
|
||||
// now check all channels if they affect the current node
|
||||
std::string targetID, subElement;
|
||||
for (std::vector<AnimationChannel>::const_iterator cit = pSrcAnim->mChannels.begin();
|
||||
for (auto cit = pSrcAnim->mChannels.begin();
|
||||
cit != pSrcAnim->mChannels.end(); ++cit) {
|
||||
const AnimationChannel &srcChannel = *cit;
|
||||
ChannelEntry entry;
|
||||
@@ -1349,7 +1357,7 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
|
||||
|
||||
// build an animation channel for the given node out of these trafo keys
|
||||
if (!resultTrafos.empty()) {
|
||||
aiNodeAnim *dstAnim = new aiNodeAnim;
|
||||
auto *dstAnim = new aiNodeAnim;
|
||||
dstAnim->mNodeName = nodeName;
|
||||
dstAnim->mNumPositionKeys = static_cast<unsigned int>(resultTrafos.size());
|
||||
dstAnim->mNumRotationKeys = static_cast<unsigned int>(resultTrafos.size());
|
||||
@@ -1391,7 +1399,7 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
|
||||
// or 2) one channel with morph target count arrays
|
||||
// assume first
|
||||
|
||||
aiMeshMorphAnim *morphAnim = new aiMeshMorphAnim;
|
||||
auto *morphAnim = new aiMeshMorphAnim;
|
||||
morphAnim->mName.Set(nodeName);
|
||||
|
||||
std::vector<MorphTimeValues> morphTimeValues;
|
||||
@@ -1434,7 +1442,7 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
|
||||
}
|
||||
|
||||
if (!anims.empty() || !morphAnims.empty()) {
|
||||
aiAnimation *anim = new aiAnimation;
|
||||
auto anim = new aiAnimation;
|
||||
anim->mName.Set(pName);
|
||||
anim->mNumChannels = static_cast<unsigned int>(anims.size());
|
||||
if (anim->mNumChannels > 0) {
|
||||
@@ -1514,7 +1522,7 @@ void ColladaLoader::AddTexture(aiMaterial &mat,
|
||||
map = sampler.mUVId;
|
||||
} else {
|
||||
map = -1;
|
||||
for (std::string::const_iterator it = sampler.mUVChannel.begin(); it != sampler.mUVChannel.end(); ++it) {
|
||||
for (auto it = sampler.mUVChannel.begin(); it != sampler.mUVChannel.end(); ++it) {
|
||||
if (IsNumeric(*it)) {
|
||||
map = strtoul10(&(*it));
|
||||
break;
|
||||
@@ -1532,7 +1540,7 @@ void ColladaLoader::AddTexture(aiMaterial &mat,
|
||||
// Fills materials from the collada material definitions
|
||||
void ColladaLoader::FillMaterials(const ColladaParser &pParser, aiScene * /*pScene*/) {
|
||||
for (auto &elem : newMats) {
|
||||
aiMaterial &mat = (aiMaterial &)*elem.second;
|
||||
auto &mat = (aiMaterial &)*elem.second;
|
||||
Collada::Effect &effect = *elem.first;
|
||||
|
||||
// resolve shading mode
|
||||
@@ -1642,17 +1650,17 @@ void ColladaLoader::FillMaterials(const ColladaParser &pParser, aiScene * /*pSce
|
||||
void ColladaLoader::BuildMaterials(ColladaParser &pParser, aiScene * /*pScene*/) {
|
||||
newMats.reserve(pParser.mMaterialLibrary.size());
|
||||
|
||||
for (ColladaParser::MaterialLibrary::const_iterator matIt = pParser.mMaterialLibrary.begin();
|
||||
for (auto matIt = pParser.mMaterialLibrary.begin();
|
||||
matIt != pParser.mMaterialLibrary.end(); ++matIt) {
|
||||
const Material &material = matIt->second;
|
||||
// a material is only a reference to an effect
|
||||
ColladaParser::EffectLibrary::iterator effIt = pParser.mEffectLibrary.find(material.mEffect);
|
||||
auto effIt = pParser.mEffectLibrary.find(material.mEffect);
|
||||
if (effIt == pParser.mEffectLibrary.end())
|
||||
continue;
|
||||
Effect &effect = effIt->second;
|
||||
|
||||
// create material
|
||||
aiMaterial *mat = new aiMaterial;
|
||||
auto *mat = new aiMaterial;
|
||||
aiString name(material.mName.empty() ? matIt->first : material.mName);
|
||||
mat->AddProperty(&name, AI_MATKEY_NAME);
|
||||
|
||||
@@ -1675,7 +1683,7 @@ aiString ColladaLoader::FindFilenameForEffectTexture(const ColladaParser &pParse
|
||||
std::string name = pName;
|
||||
while (true) {
|
||||
// the given string is a param entry. Find it
|
||||
Effect::ParamLibrary::const_iterator it = pEffect.mParams.find(name);
|
||||
auto 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;
|
||||
@@ -1685,7 +1693,7 @@ aiString ColladaLoader::FindFilenameForEffectTexture(const ColladaParser &pParse
|
||||
}
|
||||
|
||||
// find the image referred by this name in the image library of the scene
|
||||
ColladaParser::ImageLibrary::const_iterator imIt = pParser.mImageLibrary.find(name);
|
||||
auto imIt = pParser.mImageLibrary.find(name);
|
||||
if (imIt == pParser.mImageLibrary.end()) {
|
||||
ASSIMP_LOG_WARN("Collada: Unable to resolve effect texture entry \"", pName, "\", ended up at ID \"", name, "\".");
|
||||
|
||||
@@ -1697,7 +1705,7 @@ aiString ColladaLoader::FindFilenameForEffectTexture(const ColladaParser &pParse
|
||||
|
||||
// if this is an embedded texture image setup an aiTexture for it
|
||||
if (!imIt->second.mImageData.empty()) {
|
||||
aiTexture *tex = new aiTexture();
|
||||
auto *tex = new aiTexture();
|
||||
|
||||
// Store embedded texture name reference
|
||||
tex->mFilename.Set(imIt->second.mFileName.c_str());
|
||||
@@ -1729,14 +1737,6 @@ aiString ColladaLoader::FindFilenameForEffectTexture(const ColladaParser &pParse
|
||||
return result;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads a float value from an accessor and its data array.
|
||||
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];
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads a string value from an accessor and its data array.
|
||||
const std::string &ColladaLoader::ReadString(const Accessor &pAccessor, const Data &pData, size_t pIndex) const {
|
||||
|
||||
@@ -109,7 +109,7 @@ protected:
|
||||
|
||||
/// Resolve node instances
|
||||
void ResolveNodeInstances(const ColladaParser &pParser, const Collada::Node *pNode,
|
||||
std::vector<const Collada::Node *> &resolved);
|
||||
std::vector<const Collada::Node *> &resolved) const;
|
||||
|
||||
/// Builds meshes for the given node and references them
|
||||
void BuildMeshesForNode(const ColladaParser &pParser, const Collada::Node *pNode,
|
||||
@@ -166,10 +166,6 @@ protected:
|
||||
/** Fill materials from the collada material definitions */
|
||||
void FillMaterials(const ColladaParser &pParser, aiScene *pScene);
|
||||
|
||||
/** Resolve UV channel mappings*/
|
||||
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,
|
||||
@@ -180,22 +176,13 @@ protected:
|
||||
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
|
||||
* @param pData The data array to read from
|
||||
* @param pIndex The index of the element to retrieve
|
||||
* @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;
|
||||
|
||||
/** Reads a string value from an accessor and its data array.
|
||||
* @param pAccessor The accessor to use for reading
|
||||
* @param pData The data array to read from
|
||||
* @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;
|
||||
[[nodiscard]] 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;
|
||||
@@ -208,7 +195,7 @@ protected:
|
||||
/** Finds a proper name for a node derived from the collada-node's properties */
|
||||
std::string FindNameForNode(const Collada::Node *pNode);
|
||||
|
||||
protected:
|
||||
private:
|
||||
/** Filename, for a verbose error message */
|
||||
std::string mFileName;
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@ using namespace Assimp;
|
||||
using namespace Assimp::Collada;
|
||||
using namespace Assimp::Formatter;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static void ReportWarning(const char *msg, ...) {
|
||||
ai_assert(nullptr != msg);
|
||||
|
||||
@@ -75,6 +76,7 @@ static void ReportWarning(const char *msg, ...) {
|
||||
ASSIMP_LOG_WARN("Validation warning: ", std::string(szBuffer, iLen));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static bool FindCommonKey(const std::string &collada_key, const MetaKeyPairVector &key_renaming, size_t &found_index) {
|
||||
for (size_t i = 0; i < key_renaming.size(); ++i) {
|
||||
if (key_renaming[i].first == collada_key) {
|
||||
@@ -87,6 +89,7 @@ static bool FindCommonKey(const std::string &collada_key, const MetaKeyPairVecto
|
||||
return false;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static void readUrlAttribute(XmlNode &node, std::string &url) {
|
||||
url.clear();
|
||||
if (!XmlParser::getStdStrAttribute(node, "url", url)) {
|
||||
@@ -98,23 +101,319 @@ static void readUrlAttribute(XmlNode &node, std::string &url) {
|
||||
url = url.c_str() + 1;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads a node transformation entry of the given type and adds it to the given node's transformation list.
|
||||
static void ReadNodeTransformation(XmlNode &node, Node *pNode, TransformType pType) {
|
||||
if (node.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string tagName = node.name();
|
||||
|
||||
Transform tf;
|
||||
tf.mType = pType;
|
||||
|
||||
// read SID
|
||||
if (XmlParser::hasAttribute(node, "sid")) {
|
||||
XmlParser::getStdStrAttribute(node, "sid", tf.mID);
|
||||
}
|
||||
|
||||
// how many parameters to read per transformation type
|
||||
static constexpr unsigned int sNumParameters[] = { 9, 4, 3, 3, 7, 16 };
|
||||
std::string value;
|
||||
XmlParser::getValueAsString(node, value);
|
||||
const char *content = value.c_str();
|
||||
const char *end = value.c_str() + value.size();
|
||||
// read as many parameters and store in the transformation
|
||||
for (unsigned int a = 0; a < sNumParameters[pType]; a++) {
|
||||
// skip whitespace before the number
|
||||
SkipSpacesAndLineEnd(&content, end);
|
||||
// read a number
|
||||
content = fast_atoreal_move<ai_real>(content, tf.f[a]);
|
||||
}
|
||||
|
||||
// place the transformation at the queue of the node
|
||||
pNode->mTransforms.push_back(tf);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads a single string metadata item
|
||||
static void ReadMetaDataItem(XmlNode &node, ColladaParser::StringMetaData &metadata) {
|
||||
const MetaKeyPairVector &key_renaming = GetColladaAssimpMetaKeysCamelCase();
|
||||
const std::string name = node.name();
|
||||
if (name.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string v;
|
||||
if (!XmlParser::getValueAsString(node, v)) {
|
||||
return;
|
||||
}
|
||||
|
||||
v = ai_trim(v);
|
||||
aiString aistr;
|
||||
aistr.Set(v);
|
||||
|
||||
std::string camel_key_str(name);
|
||||
ToCamelCase(camel_key_str);
|
||||
|
||||
size_t found_index;
|
||||
if (FindCommonKey(camel_key_str, key_renaming, found_index)) {
|
||||
metadata.emplace(key_renaming[found_index].second, aistr);
|
||||
} else {
|
||||
metadata.emplace(camel_key_str, aistr);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads an animation sampler into the given anim channel
|
||||
static void ReadAnimationSampler(const XmlNode &node, AnimationChannel &pChannel) {
|
||||
for (XmlNode ¤tNode : node.children()) {
|
||||
const std::string ¤tName = currentNode.name();
|
||||
if (currentName == "input") {
|
||||
if (XmlParser::hasAttribute(currentNode, "semantic")) {
|
||||
std::string semantic, sourceAttr;
|
||||
XmlParser::getStdStrAttribute(currentNode, "semantic", semantic);
|
||||
if (XmlParser::hasAttribute(currentNode, "source")) {
|
||||
XmlParser::getStdStrAttribute(currentNode, "source", sourceAttr);
|
||||
const char *source = sourceAttr.c_str();
|
||||
if (source[0] != '#') {
|
||||
throw DeadlyImportError("Unsupported URL format");
|
||||
}
|
||||
source++;
|
||||
|
||||
if (semantic == "INPUT") {
|
||||
pChannel.mSourceTimes = source;
|
||||
} else if (semantic == "OUTPUT") {
|
||||
pChannel.mSourceValues = source;
|
||||
} else if (semantic == "IN_TANGENT") {
|
||||
pChannel.mInTanValues = source;
|
||||
} else if (semantic == "OUT_TANGENT") {
|
||||
pChannel.mOutTanValues = source;
|
||||
} else if (semantic == "INTERPOLATION") {
|
||||
pChannel.mInterpolationValues = source;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads the joint definitions for the given controller
|
||||
static void ReadControllerJoints(const XmlNode &node, Controller &pController) {
|
||||
for (XmlNode ¤tNode : node.children()) {
|
||||
const std::string ¤tName = currentNode.name();
|
||||
if (currentName == "input") {
|
||||
const char *attrSemantic = currentNode.attribute("semantic").as_string();
|
||||
const char *attrSource = currentNode.attribute("source").as_string();
|
||||
if (attrSource[0] != '#') {
|
||||
throw DeadlyImportError("Unsupported URL format in \"", attrSource, "\" in source attribute of <joints> data <input> element");
|
||||
}
|
||||
++attrSource;
|
||||
// parse source URL to corresponding source
|
||||
if (strcmp(attrSemantic, "JOINT") == 0) {
|
||||
pController.mJointNameSource = attrSource;
|
||||
} else if (strcmp(attrSemantic, "INV_BIND_MATRIX") == 0) {
|
||||
pController.mJointOffsetMatrixSource = attrSource;
|
||||
} else {
|
||||
throw DeadlyImportError("Unknown semantic \"", attrSemantic, "\" in <joints> data <input> element");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static void ReadControllerWeightsInput(const XmlNode ¤tNode, Controller &pController) {
|
||||
InputChannel channel;
|
||||
|
||||
const char *attrSemantic = currentNode.attribute("semantic").as_string();
|
||||
const char *attrSource = currentNode.attribute("source").as_string();
|
||||
channel.mOffset = currentNode.attribute("offset").as_int();
|
||||
|
||||
// local URLS always start with a '#'. We don't support global URLs
|
||||
if (attrSource[0] != '#') {
|
||||
throw DeadlyImportError("Unsupported URL format in \"", attrSource, "\" in source attribute of <vertex_weights> data <input> element");
|
||||
}
|
||||
channel.mAccessor = attrSource + 1;
|
||||
|
||||
// parse source URL to corresponding source
|
||||
if (strcmp(attrSemantic, "JOINT") == 0) {
|
||||
pController.mWeightInputJoints = channel;
|
||||
} else if (strcmp(attrSemantic, "WEIGHT") == 0) {
|
||||
pController.mWeightInputWeights = channel;
|
||||
} else {
|
||||
throw DeadlyImportError("Unknown semantic \"", attrSemantic, "\" in <vertex_weights> data <input> element");
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static void ReadControllerWeightsVCount(const XmlNode ¤tNode, Controller &pController) {
|
||||
const std::string stdText = currentNode.text().as_string();
|
||||
const char *text = stdText.c_str();
|
||||
const char *end = text + stdText.size();
|
||||
size_t numWeights = 0;
|
||||
for (auto it = pController.mWeightCounts.begin(); it != pController.mWeightCounts.end(); ++it) {
|
||||
if (*text == 0) {
|
||||
throw DeadlyImportError("Out of data while reading <vcount>");
|
||||
}
|
||||
|
||||
*it = strtoul10(text, &text);
|
||||
numWeights += *it;
|
||||
SkipSpacesAndLineEnd(&text, end);
|
||||
}
|
||||
// reserve weight count
|
||||
pController.mWeights.resize(numWeights);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static void ReadControllerWeightsJoint2verts(XmlNode ¤tNode, Controller &pController) {
|
||||
// read JointIndex - WeightIndex pairs
|
||||
std::string stdText;
|
||||
XmlParser::getValueAsString(currentNode, stdText);
|
||||
const char *text = stdText.c_str();
|
||||
const char *end = text + stdText.size();
|
||||
for (auto it = pController.mWeights.begin(); it != pController.mWeights.end(); ++it) {
|
||||
if (text == nullptr) {
|
||||
throw DeadlyImportError("Out of data while reading <vertex_weights>");
|
||||
}
|
||||
SkipSpacesAndLineEnd(&text, end);
|
||||
it->first = strtoul10(text, &text);
|
||||
SkipSpacesAndLineEnd(&text, end);
|
||||
if (*text == 0) {
|
||||
throw DeadlyImportError("Out of data while reading <vertex_weights>");
|
||||
}
|
||||
it->second = strtoul10(text, &text);
|
||||
SkipSpacesAndLineEnd(&text, end);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads the joint weights for the given controller
|
||||
static void ReadControllerWeights(XmlNode &node, Controller &pController) {
|
||||
// Read vertex count from attributes and resize the array accordingly
|
||||
int vertexCount = 0;
|
||||
XmlParser::getIntAttribute(node, "count", vertexCount);
|
||||
pController.mWeightCounts.resize(vertexCount);
|
||||
|
||||
for (XmlNode ¤tNode : node.children()) {
|
||||
const std::string ¤tName = currentNode.name();
|
||||
if (currentName == "input") {
|
||||
ReadControllerWeightsInput(currentNode, pController);
|
||||
} else if (currentName == "vcount" && vertexCount > 0) {
|
||||
ReadControllerWeightsVCount(currentNode, pController);
|
||||
} else if (currentName == "v" && vertexCount > 0) {
|
||||
ReadControllerWeightsJoint2verts(currentNode, pController);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads a material entry into the given material
|
||||
static void ReadMaterial(const XmlNode &node, Material &pMaterial) {
|
||||
for (XmlNode ¤tNode : node.children()) {
|
||||
const std::string ¤tName = currentNode.name();
|
||||
if (currentName == "instance_effect") {
|
||||
std::string url;
|
||||
readUrlAttribute(currentNode, url);
|
||||
pMaterial.mEffect = url;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads a light entry into the given light
|
||||
static void ReadLight(XmlNode &node, Light &pLight) {
|
||||
XmlNodeIterator xmlIt(node, XmlNodeIterator::PreOrderMode);
|
||||
XmlNode currentNode;
|
||||
// TODO: Check the current technique and skip over unsupported extra techniques
|
||||
|
||||
while (xmlIt.getNext(currentNode)) {
|
||||
const std::string ¤tName = currentNode.name();
|
||||
if (currentName == "spot") {
|
||||
pLight.mType = aiLightSource_SPOT;
|
||||
} else if (currentName == "ambient") {
|
||||
pLight.mType = aiLightSource_AMBIENT;
|
||||
} else if (currentName == "directional") {
|
||||
pLight.mType = aiLightSource_DIRECTIONAL;
|
||||
} else if (currentName == "point") {
|
||||
pLight.mType = aiLightSource_POINT;
|
||||
} else if (currentName == "color") {
|
||||
// text content contains 3 floats
|
||||
std::string v;
|
||||
XmlParser::getValueAsString(currentNode, v);
|
||||
const char *content = v.c_str();
|
||||
const char *end = content + v.size();
|
||||
|
||||
content = fast_atoreal_move<ai_real>(content, (ai_real &)pLight.mColor.r);
|
||||
SkipSpacesAndLineEnd(&content, end);
|
||||
|
||||
content = fast_atoreal_move<ai_real>(content, (ai_real &)pLight.mColor.g);
|
||||
SkipSpacesAndLineEnd(&content, end);
|
||||
|
||||
content = fast_atoreal_move<ai_real>(content, (ai_real &)pLight.mColor.b);
|
||||
SkipSpacesAndLineEnd(&content, end);
|
||||
} else if (currentName == "constant_attenuation") {
|
||||
XmlParser::getValueAsReal(currentNode, pLight.mAttConstant);
|
||||
} else if (currentName == "linear_attenuation") {
|
||||
XmlParser::getValueAsReal(currentNode, pLight.mAttLinear);
|
||||
} else if (currentName == "quadratic_attenuation") {
|
||||
XmlParser::getValueAsReal(currentNode, pLight.mAttQuadratic);
|
||||
} else if (currentName == "falloff_angle") {
|
||||
XmlParser::getValueAsReal(currentNode, pLight.mFalloffAngle);
|
||||
} else if (currentName == "falloff_exponent") {
|
||||
XmlParser::getValueAsReal(currentNode, pLight.mFalloffExponent);
|
||||
}
|
||||
// FCOLLADA extensions
|
||||
// -------------------------------------------------------
|
||||
else if (currentName == "outer_cone") {
|
||||
XmlParser::getValueAsReal(currentNode, pLight.mOuterAngle);
|
||||
} else if (currentName == "penumbra_angle") { // this one is deprecated, now calculated using outer_cone
|
||||
XmlParser::getValueAsReal(currentNode, pLight.mPenumbraAngle);
|
||||
} else if (currentName == "intensity") {
|
||||
XmlParser::getValueAsReal(currentNode, pLight.mIntensity);
|
||||
} else if (currentName == "falloff") {
|
||||
XmlParser::getValueAsReal(currentNode, pLight.mOuterAngle);
|
||||
} else if (currentName == "hotspot_beam") {
|
||||
XmlParser::getValueAsReal(currentNode, pLight.mFalloffAngle);
|
||||
}
|
||||
// OpenCOLLADA extensions
|
||||
// -------------------------------------------------------
|
||||
else if (currentName == "decay_falloff") {
|
||||
XmlParser::getValueAsReal(currentNode, pLight.mOuterAngle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads a camera entry into the given light
|
||||
static void ReadCamera(XmlNode &node, Camera &camera) {
|
||||
XmlNodeIterator xmlIt(node, XmlNodeIterator::PreOrderMode);
|
||||
XmlNode currentNode;
|
||||
while (xmlIt.getNext(currentNode)) {
|
||||
const std::string ¤tName = currentNode.name();
|
||||
if (currentName == "orthographic") {
|
||||
camera.mOrtho = true;
|
||||
} else if (currentName == "xfov" || currentName == "xmag") {
|
||||
XmlParser::getValueAsReal(currentNode, camera.mHorFov);
|
||||
} else if (currentName == "yfov" || currentName == "ymag") {
|
||||
XmlParser::getValueAsReal(currentNode, camera.mVerFov);
|
||||
} else if (currentName == "aspect_ratio") {
|
||||
XmlParser::getValueAsReal(currentNode, camera.mAspect);
|
||||
} else if (currentName == "znear") {
|
||||
XmlParser::getValueAsReal(currentNode, camera.mZNear);
|
||||
} else if (currentName == "zfar") {
|
||||
XmlParser::getValueAsReal(currentNode, camera.mZFar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
ColladaParser::ColladaParser(IOSystem *pIOHandler, const std::string &pFile) :
|
||||
mFileName(pFile),
|
||||
mXmlParser(),
|
||||
mDataLibrary(),
|
||||
mAccessorLibrary(),
|
||||
mMeshLibrary(),
|
||||
mNodeLibrary(),
|
||||
mImageLibrary(),
|
||||
mEffectLibrary(),
|
||||
mMaterialLibrary(),
|
||||
mLightLibrary(),
|
||||
mCameraLibrary(),
|
||||
mControllerLibrary(),
|
||||
mRootNode(nullptr),
|
||||
mAnims(),
|
||||
mUnitSize(1.0f),
|
||||
mUpDirection(UP_Y),
|
||||
mFormat(FV_1_5_n) {
|
||||
@@ -122,13 +421,13 @@ ColladaParser::ColladaParser(IOSystem *pIOHandler, const std::string &pFile) :
|
||||
throw DeadlyImportError("IOSystem is nullptr.");
|
||||
}
|
||||
|
||||
std::unique_ptr<IOStream> daefile;
|
||||
std::unique_ptr<IOStream> daeFile;
|
||||
std::unique_ptr<ZipArchiveIOSystem> zip_archive;
|
||||
|
||||
// Determine type
|
||||
std::string extension = BaseImporter::GetExtension(pFile);
|
||||
const std::string extension = BaseImporter::GetExtension(pFile);
|
||||
if (extension != "dae") {
|
||||
zip_archive.reset(new ZipArchiveIOSystem(pIOHandler, pFile));
|
||||
zip_archive = std::make_unique<ZipArchiveIOSystem>(pIOHandler, pFile);
|
||||
}
|
||||
|
||||
if (zip_archive && zip_archive->isOpen()) {
|
||||
@@ -138,24 +437,24 @@ ColladaParser::ColladaParser(IOSystem *pIOHandler, const std::string &pFile) :
|
||||
throw DeadlyImportError("Invalid ZAE");
|
||||
}
|
||||
|
||||
daefile.reset(zip_archive->Open(dae_filename.c_str()));
|
||||
if (daefile == nullptr) {
|
||||
daeFile.reset(zip_archive->Open(dae_filename.c_str()));
|
||||
if (daeFile == nullptr) {
|
||||
throw DeadlyImportError("Invalid ZAE manifest: '", dae_filename, "' is missing");
|
||||
}
|
||||
} else {
|
||||
// attempt to open the file directly
|
||||
daefile.reset(pIOHandler->Open(pFile));
|
||||
if (daefile == nullptr) {
|
||||
daeFile.reset(pIOHandler->Open(pFile));
|
||||
if (daeFile == nullptr) {
|
||||
throw DeadlyImportError("Failed to open file '", pFile, "'.");
|
||||
}
|
||||
}
|
||||
|
||||
// generate a XML reader for it
|
||||
if (!mXmlParser.parse(daefile.get())) {
|
||||
if (!mXmlParser.parse(daeFile.get())) {
|
||||
throw DeadlyImportError("Unable to read file, malformed XML");
|
||||
}
|
||||
// start reading
|
||||
XmlNode node = mXmlParser.getRootNode();
|
||||
const XmlNode node = mXmlParser.getRootNode();
|
||||
XmlNode colladaNode = node.child("COLLADA");
|
||||
if (colladaNode.empty()) {
|
||||
return;
|
||||
@@ -190,14 +489,14 @@ std::string ColladaParser::ReadZaeManifest(ZipArchiveIOSystem &zip_archive) {
|
||||
zip_archive.getFileListExtension(file_list, "dae");
|
||||
|
||||
if (file_list.empty()) {
|
||||
return std::string();
|
||||
return {};
|
||||
}
|
||||
|
||||
return file_list.front();
|
||||
}
|
||||
XmlParser manifestParser;
|
||||
if (!manifestParser.parse(manifestfile.get())) {
|
||||
return std::string();
|
||||
return {};
|
||||
}
|
||||
|
||||
XmlNode root = manifestParser.getRootNode();
|
||||
@@ -205,7 +504,7 @@ std::string ColladaParser::ReadZaeManifest(ZipArchiveIOSystem &zip_archive) {
|
||||
if (name != "dae_root") {
|
||||
root = *manifestParser.findNode("dae_root");
|
||||
if (nullptr == root) {
|
||||
return std::string();
|
||||
return {};
|
||||
}
|
||||
std::string v;
|
||||
XmlParser::getValueAsString(root, v);
|
||||
@@ -214,7 +513,7 @@ std::string ColladaParser::ReadZaeManifest(ZipArchiveIOSystem &zip_archive) {
|
||||
return std::string(ai_str.C_Str());
|
||||
}
|
||||
|
||||
return std::string();
|
||||
return {};
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -246,7 +545,7 @@ void ColladaParser::UriDecodePath(aiString &ss) {
|
||||
char mychar[3] = { it[1], it[2], 0 };
|
||||
size_t nbr = strtoul16(mychar);
|
||||
it += 3;
|
||||
*out++ = (char)(nbr & 0xFF);
|
||||
*out++ = static_cast<char>(nbr & 0xFF);
|
||||
} else {
|
||||
*out++ = *it++;
|
||||
}
|
||||
@@ -261,12 +560,11 @@ void ColladaParser::UriDecodePath(aiString &ss) {
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads the contents of the file
|
||||
void ColladaParser::ReadContents(XmlNode &node) {
|
||||
const std::string name = node.name();
|
||||
if (name == "COLLADA") {
|
||||
if (const std::string name = node.name(); name == "COLLADA") {
|
||||
std::string version;
|
||||
if (XmlParser::getStdStrAttribute(node, "version", version)) {
|
||||
aiString v;
|
||||
v.Set(version.c_str());
|
||||
v.Set(version);
|
||||
mAssetMetaData.emplace(AI_METADATA_SOURCE_FORMAT_VERSION, v);
|
||||
if (!::strncmp(version.c_str(), "1.5", 3)) {
|
||||
mFormat = FV_1_5_n;
|
||||
@@ -287,8 +585,7 @@ void ColladaParser::ReadContents(XmlNode &node) {
|
||||
// Reads the structure of the file
|
||||
void ColladaParser::ReadStructure(XmlNode &node) {
|
||||
for (XmlNode ¤tNode : node.children()) {
|
||||
const std::string ¤tName = currentNode.name();
|
||||
if (currentName == "asset") {
|
||||
if (const std::string ¤tName = currentNode.name(); currentName == "asset") {
|
||||
ReadAssetInfo(currentNode);
|
||||
} else if (currentName == "library_animations") {
|
||||
ReadAnimationLibrary(currentNode);
|
||||
@@ -329,8 +626,7 @@ void ColladaParser::ReadAssetInfo(XmlNode &node) {
|
||||
}
|
||||
|
||||
for (XmlNode ¤tNode : node.children()) {
|
||||
const std::string ¤tName = currentNode.name();
|
||||
if (currentName == "unit") {
|
||||
if (const std::string ¤tName = currentNode.name(); currentName == "unit") {
|
||||
mUnitSize = 1.f;
|
||||
std::string tUnitSizeString;
|
||||
if (XmlParser::getStdStrAttribute(currentNode, "meter", tUnitSizeString)) {
|
||||
@@ -364,35 +660,6 @@ void ColladaParser::ReadAssetInfo(XmlNode &node) {
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads a single string metadata item
|
||||
void ColladaParser::ReadMetaDataItem(XmlNode &node, StringMetaData &metadata) {
|
||||
const Collada::MetaKeyPairVector &key_renaming = GetColladaAssimpMetaKeysCamelCase();
|
||||
const std::string name = node.name();
|
||||
if (name.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string v;
|
||||
if (!XmlParser::getValueAsString(node, v)) {
|
||||
return;
|
||||
}
|
||||
|
||||
v = ai_trim(v);
|
||||
aiString aistr;
|
||||
aistr.Set(v);
|
||||
|
||||
std::string camel_key_str(name);
|
||||
ToCamelCase(camel_key_str);
|
||||
|
||||
size_t found_index;
|
||||
if (FindCommonKey(camel_key_str, key_renaming, found_index)) {
|
||||
metadata.emplace(key_renaming[found_index].second, aistr);
|
||||
} else {
|
||||
metadata.emplace(camel_key_str, aistr);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads the animation clips
|
||||
void ColladaParser::ReadAnimationClipLibrary(XmlNode &node) {
|
||||
@@ -424,15 +691,16 @@ void ColladaParser::ReadAnimationClipLibrary(XmlNode &node) {
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// The controller post processing step
|
||||
void ColladaParser::PostProcessControllers() {
|
||||
std::string meshId;
|
||||
for (auto &it : mControllerLibrary) {
|
||||
meshId = it.second.mMeshId;
|
||||
std::string meshId = it.second.mMeshId;
|
||||
if (meshId.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ControllerLibrary::iterator findItr = mControllerLibrary.find(meshId);
|
||||
auto findItr = mControllerLibrary.find(meshId);
|
||||
while (findItr != mControllerLibrary.end()) {
|
||||
meshId = findItr->second.mMeshId;
|
||||
findItr = mControllerLibrary.find(meshId);
|
||||
@@ -454,13 +722,13 @@ void ColladaParser::PostProcessRootAnimations() {
|
||||
for (auto &it : mAnimationClipLibrary) {
|
||||
std::string clipName = it.first;
|
||||
|
||||
Animation *clip = new Animation();
|
||||
auto *clip = new Animation();
|
||||
clip->mName = clipName;
|
||||
|
||||
temp.mSubAnims.push_back(clip);
|
||||
|
||||
for (const std::string &animationID : it.second) {
|
||||
AnimationLibrary::iterator animation = mAnimationLibrary.find(animationID);
|
||||
auto animation = mAnimationLibrary.find(animationID);
|
||||
|
||||
if (animation != mAnimationLibrary.end()) {
|
||||
Animation *pSourceAnimation = animation->second;
|
||||
@@ -533,7 +801,7 @@ void ColladaParser::ReadAnimation(XmlNode &node, Collada::Animation *pParent) {
|
||||
std::string id;
|
||||
if (XmlParser::getStdStrAttribute(currentNode, "id", id)) {
|
||||
// have it read into a channel
|
||||
ChannelMap::iterator newChannel = channels.insert(std::make_pair(id, AnimationChannel())).first;
|
||||
auto newChannel = channels.insert(std::make_pair(id, AnimationChannel())).first;
|
||||
ReadAnimationSampler(currentNode, newChannel->second);
|
||||
}
|
||||
} else if (currentName == "channel") {
|
||||
@@ -543,7 +811,7 @@ void ColladaParser::ReadAnimation(XmlNode &node, Collada::Animation *pParent) {
|
||||
if (source_name[0] == '#') {
|
||||
source_name = source_name.substr(1, source_name.size() - 1);
|
||||
}
|
||||
ChannelMap::iterator cit = channels.find(source_name);
|
||||
auto cit = channels.find(source_name);
|
||||
if (cit != channels.end()) {
|
||||
cit->second.mTarget = target;
|
||||
}
|
||||
@@ -568,40 +836,6 @@ void ColladaParser::ReadAnimation(XmlNode &node, Collada::Animation *pParent) {
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads an animation sampler into the given anim channel
|
||||
void ColladaParser::ReadAnimationSampler(XmlNode &node, Collada::AnimationChannel &pChannel) {
|
||||
for (XmlNode ¤tNode : node.children()) {
|
||||
const std::string ¤tName = currentNode.name();
|
||||
if (currentName == "input") {
|
||||
if (XmlParser::hasAttribute(currentNode, "semantic")) {
|
||||
std::string semantic, sourceAttr;
|
||||
XmlParser::getStdStrAttribute(currentNode, "semantic", semantic);
|
||||
if (XmlParser::hasAttribute(currentNode, "source")) {
|
||||
XmlParser::getStdStrAttribute(currentNode, "source", sourceAttr);
|
||||
const char *source = sourceAttr.c_str();
|
||||
if (source[0] != '#') {
|
||||
throw DeadlyImportError("Unsupported URL format");
|
||||
}
|
||||
source++;
|
||||
|
||||
if (semantic == "INPUT") {
|
||||
pChannel.mSourceTimes = source;
|
||||
} else if (semantic == "OUTPUT") {
|
||||
pChannel.mSourceValues = source;
|
||||
} else if (semantic == "IN_TANGENT") {
|
||||
pChannel.mInTanValues = source;
|
||||
} else if (semantic == "OUT_TANGENT") {
|
||||
pChannel.mOutTanValues = source;
|
||||
} else if (semantic == "INTERPOLATION") {
|
||||
pChannel.mInterpolationValues = source;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads the skeleton controller library
|
||||
void ColladaParser::ReadControllerLibrary(XmlNode &node) {
|
||||
@@ -614,8 +848,7 @@ void ColladaParser::ReadControllerLibrary(XmlNode &node) {
|
||||
if (currentName != "controller") {
|
||||
continue;
|
||||
}
|
||||
std::string id;
|
||||
if (XmlParser::getStdStrAttribute(currentNode, "id", id)) {
|
||||
if (std::string id; XmlParser::getStdStrAttribute(currentNode, "id", id)) {
|
||||
mControllerLibrary[id] = Controller();
|
||||
ReadController(currentNode, mControllerLibrary[id]);
|
||||
}
|
||||
@@ -632,13 +865,11 @@ void ColladaParser::ReadController(XmlNode &node, Collada::Controller &controlle
|
||||
XmlNodeIterator xmlIt(node, XmlNodeIterator::PreOrderMode);
|
||||
XmlNode currentNode;
|
||||
while (xmlIt.getNext(currentNode)) {
|
||||
const std::string ¤tName = currentNode.name();
|
||||
if (currentName == "morph") {
|
||||
if (const std::string ¤tName = currentNode.name(); currentName == "morph") {
|
||||
controller.mType = Morph;
|
||||
std::string id = currentNode.attribute("source").as_string();
|
||||
controller.mMeshId = id.substr(1, id.size() - 1);
|
||||
int methodIndex = currentNode.attribute("method").as_int();
|
||||
if (methodIndex > 0) {
|
||||
if (const int methodIndex = currentNode.attribute("method").as_int(); methodIndex > 0) {
|
||||
std::string method;
|
||||
XmlParser::getValueAsString(currentNode, method);
|
||||
|
||||
@@ -647,8 +878,7 @@ void ColladaParser::ReadController(XmlNode &node, Collada::Controller &controlle
|
||||
}
|
||||
}
|
||||
} else if (currentName == "skin") {
|
||||
std::string id;
|
||||
if (XmlParser::getStdStrAttribute(currentNode, "source", id)) {
|
||||
if (std::string id; XmlParser::getStdStrAttribute(currentNode, "source", id)) {
|
||||
controller.mMeshId = id.substr(1, id.size() - 1);
|
||||
}
|
||||
} else if (currentName == "bind_shape_matrix") {
|
||||
@@ -656,10 +886,10 @@ void ColladaParser::ReadController(XmlNode &node, Collada::Controller &controlle
|
||||
XmlParser::getValueAsString(currentNode, v);
|
||||
const char *content = v.c_str();
|
||||
const char *end = content + v.size();
|
||||
for (unsigned int a = 0; a < 16; a++) {
|
||||
for (float & a : controller.mBindShapeMatrix) {
|
||||
SkipSpacesAndLineEnd(&content, end);
|
||||
// read a number
|
||||
content = fast_atoreal_move<ai_real>(content, controller.mBindShapeMatrix[a]);
|
||||
content = fast_atoreal_move<ai_real>(content, a);
|
||||
// skip whitespace after it
|
||||
SkipSpacesAndLineEnd(&content, end);
|
||||
}
|
||||
@@ -686,108 +916,13 @@ void ColladaParser::ReadController(XmlNode &node, Collada::Controller &controlle
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads the joint definitions for the given controller
|
||||
void ColladaParser::ReadControllerJoints(XmlNode &node, Collada::Controller &pController) {
|
||||
for (XmlNode ¤tNode : node.children()) {
|
||||
const std::string ¤tName = currentNode.name();
|
||||
if (currentName == "input") {
|
||||
const char *attrSemantic = currentNode.attribute("semantic").as_string();
|
||||
const char *attrSource = currentNode.attribute("source").as_string();
|
||||
if (attrSource[0] != '#') {
|
||||
throw DeadlyImportError("Unsupported URL format in \"", attrSource, "\" in source attribute of <joints> data <input> element");
|
||||
}
|
||||
++attrSource;
|
||||
// parse source URL to corresponding source
|
||||
if (strcmp(attrSemantic, "JOINT") == 0) {
|
||||
pController.mJointNameSource = attrSource;
|
||||
} else if (strcmp(attrSemantic, "INV_BIND_MATRIX") == 0) {
|
||||
pController.mJointOffsetMatrixSource = attrSource;
|
||||
} else {
|
||||
throw DeadlyImportError("Unknown semantic \"", attrSemantic, "\" in <joints> data <input> element");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads the joint weights for the given controller
|
||||
void ColladaParser::ReadControllerWeights(XmlNode &node, Collada::Controller &pController) {
|
||||
// Read vertex count from attributes and resize the array accordingly
|
||||
int vertexCount = 0;
|
||||
XmlParser::getIntAttribute(node, "count", vertexCount);
|
||||
pController.mWeightCounts.resize(vertexCount);
|
||||
|
||||
for (XmlNode ¤tNode : node.children()) {
|
||||
const std::string ¤tName = currentNode.name();
|
||||
if (currentName == "input") {
|
||||
InputChannel channel;
|
||||
|
||||
const char *attrSemantic = currentNode.attribute("semantic").as_string();
|
||||
const char *attrSource = currentNode.attribute("source").as_string();
|
||||
channel.mOffset = currentNode.attribute("offset").as_int();
|
||||
|
||||
// local URLS always start with a '#'. We don't support global URLs
|
||||
if (attrSource[0] != '#') {
|
||||
throw DeadlyImportError("Unsupported URL format in \"", attrSource, "\" in source attribute of <vertex_weights> data <input> element");
|
||||
}
|
||||
channel.mAccessor = attrSource + 1;
|
||||
|
||||
// parse source URL to corresponding source
|
||||
if (strcmp(attrSemantic, "JOINT") == 0) {
|
||||
pController.mWeightInputJoints = channel;
|
||||
} else if (strcmp(attrSemantic, "WEIGHT") == 0) {
|
||||
pController.mWeightInputWeights = channel;
|
||||
} else {
|
||||
throw DeadlyImportError("Unknown semantic \"", attrSemantic, "\" in <vertex_weights> data <input> element");
|
||||
}
|
||||
} else if (currentName == "vcount" && vertexCount > 0) {
|
||||
const std::string stdText = currentNode.text().as_string();
|
||||
const char *text = stdText.c_str();
|
||||
const char *end = text + stdText.size();
|
||||
size_t numWeights = 0;
|
||||
for (std::vector<size_t>::iterator it = pController.mWeightCounts.begin(); it != pController.mWeightCounts.end(); ++it) {
|
||||
if (*text == 0) {
|
||||
throw DeadlyImportError("Out of data while reading <vcount>");
|
||||
}
|
||||
|
||||
*it = strtoul10(text, &text);
|
||||
numWeights += *it;
|
||||
SkipSpacesAndLineEnd(&text, end);
|
||||
}
|
||||
// reserve weight count
|
||||
pController.mWeights.resize(numWeights);
|
||||
} else if (currentName == "v" && vertexCount > 0) {
|
||||
// read JointIndex - WeightIndex pairs
|
||||
std::string stdText;
|
||||
XmlParser::getValueAsString(currentNode, stdText);
|
||||
const char *text = stdText.c_str();
|
||||
const char *end = text + stdText.size();
|
||||
for (std::vector<std::pair<size_t, size_t>>::iterator it = pController.mWeights.begin(); it != pController.mWeights.end(); ++it) {
|
||||
if (text == nullptr) {
|
||||
throw DeadlyImportError("Out of data while reading <vertex_weights>");
|
||||
}
|
||||
SkipSpacesAndLineEnd(&text, end);
|
||||
it->first = strtoul10(text, &text);
|
||||
SkipSpacesAndLineEnd(&text, end);
|
||||
if (*text == 0) {
|
||||
throw DeadlyImportError("Out of data while reading <vertex_weights>");
|
||||
}
|
||||
it->second = strtoul10(text, &text);
|
||||
SkipSpacesAndLineEnd(&text, end);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads the image library contents
|
||||
void ColladaParser::ReadImageLibrary(XmlNode &node) {
|
||||
void ColladaParser::ReadImageLibrary(const XmlNode &node) {
|
||||
for (XmlNode ¤tNode : node.children()) {
|
||||
const std::string ¤tName = currentNode.name();
|
||||
if (currentName == "image") {
|
||||
std::string id;
|
||||
if (XmlParser::getStdStrAttribute(currentNode, "id", id)) {
|
||||
if (std::basic_string<char> id; XmlParser::getStdStrAttribute(currentNode, "id", id)) {
|
||||
mImageLibrary[id] = Image();
|
||||
// read on from there
|
||||
ReadImage(currentNode, mImageLibrary[id]);
|
||||
@@ -798,7 +933,7 @@ void ColladaParser::ReadImageLibrary(XmlNode &node) {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads an image entry into the given image
|
||||
void ColladaParser::ReadImage(XmlNode &node, Collada::Image &pImage) {
|
||||
void ColladaParser::ReadImage(const XmlNode &node, Collada::Image &pImage) const {
|
||||
for (XmlNode ¤tNode : node.children()) {
|
||||
const std::string currentName = currentNode.name();
|
||||
if (currentName == "image") {
|
||||
@@ -861,13 +996,13 @@ void ColladaParser::ReadImage(XmlNode &node, Collada::Image &pImage) {
|
||||
// Reads the material library
|
||||
void ColladaParser::ReadMaterialLibrary(XmlNode &node) {
|
||||
std::map<std::string, int> names;
|
||||
for (XmlNode ¤tNode : node.children()) {
|
||||
for (const XmlNode ¤tNode : node.children()) {
|
||||
std::string id = currentNode.attribute("id").as_string();
|
||||
std::string name = currentNode.attribute("name").as_string();
|
||||
mMaterialLibrary[id] = Material();
|
||||
|
||||
if (!name.empty()) {
|
||||
std::map<std::string, int>::iterator it = names.find(name);
|
||||
auto it = names.find(name);
|
||||
if (it != names.end()) {
|
||||
std::ostringstream strStream;
|
||||
strStream << ++it->second;
|
||||
@@ -922,107 +1057,6 @@ void ColladaParser::ReadCameraLibrary(XmlNode &node) {
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads a material entry into the given material
|
||||
void ColladaParser::ReadMaterial(XmlNode &node, Collada::Material &pMaterial) {
|
||||
for (XmlNode ¤tNode : node.children()) {
|
||||
const std::string ¤tName = currentNode.name();
|
||||
if (currentName == "instance_effect") {
|
||||
std::string url;
|
||||
readUrlAttribute(currentNode, url);
|
||||
pMaterial.mEffect = url;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads a light entry into the given light
|
||||
void ColladaParser::ReadLight(XmlNode &node, Collada::Light &pLight) {
|
||||
XmlNodeIterator xmlIt(node, XmlNodeIterator::PreOrderMode);
|
||||
XmlNode currentNode;
|
||||
// TODO: Check the current technique and skip over unsupported extra techniques
|
||||
|
||||
while (xmlIt.getNext(currentNode)) {
|
||||
const std::string ¤tName = currentNode.name();
|
||||
if (currentName == "spot") {
|
||||
pLight.mType = aiLightSource_SPOT;
|
||||
} else if (currentName == "ambient") {
|
||||
pLight.mType = aiLightSource_AMBIENT;
|
||||
} else if (currentName == "directional") {
|
||||
pLight.mType = aiLightSource_DIRECTIONAL;
|
||||
} else if (currentName == "point") {
|
||||
pLight.mType = aiLightSource_POINT;
|
||||
} else if (currentName == "color") {
|
||||
// text content contains 3 floats
|
||||
std::string v;
|
||||
XmlParser::getValueAsString(currentNode, v);
|
||||
const char *content = v.c_str();
|
||||
const char *end = content + v.size();
|
||||
|
||||
content = fast_atoreal_move<ai_real>(content, (ai_real &)pLight.mColor.r);
|
||||
SkipSpacesAndLineEnd(&content, end);
|
||||
|
||||
content = fast_atoreal_move<ai_real>(content, (ai_real &)pLight.mColor.g);
|
||||
SkipSpacesAndLineEnd(&content, end);
|
||||
|
||||
content = fast_atoreal_move<ai_real>(content, (ai_real &)pLight.mColor.b);
|
||||
SkipSpacesAndLineEnd(&content, end);
|
||||
} else if (currentName == "constant_attenuation") {
|
||||
XmlParser::getValueAsReal(currentNode, pLight.mAttConstant);
|
||||
} else if (currentName == "linear_attenuation") {
|
||||
XmlParser::getValueAsReal(currentNode, pLight.mAttLinear);
|
||||
} else if (currentName == "quadratic_attenuation") {
|
||||
XmlParser::getValueAsReal(currentNode, pLight.mAttQuadratic);
|
||||
} else if (currentName == "falloff_angle") {
|
||||
XmlParser::getValueAsReal(currentNode, pLight.mFalloffAngle);
|
||||
} else if (currentName == "falloff_exponent") {
|
||||
XmlParser::getValueAsReal(currentNode, pLight.mFalloffExponent);
|
||||
}
|
||||
// FCOLLADA extensions
|
||||
// -------------------------------------------------------
|
||||
else if (currentName == "outer_cone") {
|
||||
XmlParser::getValueAsReal(currentNode, pLight.mOuterAngle);
|
||||
} else if (currentName == "penumbra_angle") { // this one is deprecated, now calculated using outer_cone
|
||||
XmlParser::getValueAsReal(currentNode, pLight.mPenumbraAngle);
|
||||
} else if (currentName == "intensity") {
|
||||
XmlParser::getValueAsReal(currentNode, pLight.mIntensity);
|
||||
}
|
||||
else if (currentName == "falloff") {
|
||||
XmlParser::getValueAsReal(currentNode, pLight.mOuterAngle);
|
||||
} else if (currentName == "hotspot_beam") {
|
||||
XmlParser::getValueAsReal(currentNode, pLight.mFalloffAngle);
|
||||
}
|
||||
// OpenCOLLADA extensions
|
||||
// -------------------------------------------------------
|
||||
else if (currentName == "decay_falloff") {
|
||||
XmlParser::getValueAsReal(currentNode, pLight.mOuterAngle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads a camera entry into the given light
|
||||
void ColladaParser::ReadCamera(XmlNode &node, Collada::Camera &camera) {
|
||||
XmlNodeIterator xmlIt(node, XmlNodeIterator::PreOrderMode);
|
||||
XmlNode currentNode;
|
||||
while (xmlIt.getNext(currentNode)) {
|
||||
const std::string ¤tName = currentNode.name();
|
||||
if (currentName == "orthographic") {
|
||||
camera.mOrtho = true;
|
||||
} else if (currentName == "xfov" || currentName == "xmag") {
|
||||
XmlParser::getValueAsReal(currentNode, camera.mHorFov);
|
||||
} else if (currentName == "yfov" || currentName == "ymag") {
|
||||
XmlParser::getValueAsReal(currentNode, camera.mVerFov);
|
||||
} else if (currentName == "aspect_ratio") {
|
||||
XmlParser::getValueAsReal(currentNode, camera.mAspect);
|
||||
} else if (currentName == "znear") {
|
||||
XmlParser::getValueAsReal(currentNode, camera.mZNear);
|
||||
} else if (currentName == "zfar") {
|
||||
XmlParser::getValueAsReal(currentNode, camera.mZFar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads the effect library
|
||||
void ColladaParser::ReadEffectLibrary(XmlNode &node) {
|
||||
@@ -1733,7 +1767,6 @@ size_t ColladaParser::ReadPrimitives(XmlNode &node, Mesh &pMesh, std::vector<Inp
|
||||
expectedPointCount = 3 * pNumPrimitives;
|
||||
break;
|
||||
default:
|
||||
// other primitive types don't state the index count upfront... we need to guess
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1775,7 +1808,7 @@ size_t ColladaParser::ReadPrimitives(XmlNode &node, Mesh &pMesh, std::vector<Inp
|
||||
}
|
||||
|
||||
// find the data for all sources
|
||||
for (std::vector<InputChannel>::iterator it = pMesh.mPerVertexData.begin(); it != pMesh.mPerVertexData.end(); ++it) {
|
||||
for (auto it = pMesh.mPerVertexData.begin(); it != pMesh.mPerVertexData.end(); ++it) {
|
||||
InputChannel &input = *it;
|
||||
if (input.mResolved) {
|
||||
continue;
|
||||
@@ -1794,7 +1827,7 @@ size_t ColladaParser::ReadPrimitives(XmlNode &node, Mesh &pMesh, std::vector<Inp
|
||||
}
|
||||
}
|
||||
// and the same for the per-index channels
|
||||
for (std::vector<InputChannel>::iterator it = pPerIndexChannels.begin(); it != pPerIndexChannels.end(); ++it) {
|
||||
for (auto it = pPerIndexChannels.begin(); it != pPerIndexChannels.end(); ++it) {
|
||||
InputChannel &input = *it;
|
||||
if (input.mResolved) {
|
||||
continue;
|
||||
@@ -1902,11 +1935,11 @@ void ColladaParser::CopyVertex(size_t currentVertex, size_t numOffsets, size_t n
|
||||
ai_assert((baseOffset + numOffsets - 1) < indices.size());
|
||||
|
||||
// extract per-vertex channels using the global per-vertex offset
|
||||
for (std::vector<InputChannel>::iterator it = pMesh.mPerVertexData.begin(); it != pMesh.mPerVertexData.end(); ++it) {
|
||||
for (auto it = pMesh.mPerVertexData.begin(); it != pMesh.mPerVertexData.end(); ++it) {
|
||||
ExtractDataObjectFromChannel(*it, indices[baseOffset + perVertexOffset], pMesh);
|
||||
}
|
||||
// and extract per-index channels using there specified offset
|
||||
for (std::vector<InputChannel>::iterator it = pPerIndexChannels.begin(); it != pPerIndexChannels.end(); ++it) {
|
||||
for (auto it = pPerIndexChannels.begin(); it != pPerIndexChannels.end(); ++it) {
|
||||
ExtractDataObjectFromChannel(*it, indices[baseOffset + it->mOffset], pMesh);
|
||||
}
|
||||
|
||||
@@ -2173,40 +2206,6 @@ void ColladaParser::ReadSceneNode(XmlNode &node, Node *pNode) {
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads a node transformation entry of the given type and adds it to the given node's transformation list.
|
||||
void ColladaParser::ReadNodeTransformation(XmlNode &node, Node *pNode, TransformType pType) {
|
||||
if (node.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string tagName = node.name();
|
||||
|
||||
Transform tf;
|
||||
tf.mType = pType;
|
||||
|
||||
// read SID
|
||||
if (XmlParser::hasAttribute(node, "sid")) {
|
||||
XmlParser::getStdStrAttribute(node, "sid", tf.mID);
|
||||
}
|
||||
|
||||
// how many parameters to read per transformation type
|
||||
static constexpr unsigned int sNumParameters[] = { 9, 4, 3, 3, 7, 16 };
|
||||
std::string value;
|
||||
XmlParser::getValueAsString(node, value);
|
||||
const char *content = value.c_str();
|
||||
const char *end = value.c_str() + value.size();
|
||||
// read as many parameters and store in the transformation
|
||||
for (unsigned int a = 0; a < sNumParameters[pType]; a++) {
|
||||
// skip whitespace before the number
|
||||
SkipSpacesAndLineEnd(&content, end);
|
||||
// read a number
|
||||
content = fast_atoreal_move<ai_real>(content, tf.f[a]);
|
||||
}
|
||||
|
||||
// place the transformation at the queue of the node
|
||||
pNode->mTransforms.push_back(tf);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Processes bind_vertex_input and bind elements
|
||||
@@ -2244,9 +2243,7 @@ void ColladaParser::ReadMaterialVertexInputBinding(XmlNode &node, Collada::Seman
|
||||
void ColladaParser::ReadEmbeddedTextures(ZipArchiveIOSystem &zip_archive) {
|
||||
// Attempt to load any undefined Collada::Image in ImageLibrary
|
||||
for (auto &it : mImageLibrary) {
|
||||
Collada::Image &image = it.second;
|
||||
|
||||
if (image.mImageData.empty()) {
|
||||
if (Image &image = it.second; image.mImageData.empty()) {
|
||||
std::unique_ptr<IOStream> image_file(zip_archive.Open(image.mFileName.c_str()));
|
||||
if (image_file) {
|
||||
image.mImageData.resize(image_file->FileSize());
|
||||
@@ -2329,7 +2326,7 @@ void ColladaParser::ReadScene(XmlNode &node) {
|
||||
}
|
||||
|
||||
// find the referred scene, skip the leading #
|
||||
NodeLibrary::const_iterator sit = mNodeLibrary.find(url.c_str() + 1);
|
||||
auto sit = mNodeLibrary.find(url.c_str() + 1);
|
||||
if (sit == mNodeLibrary.end()) {
|
||||
throw DeadlyImportError("Unable to resolve visual_scene reference \"", std::string(std::move(url)), "\" in <instance_visual_scene> element.");
|
||||
}
|
||||
@@ -2401,7 +2398,7 @@ aiMatrix4x4 ColladaParser::CalculateResultTransform(const std::vector<Transform>
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Determines the input data type for the given semantic string
|
||||
Collada::InputType ColladaParser::GetTypeForSemantic(const std::string &semantic) {
|
||||
InputType ColladaParser::GetTypeForSemantic(const std::string &semantic) {
|
||||
if (semantic.empty()) {
|
||||
ASSIMP_LOG_WARN("Vertex input type is empty.");
|
||||
return IT_Invalid;
|
||||
|
||||
@@ -48,7 +48,6 @@
|
||||
#define AI_COLLADAPARSER_H_INC
|
||||
|
||||
#include "ColladaHelper.h"
|
||||
#include <assimp/TinyFormatter.h>
|
||||
#include <assimp/ai_assert.h>
|
||||
#include <assimp/XmlParser.h>
|
||||
|
||||
@@ -67,268 +66,240 @@ class ZipArchiveIOSystem;
|
||||
class ColladaParser {
|
||||
friend class ColladaLoader;
|
||||
|
||||
/** Converts a path read from a collada file to the usual representation */
|
||||
static void UriDecodePath(aiString &ss);
|
||||
public:
|
||||
/// Map for generic metadata as aiString.
|
||||
using StringMetaData = std::map<std::string, aiString>;
|
||||
|
||||
protected:
|
||||
/** Map for generic metadata as aiString */
|
||||
typedef std::map<std::string, aiString> StringMetaData;
|
||||
|
||||
/** Constructor from XML file */
|
||||
/// Constructor from XML file.
|
||||
ColladaParser(IOSystem *pIOHandler, const std::string &pFile);
|
||||
|
||||
/** Destructor */
|
||||
/// Destructor
|
||||
~ColladaParser();
|
||||
|
||||
/** Attempts to read the ZAE manifest and returns the DAE to open */
|
||||
/// Attempts to read the ZAE manifest and returns the DAE to open
|
||||
static std::string ReadZaeManifest(ZipArchiveIOSystem &zip_archive);
|
||||
|
||||
/** Reads the contents of the file */
|
||||
/// Reads the contents of the file
|
||||
void ReadContents(XmlNode &node);
|
||||
|
||||
/** Reads the structure of the file */
|
||||
/// Reads the structure of the file
|
||||
void ReadStructure(XmlNode &node);
|
||||
|
||||
/** Reads asset information such as coordinate system information and legal blah */
|
||||
/// Reads asset information such as coordinate system information and legal blah
|
||||
void ReadAssetInfo(XmlNode &node);
|
||||
|
||||
/** Reads contributor information such as author and legal blah */
|
||||
/// Reads contributor information such as author and legal blah
|
||||
void ReadContributorInfo(XmlNode &node);
|
||||
|
||||
/** Reads generic metadata into provided map and renames keys for Assimp */
|
||||
void ReadMetaDataItem(XmlNode &node, StringMetaData &metadata);
|
||||
|
||||
/** Reads the animation library */
|
||||
/// Reads the animation library
|
||||
void ReadAnimationLibrary(XmlNode &node);
|
||||
|
||||
/** Reads the animation clip library */
|
||||
/// Reads the animation clip library
|
||||
void ReadAnimationClipLibrary(XmlNode &node);
|
||||
|
||||
/** Unwrap controllers dependency hierarchy */
|
||||
/// Unwrap controllers dependency hierarchy
|
||||
void PostProcessControllers();
|
||||
|
||||
/** Re-build animations from animation clip library, if present, otherwise combine single-channel animations */
|
||||
/// Re-build animations from animation clip library, if present, otherwise combine single-channel animations
|
||||
void PostProcessRootAnimations();
|
||||
|
||||
/** Reads an animation into the given parent structure */
|
||||
/// Reads an animation into the given parent structure
|
||||
void ReadAnimation(XmlNode &node, Collada::Animation *pParent);
|
||||
|
||||
/** Reads an animation sampler into the given anim channel */
|
||||
void ReadAnimationSampler(XmlNode &node, Collada::AnimationChannel &pChannel);
|
||||
|
||||
/** Reads the skeleton controller library */
|
||||
/// Reads the skeleton controller library
|
||||
void ReadControllerLibrary(XmlNode &node);
|
||||
|
||||
/** Reads a controller into the given mesh structure */
|
||||
/// Reads a controller into the given mesh structure
|
||||
void ReadController(XmlNode &node, Collada::Controller &pController);
|
||||
|
||||
/** Reads the joint definitions for the given controller */
|
||||
void ReadControllerJoints(XmlNode &node, Collada::Controller &pController);
|
||||
/// Reads the image library contents
|
||||
void ReadImageLibrary(const XmlNode &node);
|
||||
|
||||
/** Reads the joint weights for the given controller */
|
||||
void ReadControllerWeights(XmlNode &node, Collada::Controller &pController);
|
||||
/// Reads an image entry into the given image
|
||||
void ReadImage(const XmlNode &node, Collada::Image &pImage) const;
|
||||
|
||||
/** Reads the image library contents */
|
||||
void ReadImageLibrary(XmlNode &node);
|
||||
|
||||
/** Reads an image entry into the given image */
|
||||
void ReadImage(XmlNode &node, Collada::Image &pImage);
|
||||
|
||||
/** Reads the material library */
|
||||
/// Reads the material library
|
||||
void ReadMaterialLibrary(XmlNode &node);
|
||||
|
||||
/** Reads a material entry into the given material */
|
||||
void ReadMaterial(XmlNode &node, Collada::Material &pMaterial);
|
||||
|
||||
/** Reads the camera library */
|
||||
/// Reads the camera library
|
||||
void ReadCameraLibrary(XmlNode &node);
|
||||
|
||||
/** Reads a camera entry into the given camera */
|
||||
void ReadCamera(XmlNode &node, Collada::Camera &pCamera);
|
||||
|
||||
/** Reads the light library */
|
||||
/// Reads the light library
|
||||
void ReadLightLibrary(XmlNode &node);
|
||||
|
||||
/** Reads a light entry into the given light */
|
||||
void ReadLight(XmlNode &node, Collada::Light &pLight);
|
||||
|
||||
/** Reads the effect library */
|
||||
/// Reads the effect library
|
||||
void ReadEffectLibrary(XmlNode &node);
|
||||
|
||||
/** Reads an effect entry into the given effect*/
|
||||
/// Reads an effect entry into the given effect
|
||||
void ReadEffect(XmlNode &node, Collada::Effect &pEffect);
|
||||
|
||||
/** Reads an COMMON effect profile */
|
||||
/// Reads an COMMON effect profile
|
||||
void ReadEffectProfileCommon(XmlNode &node, Collada::Effect &pEffect);
|
||||
|
||||
/** Read sampler properties */
|
||||
/// Read sampler properties
|
||||
void ReadSamplerProperties(XmlNode &node, Collada::Sampler &pSampler);
|
||||
|
||||
/** Reads an effect entry containing a color or a texture defining that color */
|
||||
/// Reads an effect entry containing a color or a texture defining that color
|
||||
void ReadEffectColor(XmlNode &node, aiColor4D &pColor, Collada::Sampler &pSampler);
|
||||
|
||||
/** Reads an effect entry containing a float */
|
||||
/// Reads an effect entry containing a float
|
||||
void ReadEffectFloat(XmlNode &node, ai_real &pFloat);
|
||||
|
||||
/** Reads an effect parameter specification of any kind */
|
||||
/// Reads an effect parameter specification of any kind
|
||||
void ReadEffectParam(XmlNode &node, Collada::EffectParam &pParam);
|
||||
|
||||
/** Reads the geometry library contents */
|
||||
/// Reads the geometry library contents
|
||||
void ReadGeometryLibrary(XmlNode &node);
|
||||
|
||||
/** Reads a geometry from the geometry library. */
|
||||
/// Reads a geometry from the geometry library.
|
||||
void ReadGeometry(XmlNode &node, Collada::Mesh &pMesh);
|
||||
|
||||
/** Reads a mesh from the geometry library */
|
||||
/// Reads a mesh from the geometry library
|
||||
void ReadMesh(XmlNode &node, Collada::Mesh &pMesh);
|
||||
|
||||
/** Reads a source element - a combination of raw data and an accessor defining
|
||||
* things that should not be redefinable. Yes, that's another rant.
|
||||
*/
|
||||
/// Reads a source element - a combination of raw data and an accessor defining
|
||||
///things that should not be definable. Yes, that's another rant.
|
||||
void ReadSource(XmlNode &node);
|
||||
|
||||
/** Reads a data array holding a number of elements, and stores it in the global library.
|
||||
* Currently supported are array of floats and arrays of strings.
|
||||
*/
|
||||
/// Reads a data array holding a number of elements, and stores it in the global library.
|
||||
/// Currently supported are array of floats and arrays of strings.
|
||||
void ReadDataArray(XmlNode &node);
|
||||
|
||||
/** Reads an accessor and stores it in the global library under the given ID -
|
||||
* accessors use the ID of the parent <source> element
|
||||
*/
|
||||
/// Reads an accessor and stores it in the global library under the given ID -
|
||||
/// accessors use the ID of the parent <source> element
|
||||
void ReadAccessor(XmlNode &node, const std::string &pID);
|
||||
|
||||
/** Reads input declarations of per-vertex mesh data into the given mesh */
|
||||
/// Reads input declarations of per-vertex mesh data into the given mesh
|
||||
void ReadVertexData(XmlNode &node, Collada::Mesh &pMesh);
|
||||
|
||||
/** Reads input declarations of per-index mesh data into the given mesh */
|
||||
/// Reads input declarations of per-index mesh data into the given mesh
|
||||
void ReadIndexData(XmlNode &node, Collada::Mesh &pMesh);
|
||||
|
||||
/** Reads a single input channel element and stores it in the given array, if valid */
|
||||
/// Reads a single input channel element and stores it in the given array, if valid
|
||||
void ReadInputChannel(XmlNode &node, std::vector<Collada::InputChannel> &poChannels);
|
||||
|
||||
/** Reads a <p> primitive index list and assembles the mesh data into the given mesh */
|
||||
/// Reads a <p> primitive index list and assembles the mesh data into the given mesh
|
||||
size_t ReadPrimitives(XmlNode &node, Collada::Mesh &pMesh, std::vector<Collada::InputChannel> &pPerIndexChannels,
|
||||
size_t pNumPrimitives, const std::vector<size_t> &pVCount, Collada::PrimitiveType pPrimType);
|
||||
|
||||
/** Copies the data for a single primitive into the mesh, based on the InputChannels */
|
||||
/// Copies the data for a single primitive into the mesh, based on the InputChannels
|
||||
void CopyVertex(size_t currentVertex, size_t numOffsets, size_t numPoints, size_t perVertexOffset,
|
||||
Collada::Mesh &pMesh, std::vector<Collada::InputChannel> &pPerIndexChannels,
|
||||
size_t currentPrimitive, const std::vector<size_t> &indices);
|
||||
|
||||
/** Reads one triangle of a tristrip into the mesh */
|
||||
/// Reads one triangle of a tristrip into the mesh
|
||||
void ReadPrimTriStrips(size_t numOffsets, size_t perVertexOffset, Collada::Mesh &pMesh,
|
||||
std::vector<Collada::InputChannel> &pPerIndexChannels, size_t currentPrimitive, const std::vector<size_t> &indices);
|
||||
|
||||
/** Extracts a single object from an input channel and stores it in the appropriate mesh data array */
|
||||
/// Extracts a single object from an input channel and stores it in the appropriate mesh data array
|
||||
void ExtractDataObjectFromChannel(const Collada::InputChannel &pInput, size_t pLocalIndex, Collada::Mesh &pMesh);
|
||||
|
||||
/** Reads the library of node hierarchies and scene parts */
|
||||
/// Reads the library of node hierarchies and scene parts
|
||||
void ReadSceneLibrary(XmlNode &node);
|
||||
|
||||
/** Reads a scene node's contents including children and stores it in the given node */
|
||||
/// Reads a scene node's contents including children and stores it in the given node
|
||||
void ReadSceneNode(XmlNode &node, Collada::Node *pNode);
|
||||
|
||||
/** Reads a node transformation entry of the given type and adds it to the given node's transformation list. */
|
||||
void ReadNodeTransformation(XmlNode &node, Collada::Node *pNode, Collada::TransformType pType);
|
||||
|
||||
/** Reads a mesh reference in a node and adds it to the node's mesh list */
|
||||
|
||||
/// Reads a mesh reference in a node and adds it to the node's mesh list
|
||||
void ReadNodeGeometry(XmlNode &node, Collada::Node *pNode);
|
||||
|
||||
/** Reads the collada scene */
|
||||
/// Reads the collada scene
|
||||
void ReadScene(XmlNode &node);
|
||||
|
||||
// Processes bind_vertex_input and bind elements
|
||||
/// Processes bind_vertex_input and bind elements
|
||||
void ReadMaterialVertexInputBinding(XmlNode &node, Collada::SemanticMappingTable &tbl);
|
||||
|
||||
/** Reads embedded textures from a ZAE archive*/
|
||||
/// Reads embedded textures from a ZAE archive
|
||||
void ReadEmbeddedTextures(ZipArchiveIOSystem &zip_archive);
|
||||
|
||||
protected:
|
||||
/** Calculates the resulting transformation from all the given transform steps */
|
||||
/// Converts a path read from a collada file to the usual representation
|
||||
static void UriDecodePath(aiString &ss);
|
||||
|
||||
/// Calculates the resulting transformation from all the given transform steps
|
||||
aiMatrix4x4 CalculateResultTransform(const std::vector<Collada::Transform> &pTransforms) const;
|
||||
|
||||
/** Determines the input data type for the given semantic string */
|
||||
/// Determines the input data type for the given semantic string
|
||||
Collada::InputType GetTypeForSemantic(const std::string &pSemantic);
|
||||
|
||||
/** Finds the item in the given library by its reference, throws if not found */
|
||||
/// Finds the item in the given library by its reference, throws if not found
|
||||
template <typename Type>
|
||||
const Type &ResolveLibraryReference(const std::map<std::string, Type> &pLibrary, const std::string &pURL) const;
|
||||
|
||||
protected:
|
||||
// Filename, for a verbose error message
|
||||
private:
|
||||
/// Filename, for a verbose error message
|
||||
std::string mFileName;
|
||||
|
||||
// XML reader, member for everyday use
|
||||
/// XML reader, member for everyday use
|
||||
XmlParser mXmlParser;
|
||||
|
||||
/** All data arrays found in the file by ID. Might be referred to by actually
|
||||
everyone. Collada, you are a steaming pile of indirection. */
|
||||
/// All data arrays found in the file by ID. Might be referred to by actually
|
||||
/// everyone. Collada, you are a steaming pile of indirection.
|
||||
using DataLibrary = std::map<std::string, Collada::Data> ;
|
||||
DataLibrary mDataLibrary;
|
||||
|
||||
/** Same for accessors which define how the data in a data array is accessed. */
|
||||
/// Same for accessors which define how the data in a data array is accessed.
|
||||
using AccessorLibrary = std::map<std::string, Collada::Accessor> ;
|
||||
AccessorLibrary mAccessorLibrary;
|
||||
|
||||
/** Mesh library: mesh by ID */
|
||||
/// Mesh library: mesh by ID
|
||||
using MeshLibrary = std::map<std::string, Collada::Mesh *>;
|
||||
MeshLibrary mMeshLibrary;
|
||||
|
||||
/** node library: root node of the hierarchy part by ID */
|
||||
/// node library: root node of the hierarchy part by ID
|
||||
using NodeLibrary = std::map<std::string, Collada::Node *>;
|
||||
NodeLibrary mNodeLibrary;
|
||||
|
||||
/** Image library: stores texture properties by ID */
|
||||
/// Image library: stores texture properties by ID
|
||||
using ImageLibrary = std::map<std::string, Collada::Image> ;
|
||||
ImageLibrary mImageLibrary;
|
||||
|
||||
/** Effect library: surface attributes by ID */
|
||||
/// Effect library: surface attributes by ID
|
||||
using EffectLibrary = std::map<std::string, Collada::Effect> ;
|
||||
EffectLibrary mEffectLibrary;
|
||||
|
||||
/** Material library: surface material by ID */
|
||||
/// Material library: surface material by ID
|
||||
using MaterialLibrary = std::map<std::string, Collada::Material> ;
|
||||
MaterialLibrary mMaterialLibrary;
|
||||
|
||||
/** Light library: surface light by ID */
|
||||
/// Light library: surface light by ID
|
||||
using LightLibrary = std::map<std::string, Collada::Light> ;
|
||||
LightLibrary mLightLibrary;
|
||||
|
||||
/** Camera library: surface material by ID */
|
||||
/// Camera library: surface material by ID
|
||||
using CameraLibrary = std::map<std::string, Collada::Camera> ;
|
||||
CameraLibrary mCameraLibrary;
|
||||
|
||||
/** Controller library: joint controllers by ID */
|
||||
/// Controller library: joint controllers by ID
|
||||
using ControllerLibrary = std::map<std::string, Collada::Controller> ;
|
||||
ControllerLibrary mControllerLibrary;
|
||||
|
||||
/** Animation library: animation references by ID */
|
||||
/// Animation library: animation references by ID
|
||||
using AnimationLibrary = std::map<std::string, Collada::Animation *> ;
|
||||
AnimationLibrary mAnimationLibrary;
|
||||
|
||||
/** Animation clip library: clip animation references by ID */
|
||||
/// Animation clip library: clip animation references by ID
|
||||
using AnimationClipLibrary = std::vector<std::pair<std::string, std::vector<std::string>>> ;
|
||||
AnimationClipLibrary mAnimationClipLibrary;
|
||||
|
||||
/** Pointer to the root node. Don't delete, it just points to one of
|
||||
the nodes in the node library. */
|
||||
/// Pointer to the root node. Don't delete, it just points to one of the nodes in the node library.
|
||||
Collada::Node *mRootNode;
|
||||
|
||||
/** Root animation container */
|
||||
/// Root animation container
|
||||
Collada::Animation mAnims;
|
||||
|
||||
/** Size unit: how large compared to a meter */
|
||||
/// Size unit: how large compared to a meter
|
||||
ai_real mUnitSize;
|
||||
|
||||
/** Which is the up vector */
|
||||
/// Which is the up vector
|
||||
enum { UP_X,
|
||||
UP_Y,
|
||||
UP_Z } mUpDirection;
|
||||
|
||||
/** Asset metadata (global for scene) */
|
||||
/// Asset metadata (global for scene)
|
||||
StringMetaData mAssetMetaData;
|
||||
|
||||
/** Collada file format version */
|
||||
/// Collada file format version
|
||||
Collada::FormatVersion mFormat;
|
||||
};
|
||||
|
||||
|
||||
@@ -86,6 +86,7 @@ SET( COMMON
|
||||
unit/TestModelFactory.h
|
||||
unit/utTypes.cpp
|
||||
unit/utVersion.cpp
|
||||
unit/Common/utParsingUtils.cpp
|
||||
unit/utProfiler.cpp
|
||||
unit/utSharedPPData.cpp
|
||||
unit/utStringUtils.cpp
|
||||
|
||||
66
test/unit/Common/utParsingUtils.cpp
Normal file
66
test/unit/Common/utParsingUtils.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2025, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the following
|
||||
conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "UnitTestPCH.h"
|
||||
#include <assimp/ParsingUtils.h>
|
||||
#include <assimp/fast_atof.h>
|
||||
#include <array>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
class utParsingUtils : public ::testing::Test {};
|
||||
|
||||
TEST_F(utParsingUtils, parseFloatsStringTest) {
|
||||
const std::array<float, 16> floatArray = {
|
||||
1.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 7.54979e-8f, -1.0f, 0.0f,
|
||||
0.0f, 1.0f, 7.54979e-8f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f};
|
||||
const std::string floatArrayAsStr = "1 0 0 0 0 7.54979e-8 -1 0 0 1 7.54979e-8 0 0 0 0 1";
|
||||
const char *content = floatArrayAsStr.c_str();
|
||||
const char *end = content + floatArrayAsStr.size();
|
||||
for (float i : floatArray) {
|
||||
float value = 0.0f;
|
||||
SkipSpacesAndLineEnd(&content, end);
|
||||
content = fast_atoreal_move<ai_real>(content, value);
|
||||
EXPECT_FLOAT_EQ(value, i);
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
|
||||
|
||||
Copyright (c) 2006-2025, assimp team
|
||||
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
@@ -122,6 +120,7 @@ protected:
|
||||
TEST_CASE(0e-19);
|
||||
TEST_CASE(400012);
|
||||
TEST_CASE(5.9e-76);
|
||||
TEST_CASE(7.54979e-8);
|
||||
TEST_CASE_INF(inf);
|
||||
TEST_CASE_INF(inf);
|
||||
TEST_CASE_INF(infinity);
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2025, assimp team
|
||||
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
|
||||
Reference in New Issue
Block a user