Fix incorrect xml-parsing in collada importer.

pull/3635/head
Kim Kulling 2021-02-02 22:06:33 +01:00
parent 754b2ba434
commit fa2354ebc3
4 changed files with 123 additions and 129 deletions

View File

@ -206,7 +206,8 @@ struct SemanticMappingTable {
std::string mMatName; std::string mMatName;
/// List of semantic map commands, grouped by effect semantic name /// 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 /// For std::find
bool operator==(const std::string &s) const { bool operator==(const std::string &s) const {

View File

@ -327,7 +327,7 @@ void ColladaLoader::ResolveNodeInstances(const ColladaParser &pParser, const Col
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Resolve UV channels // Resolve UV channels
void ColladaLoader::ApplyVertexToEffectSemanticMapping(Collada::Sampler &sampler, const Collada::SemanticMappingTable &table) { void ColladaLoader::ApplyVertexToEffectSemanticMapping(Collada::Sampler &sampler, const Collada::SemanticMappingTable &table) {
std::map<std::string, Collada::InputSemanticMapEntry>::const_iterator it = table.mMap.find(sampler.mUVChannel); Collada::SemanticMappingTable::InputSemanticMap::const_iterator it = table.mMap.find(sampler.mUVChannel);
if (it == table.mMap.end()) { if (it == table.mMap.end()) {
return; return;
} }
@ -692,6 +692,9 @@ aiMesh *ColladaLoader::CreateMesh(const ColladaParser &pParser, const Collada::M
for (std::map<std::string, Collada::Controller>::const_iterator it = pParser.mControllerLibrary.begin(); for (std::map<std::string, Collada::Controller>::const_iterator it = pParser.mControllerLibrary.begin();
it != pParser.mControllerLibrary.end(); ++it) { it != pParser.mControllerLibrary.end(); ++it) {
const Collada::Controller &c = it->second; const Collada::Controller &c = it->second;
/*if (c.mMeshId.empty()) {
continue;
}*/
const Collada::Mesh *baseMesh = pParser.ResolveLibraryReference(pParser.mMeshLibrary, c.mMeshId); const Collada::Mesh *baseMesh = pParser.ResolveLibraryReference(pParser.mMeshLibrary, c.mMeshId);
if (c.mType == Collada::Morph && baseMesh->mName == pSrcMesh->mName) { if (c.mType == Collada::Morph && baseMesh->mName == pSrcMesh->mName) {

View File

@ -45,8 +45,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef AI_COLLADALOADER_H_INC #ifndef AI_COLLADALOADER_H_INC
#define AI_COLLADALOADER_H_INC #define AI_COLLADALOADER_H_INC
#include <assimp/BaseImporter.h>
#include "ColladaParser.h" #include "ColladaParser.h"
#include <assimp/BaseImporter.h>
struct aiNode; struct aiNode;
struct aiCamera; struct aiCamera;
@ -54,28 +54,24 @@ struct aiLight;
struct aiTexture; struct aiTexture;
struct aiAnimation; struct aiAnimation;
namespace Assimp namespace Assimp {
{
struct ColladaMeshIndex struct ColladaMeshIndex {
{
std::string mMeshID; std::string mMeshID;
size_t mSubMesh; size_t mSubMesh;
std::string mMaterial; std::string mMaterial;
ColladaMeshIndex( const std::string& pMeshID, size_t pSubMesh, const std::string& pMaterial) ColladaMeshIndex(const std::string &pMeshID, size_t pSubMesh, const std::string &pMaterial) :
: mMeshID( pMeshID), mSubMesh( pSubMesh), mMaterial( pMaterial) mMeshID(pMeshID), mSubMesh(pSubMesh), mMaterial(pMaterial) {
{ } ai_assert(!pMeshID.empty());
}
bool operator < (const ColladaMeshIndex& p) const bool operator<(const ColladaMeshIndex &p) const {
{ if (mMeshID == p.mMeshID) {
if( mMeshID == p.mMeshID)
{
if (mSubMesh == p.mSubMesh) if (mSubMesh == p.mSubMesh)
return mMaterial < p.mMaterial; return mMaterial < p.mMaterial;
else else
return mSubMesh < p.mSubMesh; return mSubMesh < p.mSubMesh;
} else } else {
{
return mMeshID < p.mMeshID; return mMeshID < p.mMeshID;
} }
} }
@ -84,12 +80,10 @@ struct ColladaMeshIndex
/** Loader class to read Collada scenes. Collada is over-engineered to death, with every new iteration bringing /** 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. * 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: public:
ColladaLoader(); ColladaLoader();
~ColladaLoader(); ~ColladaLoader() override;
public: public:
/** Returns whether the class can handle the format of the given file. /** Returns whether the class can handle the format of the given file.

View File

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