xml-migration: introduce xmlnode.

pull/2966/head
Kim Kulling 2020-01-27 22:11:27 +01:00
parent 6a471b4390
commit 8ef106e185
3 changed files with 146 additions and 124 deletions

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2020, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -65,6 +63,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace Assimp { namespace Assimp {
class XmlNode;
/// \class AMFImporter /// \class AMFImporter
/// Class that holding scene graph which include: geometry, metadata, materials etc. /// Class that holding scene graph which include: geometry, metadata, materials etc.
/// ///
@ -345,7 +345,7 @@ private:
void ParseHelper_Decode_Base64(const std::string& pInputBase64, std::vector<uint8_t>& pOutputData) const; void ParseHelper_Decode_Base64(const std::string& pInputBase64, std::vector<uint8_t>& pOutputData) const;
/// Parse <AMF> node of the file. /// Parse <AMF> node of the file.
void ParseNode_Root(); void ParseNode_Root(XmlNode *root);
/// Parse <constellation> node of the file. /// Parse <constellation> node of the file.
void ParseNode_Constellation(); void ParseNode_Constellation();

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2020, assimp team Copyright (c) 2006-2020, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -564,7 +562,11 @@ void IRRImporter::ComputeAnimations(Node *root, aiNode *real, std::vector<aiNode
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// This function is maybe more generic than we'd need it here // This function is maybe more generic than we'd need it here
void SetupMapping(aiMaterial *mat, aiTextureMapping mode, const aiVector3D &axis = aiVector3D(0.f, 0.f, -1.f)) { void SetupMapping(aiMaterial *mat, aiTextureMapping mode, const aiVector3D &axis = aiVector3D(0.f, 0.f, -1.f)) {
// Check whether there are texture properties defined - setup if (nullptr == mat) {
return;
}
// Check whether there are texture properties defined - setup
// the desired texture mapping mode for all of them and ignore // the desired texture mapping mode for all of them and ignore
// all UV settings we might encounter. WE HAVE NO UVS! // all UV settings we might encounter. WE HAVE NO UVS!
@ -668,7 +670,7 @@ void IRRImporter::GenerateGraph(Node *root, aiNode *rootOut, aiScene *scene,
} }
// NOTE: Each mesh should have exactly one material assigned, // NOTE: Each mesh should have exactly one material assigned,
// but we do it in a separate loop if this behaviour changes // but we do it in a separate loop if this behavior changes
// in future. // in future.
for (unsigned int i = 0; i < localScene->mNumMeshes; ++i) { for (unsigned int i = 0; i < localScene->mNumMeshes; ++i) {
// Process material flags // Process material flags
@ -701,9 +703,9 @@ void IRRImporter::GenerateGraph(Node *root, aiNode *rootOut, aiScene *scene,
} }
// If we have a second texture coordinate set and a second texture // If we have a second texture coordinate set and a second texture
// (either lightmap, normalmap, 2layered material) we need to // (either light-map, normal-map, 2layered material) we need to
// setup the correct UV index for it. The texture can either // setup the correct UV index for it. The texture can either
// be diffuse (lightmap & 2layer) or a normal map (normal & parallax) // be diffuse (light-map & 2layer) or a normal map (normal & parallax)
if (mesh->HasTextureCoords(1)) { if (mesh->HasTextureCoords(1)) {
int idx = 1; int idx = 1;
@ -726,8 +728,8 @@ void IRRImporter::GenerateGraph(Node *root, aiNode *rootOut, aiScene *scene,
// Generate the sphere model. Our input parameter to // Generate the sphere model. Our input parameter to
// the sphere generation algorithm is the number of // the sphere generation algorithm is the number of
// subdivisions of each triangle - but here we have // subdivisions of each triangle - but here we have
// the number of poylgons on a specific axis. Just // the number of polygons on a specific axis. Just
// use some hardcoded limits to approximate this ... // use some hard-coded limits to approximate this ...
unsigned int mul = root->spherePolyCountX * root->spherePolyCountY; unsigned int mul = root->spherePolyCountX * root->spherePolyCountY;
if (mul < 100) if (mul < 100)
mul = 2; mul = 2;
@ -767,13 +769,13 @@ void IRRImporter::GenerateGraph(Node *root, aiNode *rootOut, aiScene *scene,
} break; } break;
case Node::SKYBOX: { case Node::SKYBOX: {
// A skybox is defined by six materials // A sky-box is defined by six materials
if (root->materials.size() < 6) { if (root->materials.size() < 6) {
ASSIMP_LOG_ERROR("IRR: There should be six materials for a skybox"); ASSIMP_LOG_ERROR("IRR: There should be six materials for a skybox");
break; break;
} }
// copy those materials and generate 6 meshes for our new skybox // copy those materials and generate 6 meshes for our new sky-box
materials.reserve(materials.size() + 6); materials.reserve(materials.size() + 6);
for (unsigned int i = 0; i < 6; ++i) for (unsigned int i = 0; i < 6; ++i)
materials.insert(materials.end(), root->materials[i].first); materials.insert(materials.end(), root->materials[i].first);
@ -880,7 +882,7 @@ void IRRImporter::InternReadFile(const std::string &pFile,
// Current node parent // Current node parent
Node *curParent = root; Node *curParent = root;
// Scenegraph node we're currently working on // Scene-graph node we're currently working on
Node *curNode = nullptr; Node *curNode = nullptr;
// List of output cameras // List of output cameras
@ -905,7 +907,7 @@ void IRRImporter::InternReadFile(const std::string &pFile,
for (pugi::xml_node child : rootElement->children()) for (pugi::xml_node child : rootElement->children())
switch (child.type()) { switch (child.type()) {
case pugi::node_element: case pugi::node_element:
if (!ASSIMP_stricmp(child.name(), "node")) { if (!ASSIMP_stricmp(child.name(), "node")) {
// *********************************************************************** // ***********************************************************************
/* What we're going to do with the node depends /* What we're going to do with the node depends
* on its type: * on its type:
@ -986,7 +988,7 @@ void IRRImporter::InternReadFile(const std::string &pFile,
inAnimator = true; inAnimator = true;
} else if (!ASSIMP_stricmp(child.name(), "attributes")) { } else if (!ASSIMP_stricmp(child.name(), "attributes")) {
// We should have a valid node here // We should have a valid node here
// FIX: no ... the scene root node is also contained in an attributes block // FIX: no ... the scene root node is also contained in an attributes block
if (!curNode) { if (!curNode) {
#if 0 #if 0
ASSIMP_LOG_ERROR("IRR: Encountered <attributes> element, but " ASSIMP_LOG_ERROR("IRR: Encountered <attributes> element, but "
@ -1009,7 +1011,7 @@ void IRRImporter::InternReadFile(const std::string &pFile,
continue; continue;
} else if (inAnimator) { } else if (inAnimator) {
// This is an animation path - add a new animator // This is an animation path - add a new animator
// to the list. // to the list.
curNode->animators.push_back(Animator()); curNode->animators.push_back(Animator());
curAnim = &curNode->animators.back(); curAnim = &curNode->animators.back();
@ -1019,10 +1021,10 @@ void IRRImporter::InternReadFile(const std::string &pFile,
/* Parse all elements in the attributes block /* Parse all elements in the attributes block
* and process them. * and process them.
*/ */
// while (reader->read()) { // while (reader->read()) {
for (pugi::xml_node attrib : child.children()) { for (pugi::xml_node attrib : child.children()) {
if (attrib.type() == pugi::node_element) { if (attrib.type() == pugi::node_element) {
//if (reader->getNodeType() == EXN_ELEMENT) { //if (reader->getNodeType() == EXN_ELEMENT) {
//if (!ASSIMP_stricmp(reader->getNodeName(), "vector3d")) { //if (!ASSIMP_stricmp(reader->getNodeName(), "vector3d")) {
if (!ASSIMP_stricmp(attrib.name(), "vector3d")) { if (!ASSIMP_stricmp(attrib.name(), "vector3d")) {
VectorProperty prop; VectorProperty prop;
@ -1081,16 +1083,16 @@ void IRRImporter::InternReadFile(const std::string &pFile,
} }
} }
} }
//} else if (!ASSIMP_stricmp(reader->getNodeName(), "bool")) { //} else if (!ASSIMP_stricmp(reader->getNodeName(), "bool")) {
} else if (!ASSIMP_stricmp(attrib.name(), "bool")) { } else if (!ASSIMP_stricmp(attrib.name(), "bool")) {
BoolProperty prop; BoolProperty prop;
ReadBoolProperty(prop); ReadBoolProperty(prop);
if (inAnimator && curAnim->type == Animator::FLY_CIRCLE && prop.name == "Loop") { if (inAnimator && curAnim->type == Animator::FLY_CIRCLE && prop.name == "Loop") {
curAnim->loop = prop.value; curAnim->loop = prop.value;
} }
//} else if (!ASSIMP_stricmp(reader->getNodeName(), "float")) { //} else if (!ASSIMP_stricmp(reader->getNodeName(), "float")) {
} else if (!ASSIMP_stricmp(attrib.name(), "float")) { } else if (!ASSIMP_stricmp(attrib.name(), "float")) {
FloatProperty prop; FloatProperty prop;
ReadFloatProperty(prop); ReadFloatProperty(prop);
@ -1138,8 +1140,8 @@ void IRRImporter::InternReadFile(const std::string &pFile,
curNode->sphereRadius = prop.value; curNode->sphereRadius = prop.value;
} }
} }
//} else if (!ASSIMP_stricmp(reader->getNodeName(), "int")) { //} else if (!ASSIMP_stricmp(reader->getNodeName(), "int")) {
} else if (!ASSIMP_stricmp(attrib.name(), "int")) { } else if (!ASSIMP_stricmp(attrib.name(), "int")) {
IntProperty prop; IntProperty prop;
ReadIntProperty(prop); ReadIntProperty(prop);
@ -1158,8 +1160,8 @@ void IRRImporter::InternReadFile(const std::string &pFile,
} }
} }
} }
//} else if (!ASSIMP_stricmp(reader->getNodeName(), "string") || !ASSIMP_stricmp(reader->getNodeName(), "enum")) { //} else if (!ASSIMP_stricmp(reader->getNodeName(), "string") || !ASSIMP_stricmp(reader->getNodeName(), "enum")) {
} else if (!ASSIMP_stricmp(attrib.name(), "string") || !ASSIMP_stricmp(attrib.name(), "enum")) { } else if (!ASSIMP_stricmp(attrib.name(), "string") || !ASSIMP_stricmp(attrib.name(), "enum")) {
StringProperty prop; StringProperty prop;
ReadStringProperty(prop); ReadStringProperty(prop);
if (prop.value.length()) { if (prop.value.length()) {
@ -1209,11 +1211,11 @@ void IRRImporter::InternReadFile(const std::string &pFile,
} }
/* TODO: maybe implement the protection against recursive /* TODO: maybe implement the protection against recursive
* loading calls directly in BatchLoader? The current * loading calls directly in BatchLoader? The current
* implementation is not absolutely safe. A LWS and an IRR * implementation is not absolutely safe. A LWS and an IRR
* file referencing each other *could* cause the system to * file referencing each other *could* cause the system to
* recurse forever. * recurse forever.
*/ */
const std::string extension = GetExtension(prop.value); const std::string extension = GetExtension(prop.value);
if ("irr" == extension) { if ("irr" == extension) {
@ -1240,7 +1242,7 @@ void IRRImporter::InternReadFile(const std::string &pFile,
} }
} }
} }
//} else if (reader->getNodeType() == EXN_ELEMENT_END && !ASSIMP_stricmp(reader->getNodeName(), "attributes")) { //} else if (reader->getNodeType() == EXN_ELEMENT_END && !ASSIMP_stricmp(reader->getNodeName(), "attributes")) {
} else if (attrib.type() == pugi::node_null && !ASSIMP_stricmp(attrib.name(), "attributes")) { } else if (attrib.type() == pugi::node_null && !ASSIMP_stricmp(attrib.name(), "attributes")) {
break; break;
} }
@ -1248,7 +1250,7 @@ void IRRImporter::InternReadFile(const std::string &pFile,
} }
break; break;
/*case EXN_ELEMENT_END: /*case EXN_ELEMENT_END:
// If we reached the end of a node, we need to continue processing its parent // If we reached the end of a node, we need to continue processing its parent
if (!ASSIMP_stricmp(reader->getNodeName(), "node")) { if (!ASSIMP_stricmp(reader->getNodeName(), "node")) {
@ -1274,108 +1276,108 @@ void IRRImporter::InternReadFile(const std::string &pFile,
default: default:
// GCC complains that not all enumeration values are handled // GCC complains that not all enumeration values are handled
break; break;
} }
//} //}
// Now iterate through all cameras and compute their final (horizontal) FOV // Now iterate through all cameras and compute their final (horizontal) FOV
for (aiCamera *cam : cameras) { for (aiCamera *cam : cameras) {
// screen aspect could be missing // screen aspect could be missing
if (cam->mAspect) { if (cam->mAspect) {
cam->mHorizontalFOV *= cam->mAspect; cam->mHorizontalFOV *= cam->mAspect;
} else { } else {
ASSIMP_LOG_WARN("IRR: Camera aspect is not given, can't compute horizontal FOV"); ASSIMP_LOG_WARN("IRR: Camera aspect is not given, can't compute horizontal FOV");
} }
} }
batch.LoadAll(); batch.LoadAll();
// Allocate a temporary scene data structure // Allocate a temporary scene data structure
aiScene *tempScene = new aiScene(); aiScene *tempScene = new aiScene();
tempScene->mRootNode = new aiNode(); tempScene->mRootNode = new aiNode();
tempScene->mRootNode->mName.Set("<IRRRoot>"); tempScene->mRootNode->mName.Set("<IRRRoot>");
// Copy the cameras to the output array // Copy the cameras to the output array
if (!cameras.empty()) { if (!cameras.empty()) {
tempScene->mNumCameras = (unsigned int)cameras.size(); tempScene->mNumCameras = (unsigned int)cameras.size();
tempScene->mCameras = new aiCamera *[tempScene->mNumCameras]; tempScene->mCameras = new aiCamera *[tempScene->mNumCameras];
::memcpy(tempScene->mCameras, &cameras[0], sizeof(void *) * tempScene->mNumCameras); ::memcpy(tempScene->mCameras, &cameras[0], sizeof(void *) * tempScene->mNumCameras);
} }
// Copy the light sources to the output array // Copy the light sources to the output array
if (!lights.empty()) { if (!lights.empty()) {
tempScene->mNumLights = (unsigned int)lights.size(); tempScene->mNumLights = (unsigned int)lights.size();
tempScene->mLights = new aiLight *[tempScene->mNumLights]; tempScene->mLights = new aiLight *[tempScene->mNumLights];
::memcpy(tempScene->mLights, &lights[0], sizeof(void *) * tempScene->mNumLights); ::memcpy(tempScene->mLights, &lights[0], sizeof(void *) * tempScene->mNumLights);
} }
// temporary data // temporary data
std::vector<aiNodeAnim *> anims; std::vector<aiNodeAnim *> anims;
std::vector<aiMaterial *> materials; std::vector<aiMaterial *> materials;
std::vector<AttachmentInfo> attach; std::vector<AttachmentInfo> attach;
std::vector<aiMesh *> meshes; std::vector<aiMesh *> meshes;
// try to guess how much storage we'll need // try to guess how much storage we'll need
anims.reserve(guessedAnimCnt + (guessedAnimCnt >> 2)); anims.reserve(guessedAnimCnt + (guessedAnimCnt >> 2));
meshes.reserve(guessedMeshCnt + (guessedMeshCnt >> 2)); meshes.reserve(guessedMeshCnt + (guessedMeshCnt >> 2));
materials.reserve(guessedMatCnt + (guessedMatCnt >> 2)); materials.reserve(guessedMatCnt + (guessedMatCnt >> 2));
// Now process our scene-graph recursively: generate final // Now process our scene-graph recursively: generate final
// meshes and generate animation channels for all nodes. // meshes and generate animation channels for all nodes.
unsigned int defMatIdx = UINT_MAX; unsigned int defMatIdx = UINT_MAX;
GenerateGraph(root, tempScene->mRootNode, tempScene, GenerateGraph(root, tempScene->mRootNode, tempScene,
batch, meshes, anims, attach, materials, defMatIdx); batch, meshes, anims, attach, materials, defMatIdx);
if (!anims.empty()) { if (!anims.empty()) {
tempScene->mNumAnimations = 1; tempScene->mNumAnimations = 1;
tempScene->mAnimations = new aiAnimation *[tempScene->mNumAnimations]; tempScene->mAnimations = new aiAnimation *[tempScene->mNumAnimations];
aiAnimation *an = tempScene->mAnimations[0] = new aiAnimation(); aiAnimation *an = tempScene->mAnimations[0] = new aiAnimation();
// *********************************************************** // ***********************************************************
// This is only the global animation channel of the scene. // This is only the global animation channel of the scene.
// If there are animated models, they will have separate // If there are animated models, they will have separate
// animation channels in the scene. To display IRR scenes // animation channels in the scene. To display IRR scenes
// correctly, users will need to combine the global anim // correctly, users will need to combine the global anim
// channel with all the local animations they want to play // channel with all the local animations they want to play
// *********************************************************** // ***********************************************************
an->mName.Set("Irr_GlobalAnimChannel"); an->mName.Set("Irr_GlobalAnimChannel");
// copy all node animation channels to the global channel // copy all node animation channels to the global channel
an->mNumChannels = (unsigned int)anims.size(); an->mNumChannels = (unsigned int)anims.size();
an->mChannels = new aiNodeAnim *[an->mNumChannels]; an->mChannels = new aiNodeAnim *[an->mNumChannels];
::memcpy(an->mChannels, &anims[0], sizeof(void *) * an->mNumChannels); ::memcpy(an->mChannels, &anims[0], sizeof(void *) * an->mNumChannels);
} }
if (!meshes.empty()) { if (!meshes.empty()) {
// copy all meshes to the temporary scene // copy all meshes to the temporary scene
tempScene->mNumMeshes = (unsigned int)meshes.size(); tempScene->mNumMeshes = (unsigned int)meshes.size();
tempScene->mMeshes = new aiMesh *[tempScene->mNumMeshes]; tempScene->mMeshes = new aiMesh *[tempScene->mNumMeshes];
::memcpy(tempScene->mMeshes, &meshes[0], tempScene->mNumMeshes * sizeof(void *)); ::memcpy(tempScene->mMeshes, &meshes[0], tempScene->mNumMeshes * sizeof(void *));
} }
// Copy all materials to the output array // Copy all materials to the output array
if (!materials.empty()) { if (!materials.empty()) {
tempScene->mNumMaterials = (unsigned int)materials.size(); tempScene->mNumMaterials = (unsigned int)materials.size();
tempScene->mMaterials = new aiMaterial *[tempScene->mNumMaterials]; tempScene->mMaterials = new aiMaterial *[tempScene->mNumMaterials];
::memcpy(tempScene->mMaterials, &materials[0], sizeof(void *) * tempScene->mNumMaterials); ::memcpy(tempScene->mMaterials, &materials[0], sizeof(void *) * tempScene->mNumMaterials);
} }
// Now merge all sub scenes and attach them to the correct // Now merge all sub scenes and attach them to the correct
// attachment points in the scenegraph. // attachment points in the scenegraph.
SceneCombiner::MergeScenes(&pScene, tempScene, attach, SceneCombiner::MergeScenes(&pScene, tempScene, attach,
AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES | (!configSpeedFlag ? ( AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES | (!configSpeedFlag ? (
AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY | AI_INT_MERGE_SCENE_GEN_UNIQUE_MATNAMES) : AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY | AI_INT_MERGE_SCENE_GEN_UNIQUE_MATNAMES) :
0)); 0));
// If we have no meshes | no materials now set the INCOMPLETE // If we have no meshes | no materials now set the INCOMPLETE
// scene flag. This is necessary if we failed to load all // scene flag. This is necessary if we failed to load all
// models from external files // models from external files
if (!pScene->mNumMeshes || !pScene->mNumMaterials) { if (!pScene->mNumMeshes || !pScene->mNumMaterials) {
ASSIMP_LOG_WARN("IRR: No meshes loaded, setting AI_SCENE_FLAGS_INCOMPLETE"); ASSIMP_LOG_WARN("IRR: No meshes loaded, setting AI_SCENE_FLAGS_INCOMPLETE");
pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
} }
// Finished ... everything destructs automatically and all // Finished ... everything destructs automatically and all
// temporary scenes have already been deleted by MergeScenes() // temporary scenes have already been deleted by MergeScenes()
delete root; delete root;
} }
#endif // !! ASSIMP_BUILD_NO_IRR_IMPORTER #endif // !! ASSIMP_BUILD_NO_IRR_IMPORTER

View File

@ -141,6 +141,25 @@ private:
}; // ! class CIrrXML_IOStreamReader }; // ! class CIrrXML_IOStreamReader
*/ */
class XmlNode {
public:
XmlNode()
: mNode(nullptr){
// empty
}
XmlNode(pugi::xml_node *node)
: mNode(node) {
// empty
}
pugi::xml_node *getNode() const {
return mNode;
}
private:
pugi::xml_node *mNode;
};
class XmlParser { class XmlParser {
public: public:
XmlParser() : XmlParser() :
@ -158,7 +177,7 @@ public:
mDoc = nullptr; mDoc = nullptr;
} }
pugi::xml_node *parse(IOStream *stream) { XmlNode *parse(IOStream *stream) {
if (nullptr == stream) { if (nullptr == stream) {
return nullptr; return nullptr;
} }
@ -168,7 +187,8 @@ public:
mDoc = new pugi::xml_document(); mDoc = new pugi::xml_document();
pugi::xml_parse_result result = mDoc->load_string(&mData[0]); pugi::xml_parse_result result = mDoc->load_string(&mData[0]);
if (result.status == pugi::status_ok) { if (result.status == pugi::status_ok) {
mRoot = &mDoc->root(); pugi::xml_node *root = &mDoc->root();
mRoot = new XmlNode(root);
} }
return mRoot; return mRoot;
@ -180,7 +200,7 @@ public:
private: private:
pugi::xml_document *mDoc; pugi::xml_document *mDoc;
pugi::xml_node *mRoot; XmlNode *mRoot;
std::vector<char> mData; std::vector<char> mData;
}; };