From c359b973bbf244b97ea1c996687460ac305ce47e Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Wed, 26 Aug 2020 22:31:46 +0200 Subject: [PATCH] finish migration of collada. --- code/AssetLib/Collada/ColladaParser.cpp | 660 ++++++++---------------- code/AssetLib/Collada/ColladaParser.h | 37 -- code/CMakeLists.txt | 3 +- include/assimp/XmlParser.h | 11 + 4 files changed, 241 insertions(+), 470 deletions(-) diff --git a/code/AssetLib/Collada/ColladaParser.cpp b/code/AssetLib/Collada/ColladaParser.cpp index 03afda0ab..e1046c622 100644 --- a/code/AssetLib/Collada/ColladaParser.cpp +++ b/code/AssetLib/Collada/ColladaParser.cpp @@ -224,7 +224,7 @@ void ColladaParser::UriDecodePath(aiString &ss) { // ------------------------------------------------------------------------------------------------ // Read bool from text contents of current element -bool ColladaParser::ReadBoolFromTextContent() { +/*bool ColladaParser::ReadBoolFromTextContent() { const char *cur = GetTextContent(); if (nullptr == cur) { return false; @@ -240,7 +240,7 @@ ai_real ColladaParser::ReadFloatFromTextContent() { return 0.0; } return fast_atof(cur); -} +}*/ // ------------------------------------------------------------------------------------------------ // Reads the contents of the file @@ -664,11 +664,11 @@ void ColladaParser::ReadController(XmlNode &node, Collada::Controller &pControll } } else if (currentName == "source") { ReadSource(currentNode); - } else if (IsElement("joints")) { + } else if (currentName == "joints" ) { ReadControllerJoints(currentNode, pController); - } else if (IsElement("vertex_weights")) { + } else if (currentName == "vertex_weights") { ReadControllerWeights(currentNode, pController); - } else if (IsElement("targets")) { + } else if (currentName == "targets") { for (XmlNode currendChildNode : currentNode.children()) { const std::string currentChildName = currendChildNode.name(); if (currentChildName == "input") { @@ -713,13 +713,8 @@ void ColladaParser::ReadControllerJoints(XmlNode &node, Collada::Controller &pCo // 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 = node.attribute("count").as_int(); - pController.mWeightCounts.resize(vertexCount); - - /*// read vertex count from attributes and resize the array accordingly - int indexCount = GetAttribute("count"); - size_t vertexCount = (size_t)mReader->getAttributeValueAsInt(indexCount); - pController.mWeightCounts.resize(vertexCount);*/ + int vertexCount; + XmlParser::getIntAttribute(node, "count", vertexCount); for (XmlNode currentNode : node.children()) { std::string currentName = currentNode.name(); @@ -810,7 +805,7 @@ void ColladaParser::ReadImage(XmlNode &node, Collada::Image &pImage) { // FIX: C4D exporter writes empty tags if (!currentNode.empty()) { // element content is filename - hopefully - const char *sz = TestTextContent(); + const char *sz = currentNode.value(); if (sz) { aiString filepath(sz); UriDecodePath(filepath); @@ -981,7 +976,7 @@ void ColladaParser::ReadLight(XmlNode &node, Collada::Light &pLight) { pLight.mType = aiLightSource_POINT; } else if (currentName == "color") { // text content contains 3 floats - const char *content = GetTextContent(); + const char *content = currentNode.value(); content = fast_atoreal_move(content, (ai_real &)pLight.mColor.r); SkipSpacesAndLineEnd(&content); @@ -992,35 +987,33 @@ void ColladaParser::ReadLight(XmlNode &node, Collada::Light &pLight) { content = fast_atoreal_move(content, (ai_real &)pLight.mColor.b); SkipSpacesAndLineEnd(&content); } else if (currentName == "constant_attenuation") { - pLight.mAttConstant = ReadFloatFromTextContent(); + XmlParser::getFloatAttribute(currentNode, "constant_attenuation", pLight.mAttConstant); } else if (currentName == "linear_attenuation") { - pLight.mAttLinear = ReadFloatFromTextContent(); + XmlParser::getFloatAttribute(currentNode, "linear_attenuation", pLight.mAttLinear); } else if (currentName == "quadratic_attenuation") { - pLight.mAttQuadratic = ReadFloatFromTextContent(); + XmlParser::getFloatAttribute(currentNode, "quadratic_attenuation", pLight.mAttQuadratic); } else if (currentName == "falloff_angle") { - pLight.mFalloffAngle = ReadFloatFromTextContent(); + XmlParser::getFloatAttribute(currentNode, "falloff_angle", pLight.mFalloffAngle); } else if (currentName == "falloff_exponent") { - pLight.mFalloffExponent = ReadFloatFromTextContent(); + XmlParser::getFloatAttribute(currentNode, "falloff_exponent", pLight.mFalloffExponent); } // FCOLLADA extensions // ------------------------------------------------------- else if (currentName == "outer_cone") { - pLight.mOuterAngle = ReadFloatFromTextContent(); - } - // ... and this one is even deprecated - else if (currentName == "penumbra_angle") { - pLight.mPenumbraAngle = ReadFloatFromTextContent(); + XmlParser::getFloatAttribute(currentNode, "outer_cone", pLight.mOuterAngle); + } else if (currentName == "penumbra_angle") { // ... and this one is even deprecated + XmlParser::getFloatAttribute(currentNode, "penumbra_angle", pLight.mPenumbraAngle); } else if (currentName == "intensity") { - pLight.mIntensity = ReadFloatFromTextContent(); + XmlParser::getFloatAttribute(currentNode, "intensity", pLight.mIntensity); } else if (currentName == "falloff") { - pLight.mOuterAngle = ReadFloatFromTextContent(); + XmlParser::getFloatAttribute(currentNode, "falloff", pLight.mOuterAngle); } else if (currentName == "hotspot_beam") { - pLight.mFalloffAngle = ReadFloatFromTextContent(); + XmlParser::getFloatAttribute(currentNode, "hotspot_beam", pLight.mFalloffAngle); } // OpenCOLLADA extensions // ------------------------------------------------------- else if (currentName == "decay_falloff") { - pLight.mOuterAngle = ReadFloatFromTextContent(); + XmlParser::getFloatAttribute(currentNode, "decay_falloff", pLight.mOuterAngle); } } } @@ -1033,15 +1026,15 @@ void ColladaParser::ReadCamera(XmlNode &node, Collada::Camera &camera) { if (currentName == "orthographic") { camera.mOrtho = true; } else if (currentName == "xfov" || currentName == "xmag") { - camera.mHorFov = ReadFloatFromTextContent(); + XmlParser::getFloatAttribute(currentNode, currentName.c_str(), (ai_real &)camera.mHorFov); } else if (currentName == "yfov" || currentName == "ymag") { - camera.mVerFov = ReadFloatFromTextContent(); + XmlParser::getFloatAttribute(currentNode, currentName.c_str(), (ai_real &)camera.mVerFov); } else if (currentName == "aspect_ratio") { - camera.mAspect = ReadFloatFromTextContent(); + XmlParser::getFloatAttribute(currentNode, currentName.c_str(), (ai_real &)camera.mAspect); } else if (currentName == "znear") { - camera.mZNear = ReadFloatFromTextContent(); + XmlParser::getFloatAttribute(currentNode, currentName.c_str(), (ai_real &)camera.mZNear); } else if (currentName == "zfar") { - camera.mZFar = ReadFloatFromTextContent(); + XmlParser::getFloatAttribute(currentNode, currentName.c_str(), (ai_real &)camera.mZFar); } } } @@ -1158,7 +1151,7 @@ void ColladaParser::ReadEffectProfileCommon(XmlNode &node, Collada::Effect &pEff // GOOGLEEARTH/OKINO extensions // ------------------------------------------------------- else if (currentName == "double_sided") - pEffect.mDoubleSided = ReadBoolFromTextContent(); + XmlParser::getBoolAttribute(currentNode, currentName.c_str(), pEffect.mDoubleSided); // FCOLLADA extensions // ------------------------------------------------------- @@ -1170,9 +1163,9 @@ void ColladaParser::ReadEffectProfileCommon(XmlNode &node, Collada::Effect &pEff // MAX3D extensions // ------------------------------------------------------- else if (currentName == "wireframe") { - pEffect.mWireframe = ReadBoolFromTextContent(); + XmlParser::getBoolAttribute(currentNode, currentName.c_str(), pEffect.mWireframe); } else if (currentName == "faceted") { - pEffect.mFaceted = ReadBoolFromTextContent(); + XmlParser::getBoolAttribute(currentNode, currentName.c_str(), pEffect.mFaceted); } } } @@ -1188,26 +1181,26 @@ void ColladaParser::ReadSamplerProperties(XmlNode &node, Sampler &out) { // MAYA extensions // ------------------------------------------------------- if (currentName == "wrapU") { - out.mWrapU = ReadBoolFromTextContent(); + XmlParser::getBoolAttribute(currentNode, currentName.c_str(), out.mWrapU); } else if (currentName == "wrapV") { - out.mWrapV = ReadBoolFromTextContent(); + XmlParser::getBoolAttribute(currentNode, currentName.c_str(), out.mWrapV); } else if (currentName == "mirrorU") { - out.mMirrorU = ReadBoolFromTextContent(); + XmlParser::getBoolAttribute(currentNode, currentName.c_str(), out.mMirrorU); } else if (currentName == "mirrorV") { - out.mMirrorV = ReadBoolFromTextContent(); + XmlParser::getBoolAttribute(currentNode, currentName.c_str(), out.mMirrorV); } else if (currentName == "repeatU") { - out.mTransform.mScaling.x = ReadFloatFromTextContent(); + XmlParser::getFloatAttribute(currentNode, currentName.c_str(), out.mTransform.mScaling.x); } else if (currentName == "repeatV") { - out.mTransform.mScaling.y = ReadFloatFromTextContent(); + XmlParser::getFloatAttribute(currentNode, currentName.c_str(), out.mTransform.mScaling.y); } else if (currentName == "offsetU") { - out.mTransform.mTranslation.x = ReadFloatFromTextContent(); + XmlParser::getFloatAttribute(currentNode, currentName.c_str(), out.mTransform.mTranslation.x); } else if (currentName == "offsetV") { - out.mTransform.mTranslation.y = ReadFloatFromTextContent(); + XmlParser::getFloatAttribute(currentNode, currentName.c_str(), out.mTransform.mTranslation.y); } else if (currentName == "rotateUV") { - out.mTransform.mRotation = ReadFloatFromTextContent(); + XmlParser::getFloatAttribute(currentNode, currentName.c_str(), out.mTransform.mRotation); } else if (currentName == "blend_mode") { - const char *sz = GetTextContent(); + const char *sz = currentNode.value(); // http://www.feelingsoftware.com/content/view/55/72/lang,en/ // NONE, OVER, IN, OUT, ADD, SUBTRACT, MULTIPLY, DIFFERENCE, LIGHTEN, DARKEN, SATURATE, DESATURATE and ILLUMINATE if (0 == ASSIMP_strincmp(sz, "ADD", 3)) @@ -1223,14 +1216,14 @@ void ColladaParser::ReadSamplerProperties(XmlNode &node, Sampler &out) { // OKINO extensions // ------------------------------------------------------- else if (currentName == "weighting") { - out.mWeighting = ReadFloatFromTextContent(); + XmlParser::getFloatAttribute(currentNode, currentName.c_str(), out.mWeighting); } else if (currentName == "mix_with_previous_layer") { - out.mMixWithPrevious = ReadFloatFromTextContent(); + XmlParser::getFloatAttribute(currentNode, currentName.c_str(), out.mMixWithPrevious); } // MAX3D extensions // ------------------------------------------------------- else if (currentName == "amount") { - out.mWeighting = ReadFloatFromTextContent(); + XmlParser::getFloatAttribute(currentNode, currentName.c_str(), out.mWeighting); } } } @@ -1289,7 +1282,7 @@ void ColladaParser::ReadEffectColor(XmlNode &node, aiColor4D &pColor, Sampler &p // Reads an effect entry containing a float void ColladaParser::ReadEffectFloat(XmlNode &node, ai_real &pFloat) { pFloat = 0.f; - if (node.name() == "float") { + if (node.name() == std::string("float")) { XmlParser::getFloatAttribute(node, "float", pFloat); } } @@ -1415,13 +1408,13 @@ void ColladaParser::ReadSource(XmlNode &node) { void ColladaParser::ReadDataArray(XmlNode &node) { std::string name = node.name(); bool isStringArray = (name == "IDREF_array" || name == "Name_array"); - bool isEmptyElement = node.empty(); + //bool isEmptyElement = node.empty(); // read attributes std::string id; XmlParser::getStdStrAttribute(node, "id", id); - int count; - XmlParser::getIntAttribute(node, "count", count); + unsigned int count; + XmlParser::getUIntAttribute(node, "count", count); const char *content = node.value(); // read values and store inside an array in the data library @@ -1545,7 +1538,7 @@ void ColladaParser::ReadAccessor(XmlNode &node, const std::string &pID) { // TODO: (thom) I don't have a spec here at work. Check if there are other multi-value types // which should be tested for here. std::string type; - + XmlParser::getStdStrAttribute(currentNode, "type", type); if (type == "float4x4") acc.mSize += 16; @@ -1565,10 +1558,10 @@ void ColladaParser::ReadVertexData(XmlNode &node, Mesh &pMesh) { XmlParser::getStdStrAttribute(node, "id", pMesh.mVertexID); for (XmlNode ¤tNode : node.children()) { const std::string ¤tName = currentNode.name(); - if (currentName == "input" ) { + if (currentName == "input") { ReadInputChannel(currentNode, pMesh.mPerVertexData); } else { - ThrowException(format() << "Unexpected sub element <" << mReader->getNodeName() << "> in tag "); + ThrowException(format() << "Unexpected sub element <" << currentName << "> in tag "); } } } @@ -1579,7 +1572,8 @@ void ColladaParser::ReadIndexData(XmlNode &node, Mesh &pMesh) { std::vector vcount; std::vector perIndexData; - XmlParser::getIntAttribute(node, "count", (int) numPrimitives); + unsigned int numPrimitives; + XmlParser::getUIntAttribute(node, "count", (unsigned int)numPrimitives); // read primitive count from the attribute //int attrCount = GetAttribute("count"); //size_t numPrimitives = (size_t)mReader->getAttributeValueAsInt(attrCount); @@ -1587,14 +1581,14 @@ void ColladaParser::ReadIndexData(XmlNode &node, Mesh &pMesh) { // so we need to sum up the actual number of primitives while we read the

-tags size_t actualPrimitives = 0; SubMesh subgroup; - if (XmlParser::hasAttribute("material")) { + if (XmlParser::hasAttribute(node, "material")) { XmlParser::getStdStrAttribute(node, "material", subgroup.mMaterial); } // material subgroup -// int attrMaterial = TestAttribute("material"); - + // int attrMaterial = TestAttribute("material"); + //if (attrMaterial > -1) - // subgroup.mMaterial = mReader->getAttributeValue(attrMaterial); + // subgroup.mMaterial = mReader->getAttributeValue(attrMaterial); // distinguish between polys and triangles std::string elementName = node.name(); @@ -1626,7 +1620,7 @@ void ColladaParser::ReadIndexData(XmlNode &node, Mesh &pMesh) { if (numPrimitives) // It is possible to define a mesh without any primitives { // case - specifies the number of indices for each polygon - const char *content = GetTextContent(); + const char *content = currentNode.value(); vcount.reserve(numPrimitives); for (unsigned int a = 0; a < numPrimitives; a++) { if (*content == 0) @@ -1645,10 +1639,10 @@ void ColladaParser::ReadIndexData(XmlNode &node, Mesh &pMesh) { } } else if (currentName == "extra") { // skip - } else if (currentName == "ph") { + } else if (currentName == "ph") { // skip } else { - ThrowException(format() << "Unexpected sub element <" << mReader->getNodeName() << "> in tag <" << elementName << ">"); + ThrowException(format() << "Unexpected sub element <" << currentName << "> in tag <" << elementName << ">"); } } @@ -1686,31 +1680,26 @@ void ColladaParser::ReadInputChannel(XmlNode &node, std::vector &p channel.mAccessor = source.c_str() + 1; // skipping the leading #, hopefully the remaining text is the accessor ID only // read index offset, if per-index - if (XmlParser::hasAttribute("offset")) { - XmlParser::getStdStrAttribute(node, "offset", channel.mOffset); - } + if (XmlParser::hasAttribute(node, "offset")) { + XmlParser::getUIntAttribute(node, "offset", (unsigned int &)channel.mOffset); + } //int attrOffset = TestAttribute("offset"); //if (attrOffset > -1) -// channel.mOffset = mReader->getAttributeValueAsInt(attrOffset); + // channel.mOffset = mReader->getAttributeValueAsInt(attrOffset); // read set if texture coordinates if (channel.mType == IT_Texcoord || channel.mType == IT_Color) { - int attrSet = TestAttribute("set"); - if (attrSet > -1) { - attrSet = mReader->getAttributeValueAsInt(attrSet); - if (attrSet < 0) - ThrowException(format() << "Invalid index \"" << (attrSet) << "\" in set attribute of element"); - - channel.mIndex = attrSet; + int attrSet = -1; + if (XmlParser::hasAttribute(node, "set")) { + XmlParser::getIntAttribute(node, "set", attrSet); } + + channel.mIndex = attrSet; } // store, if valid type if (channel.mType != IT_Invalid) poChannels.push_back(channel); - - // skip remaining stuff of this element, if any - SkipElement(); } // ------------------------------------------------------------------------------------------------ @@ -1753,7 +1742,7 @@ size_t ColladaParser::ReadPrimitives(XmlNode &node, Mesh &pMesh, std::vector 0) // It is possible to not contain any indices { - const char *content = GetTextContent(); + const char *content = node.value(); while (*content != 0) { // read a value. // Hack: (thom) Some exporters put negative indices sometimes. We just try to carry on anyways. @@ -1875,7 +1864,6 @@ size_t ColladaParser::ReadPrimitives(XmlNode &node, Mesh &pMesh, std::vectorisEmptyElement()) return;*/ - while (mReader->read()) { - if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { - // a visual scene - generate root node under its ID and let ReadNode() do the recursive work - if (IsElement("visual_scene")) { - // read ID. Is optional according to the spec, but how on earth should a scene_instance refer to it then? - int indexID = GetAttribute("id"); - const char *attrID = mReader->getAttributeValue(indexID); + for (XmlNode ¤tNode : node.children()) { + const std::string ¤tName = currentNode.name(); + if (currentName == "visual_scene") { + // read ID. Is optional according to the spec, but how on earth should a scene_instance refer to it then? + std::string id; + XmlParser::getStdStrAttribute(currentNode, "id", id); + //int indexID = GetAttribute("id"); + //const char *attrID = mReader->getAttributeValue(indexID); - // read name if given. - int indexName = TestAttribute("name"); - const char *attrName = "Scene"; - if (indexName > -1) - attrName = mReader->getAttributeValue(indexName); - - // create a node and store it in the library under its ID - Node *node = new Node; - node->mID = attrID; - node->mName = attrName; - mNodeLibrary[node->mID] = node; - - ReadSceneNode(node); - } else { - // ignore the rest - SkipElement(); + std::string attrName = "Scene"; + if (XmlParser::hasAttribute(currentNode, "name")) { + XmlParser::getStdStrAttribute(currentNode, "name", attrName); } - } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { - if (strcmp(mReader->getNodeName(), "library_visual_scenes") == 0) - //ThrowException( "Expected end of \"library_visual_scenes\" element."); + // read name if given. + //int indexName = TestAttribute("name"); + //const char *attrName = "Scene"; + //if (indexName > -1) + //attrName = mReader->getAttributeValue(indexName); - break; + // create a node and store it in the library under its ID + Node *sceneNode = new Node; + sceneNode->mID = id; + sceneNode->mName = attrName; + mNodeLibrary[sceneNode->mID] = sceneNode; + + ReadSceneNode(node, sceneNode); } } } @@ -2066,113 +2050,98 @@ void ColladaParser::ReadSceneNode(XmlNode &node, Node *pNode) { return; } - /* if (mReader->isEmptyElement()) - return;*/ - - while (mReader->read()) { - if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { - if (IsElement("node")) { - Node *child = new Node; - int attrID = TestAttribute("id"); - if (attrID > -1) - child->mID = mReader->getAttributeValue(attrID); - int attrSID = TestAttribute("sid"); - if (attrSID > -1) - child->mSID = mReader->getAttributeValue(attrSID); - - int attrName = TestAttribute("name"); - if (attrName > -1) - child->mName = mReader->getAttributeValue(attrName); - - if (pNode) { - pNode->mChildren.push_back(child); - child->mParent = pNode; - } else { - // no parent node given, probably called from element. - // create new node in node library - mNodeLibrary[child->mID] = child; - } - - // read on recursively from there - ReadSceneNode(child); - continue; + for (XmlNode ¤tNode : node.children()) { + const std::string ¤tName = currentNode.name(); + if (currentName == "node") { + Node *child = new Node; + if (XmlParser::hasAttribute(currentNode, "id")) { + XmlParser::getStdStrAttribute(currentNode, "id", child->mID); } - // For any further stuff we need a valid node to work on - else if (!pNode) - continue; - - if (IsElement("lookat")) - ReadNodeTransformation(pNode, TF_LOOKAT); - else if (IsElement("matrix")) - ReadNodeTransformation(pNode, TF_MATRIX); - else if (IsElement("rotate")) - ReadNodeTransformation(pNode, TF_ROTATE); - else if (IsElement("scale")) - ReadNodeTransformation(pNode, TF_SCALE); - else if (IsElement("skew")) - ReadNodeTransformation(pNode, TF_SKEW); - else if (IsElement("translate")) - ReadNodeTransformation(pNode, TF_TRANSLATE); - else if (IsElement("render") && pNode->mParent == nullptr && 0 == pNode->mPrimaryCamera.length()) { - // ... scene evaluation or, in other words, postprocessing pipeline, - // or, again in other words, a turing-complete description how to - // render a Collada scene. The only thing that is interesting for - // us is the primary camera. - int attrId = TestAttribute("camera_node"); - if (-1 != attrId) { - const char *s = mReader->getAttributeValue(attrId); - if (s[0] != '#') - ASSIMP_LOG_ERROR("Collada: Unresolved reference format of camera"); - else - pNode->mPrimaryCamera = s + 1; - } - } else if (IsElement("instance_node")) { - // find the node in the library - int attrID = TestAttribute("url"); - if (attrID != -1) { - const char *s = mReader->getAttributeValue(attrID); - if (s[0] != '#') - ASSIMP_LOG_ERROR("Collada: Unresolved reference format of node"); - else { - pNode->mNodeInstances.push_back(NodeInstance()); - pNode->mNodeInstances.back().mNode = s + 1; - } - } - } else if (IsElement("instance_geometry") || IsElement("instance_controller")) { - // Reference to a mesh or controller, with possible material associations - ReadNodeGeometry(pNode); - } else if (IsElement("instance_light")) { - // Reference to a light, name given in 'url' attribute - int attrID = TestAttribute("url"); - if (-1 == attrID) - ASSIMP_LOG_WARN("Collada: Expected url attribute in element"); - else { - const char *url = mReader->getAttributeValue(attrID); - if (url[0] != '#') - ThrowException("Unknown reference format in element"); - - pNode->mLights.push_back(LightInstance()); - pNode->mLights.back().mLight = url + 1; - } - } else if (IsElement("instance_camera")) { - // Reference to a camera, name given in 'url' attribute - int attrID = TestAttribute("url"); - if (-1 == attrID) - ASSIMP_LOG_WARN("Collada: Expected url attribute in element"); - else { - const char *url = mReader->getAttributeValue(attrID); - if (url[0] != '#') - ThrowException("Unknown reference format in element"); - - pNode->mCameras.push_back(CameraInstance()); - pNode->mCameras.back().mCamera = url + 1; - } + if (XmlParser::hasAttribute(currentNode, "sid")) { + XmlParser::getStdStrAttribute(currentNode, "id", child->mSID); + } + if (XmlParser::hasAttribute(currentNode, "name")) { + XmlParser::getStdStrAttribute(currentNode, "name", child->mName); + } + if (pNode) { + pNode->mChildren.push_back(child); + child->mParent = pNode; } else { - // skip everything else for the moment - SkipElement(); + // no parent node given, probably called from element. + // create new node in node library + mNodeLibrary[child->mID] = child; + } + + // read on recursively from there + ReadSceneNode(currentNode, child); + continue; + } else if (!pNode) { + // For any further stuff we need a valid node to work on + continue; + } + if (currentName == "lookat") { + ReadNodeTransformation(currentNode, pNode, TF_LOOKAT); + } else if (currentName == "matrix") { + ReadNodeTransformation(currentNode, pNode, TF_MATRIX); + } else if (currentName == "rotate") { + ReadNodeTransformation(currentNode, pNode, TF_ROTATE); + } else if (currentName == "scale") { + ReadNodeTransformation(currentNode, pNode, TF_SCALE); + } else if (currentName == "skew") { + ReadNodeTransformation(currentNode, pNode, TF_SKEW); + } else if (currentName == "translate") { + ReadNodeTransformation(currentNode, pNode, TF_TRANSLATE); + } else if (currentName == "render" && pNode->mParent == nullptr && 0 == pNode->mPrimaryCamera.length()) { + // ... scene evaluation or, in other words, postprocessing pipeline, + // or, again in other words, a turing-complete description how to + // render a Collada scene. The only thing that is interesting for + // us is the primary camera. + if (XmlParser::hasAttribute(currentNode, "camera_node")) { + std::string s; + XmlParser::getStdStrAttribute(currentNode, "camera_node", s); + if (s[0] != '#') { + ASSIMP_LOG_ERROR("Collada: Unresolved reference format of camera"); + } else { + pNode->mPrimaryCamera = s.c_str() + 1; + } + } + } else if (currentName == "instance_node") { + // find the node in the library + if (XmlParser::hasAttribute(currentNode, "url")) { + std::string s; + XmlParser::getStdStrAttribute(currentNode, "url", s); + if (s[0] != '#') { + ASSIMP_LOG_ERROR("Collada: Unresolved reference format of node"); + } else { + pNode->mNodeInstances.push_back(NodeInstance()); + pNode->mNodeInstances.back().mNode = s.c_str() + 1; + } + } + } else if (currentName == "instance_geometry" || currentName == "instance_controller") { + // Reference to a mesh or controller, with possible material associations + ReadNodeGeometry(currentNode, pNode); + } else if (currentName == "instance_light") { + // Reference to a light, name given in 'url' attribute + if (XmlParser::hasAttribute(currentNode, "url")) { + std::string url; + XmlParser::getStdStrAttribute(currentNode, "url", url); + if (url[0] != '#') + ThrowException("Unknown reference format in element"); + + pNode->mLights.push_back(LightInstance()); + pNode->mLights.back().mLight = url.c_str() + 1; + } + } else if (currentName == "instance_camera") { + // Reference to a camera, name given in 'url' attribute + if (XmlParser::hasAttribute(currentNode, "url")) { + std::string url; + XmlParser::getStdStrAttribute(currentNode, "url", url); + if (url[0] != '#') { + ThrowException("Unknown reference format in element"); + } + pNode->mCameras.push_back(CameraInstance()); + pNode->mCameras.back().mCamera = url.c_str() + 1; } - } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { - break; } } } @@ -2183,22 +2152,20 @@ void ColladaParser::ReadNodeTransformation(XmlNode &node, Node *pNode, Transform if (node.empty()) { return; } - /*if (mReader->isEmptyElement()) - return;*/ - std::string tagName = mReader->getNodeName(); + std::string tagName = node.name(); Transform tf; tf.mType = pType; // read SID - int indexSID = TestAttribute("sid"); - if (indexSID >= 0) - tf.mID = mReader->getAttributeValue(indexSID); + if (XmlParser::hasAttribute(node, "sid")) { + XmlParser::getStdStrAttribute(node, "sid", tf.mID); + } // how many parameters to read per transformation type static const unsigned int sNumParameters[] = { 9, 4, 3, 3, 7, 16 }; - const char *content = GetTextContent(); + const char *content = node.value(); // read as many parameters and store in the transformation for (unsigned int a = 0; a < sNumParameters[pType]; a++) { @@ -2210,39 +2177,36 @@ void ColladaParser::ReadNodeTransformation(XmlNode &node, Node *pNode, Transform // place the transformation at the queue of the node pNode->mTransforms.push_back(tf); - - // and consume the closing tag - TestClosing(tagName.c_str()); } // ------------------------------------------------------------------------------------------------ // Processes bind_vertex_input and bind elements void ColladaParser::ReadMaterialVertexInputBinding(XmlNode &node, Collada::SemanticMappingTable &tbl) { - while (mReader->read()) { - if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { - if (IsElement("bind_vertex_input")) { - Collada::InputSemanticMapEntry vn; + for (XmlNode ¤tNode : node.children()) { + const std::string ¤tName = currentNode.name(); + if (currentName == "bind_vertex_input") { + Collada::InputSemanticMapEntry vn; - // effect semantic - int n = GetAttribute("semantic"); - std::string s = mReader->getAttributeValue(n); - - // input semantic - n = GetAttribute("input_semantic"); - vn.mType = GetTypeForSemantic(mReader->getAttributeValue(n)); - - // index of input set - n = TestAttribute("input_set"); - if (-1 != n) - vn.mSet = mReader->getAttributeValueAsInt(n); - - tbl.mMap[s] = vn; - } else if (IsElement("bind")) { - ASSIMP_LOG_WARN("Collada: Found unsupported element"); + // effect semantic + if (XmlParser::hasAttribute(currentNode, "semantic")) { + std::string s; + XmlParser::getStdStrAttribute(currentNode, "semantic", s); + XmlParser::getUIntAttribute(currentNode, "input_semantic", (unsigned int &)vn.mType); } - } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { - if (strcmp(mReader->getNodeName(), "instance_material") == 0) - break; + std::string s; + XmlParser::getStdStrAttribute(currentNode, "semantic", s); + + // input semantic + XmlParser::getUIntAttribute(currentNode, "input_semantic", (unsigned int &)vn.mType); + + // index of input set + if (XmlParser::hasAttribute(currentNode, "input_set")) { + XmlParser::getUIntAttribute(currentNode, "input_set", vn.mSet); + } + + tbl.mMap[s] = vn; + } else if (currentName == "bind") { + ASSIMP_LOG_WARN("Collada: Found unsupported element"); } } } @@ -2270,41 +2234,31 @@ void ColladaParser::ReadEmbeddedTextures(ZipArchiveIOSystem &zip_archive) { // Reads a mesh reference in a node and adds it to the node's mesh list void ColladaParser::ReadNodeGeometry(XmlNode &node, Node *pNode) { // referred mesh is given as an attribute of the element - int attrUrl = GetAttribute("url"); - const char *url = mReader->getAttributeValue(attrUrl); + std::string url; + XmlParser::getStdStrAttribute(node, "url", url); if (url[0] != '#') ThrowException("Unknown reference format"); Collada::MeshInstance instance; - instance.mMeshOrController = url + 1; // skipping the leading # + instance.mMeshOrController = url.c_str() + 1; // skipping the leading # - if (!mReader->isEmptyElement()) { - // read material associations. Ignore additional elements in between - while (mReader->read()) { - if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { - if (IsElement("instance_material")) { - // read ID of the geometry subgroup and the target material - int attrGroup = GetAttribute("symbol"); - std::string group = mReader->getAttributeValue(attrGroup); - int attrMaterial = GetAttribute("target"); - const char *urlMat = mReader->getAttributeValue(attrMaterial); - Collada::SemanticMappingTable s; - if (urlMat[0] == '#') - urlMat++; + for (XmlNode ¤tNode : node.children()) { + const std::string ¤tName = currentNode.name(); + if (currentName=="instance_material") { + // read ID of the geometry subgroup and the target material + std::string group; + XmlParser::getStdStrAttribute(currentNode, "symbol", group); + XmlParser::getStdStrAttribute(currentNode, "symbol", url); + const char *urlMat = url.c_str(); + Collada::SemanticMappingTable s; + if (urlMat[0] == '#') + urlMat++; - s.mMatName = urlMat; + s.mMatName = urlMat; - // resolve further material details + THIS UGLY AND NASTY semantic mapping stuff - if (!mReader->isEmptyElement()) - ReadMaterialVertexInputBinding(s); - // store the association - instance.mMaterials[group] = s; - } - } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { - if (strcmp(mReader->getNodeName(), "instance_geometry") == 0 || strcmp(mReader->getNodeName(), "instance_controller") == 0) - break; - } + // store the association + instance.mMaterials[group] = s; } } @@ -2318,8 +2272,6 @@ void ColladaParser::ReadScene(XmlNode &node) { if (node.empty()) { return; } - /*if (mReader->isEmptyElement()) - return;*/ for (XmlNode currentNode : node.children()) { const std::string currentName = currentNode.name(); @@ -2329,46 +2281,20 @@ void ColladaParser::ReadScene(XmlNode &node) { ThrowException("Invalid scene containing multiple root nodes in element"); // read the url of the scene to instance. Should be of format "#some_name" - int urlIndex = currentNode.attribute("url").as_int(); - const char *url = currentNode.attributes.begin() + urlIndex; + std::string url; + XmlParser::getStdStrAttribute(currentNode, "url", url); if (url[0] != '#') { ThrowException("Unknown reference format in element"); } // find the referred scene, skip the leading # - NodeLibrary::const_iterator sit = mNodeLibrary.find(url + 1); + NodeLibrary::const_iterator sit = mNodeLibrary.find(url.c_str() + 1); if (sit == mNodeLibrary.end()) { ThrowException("Unable to resolve visual_scene reference \"" + std::string(url) + "\" in element."); } mRootNode = sit->second; } } - - /*while (mReader->read()) { - if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { - if (IsElement("instance_visual_scene")) { - // should be the first and only occurrence - if (mRootNode) - ThrowException("Invalid scene containing multiple root nodes in element"); - - // read the url of the scene to instance. Should be of format "#some_name" - int urlIndex = GetAttribute("url"); - const char *url = mReader->getAttributeValue(urlIndex); - if (url[0] != '#') - ThrowException("Unknown reference format in element"); - - // find the referred scene, skip the leading # - NodeLibrary::const_iterator sit = mNodeLibrary.find(url + 1); - if (sit == mNodeLibrary.end()) - ThrowException("Unable to resolve visual_scene reference \"" + std::string(url) + "\" in element."); - mRootNode = sit->second; - } else { - SkipElement(); - } - } else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { - break; - } - }*/ } // ------------------------------------------------------------------------------------------------ @@ -2391,136 +2317,6 @@ void ColladaParser::ReportWarning(const char *msg, ...) { ASSIMP_LOG_WARN_F("Validation warning: ", std::string(szBuffer, iLen)); } -// ------------------------------------------------------------------------------------------------ -// Skips all data until the end node of the current element -/*void ColladaParser::SkipElement() { - // nothing to skip if it's an - if (mReader->isEmptyElement()) { - return; - } - - // reroute - SkipElement(mReader->getNodeName()); -}*/ - -// ------------------------------------------------------------------------------------------------ -// Skips all data until the end node of the given element -/*void ColladaParser::SkipElement(const char *pElement) { - // copy the current node's name because it'a pointer to the reader's internal buffer, - // which is going to change with the upcoming parsing - std::string element = pElement; - while (mReader->read()) { - if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { - if (mReader->getNodeName() == element) { - break; - } - } - } -}*/ - -// ------------------------------------------------------------------------------------------------ -// Tests for an opening element of the given name, throws an exception if not found -/*void ColladaParser::TestOpening(const char *pName) { - // read element start - if (!mReader->read()) { - ThrowException(format() << "Unexpected end of file while beginning of <" << pName << "> element."); - } - // whitespace in front is ok, just read again if found - if (mReader->getNodeType() == irr::io::EXN_TEXT) { - if (!mReader->read()) { - ThrowException(format() << "Unexpected end of file while reading beginning of <" << pName << "> element."); - } - } - - if (mReader->getNodeType() != irr::io::EXN_ELEMENT || strcmp(mReader->getNodeName(), pName) != 0) { - ThrowException(format() << "Expected start of <" << pName << "> element."); - } -}*/ - -// ------------------------------------------------------------------------------------------------ -// Tests for the closing tag of the given element, throws an exception if not found -/*void ColladaParser::TestClosing(const char *pName) { - // check if we have an empty (self-closing) element - if (mReader->isEmptyElement()) { - return; - } - - // check if we're already on the closing tag and return right away - if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END && strcmp(mReader->getNodeName(), pName) == 0) { - return; - } - - // if not, read some more - if (!mReader->read()) { - ThrowException(format() << "Unexpected end of file while reading end of <" << pName << "> element."); - } - // whitespace in front is ok, just read again if found - if (mReader->getNodeType() == irr::io::EXN_TEXT) { - if (!mReader->read()) { - ThrowException(format() << "Unexpected end of file while reading end of <" << pName << "> element."); - } - } - - // but this has the be the closing tag, or we're lost - if (mReader->getNodeType() != irr::io::EXN_ELEMENT_END || strcmp(mReader->getNodeName(), pName) != 0) { - ThrowException(format() << "Expected end of <" << pName << "> element."); - } -}*/ - -// ------------------------------------------------------------------------------------------------ -// Returns the index of the named attribute or -1 if not found. Does not throw, therefore useful for optional attributes -/*int ColladaParser::GetAttribute(const char *pAttr) const { - int index = TestAttribute(pAttr); - if (index == -1) { - ThrowException(format() << "Expected attribute \"" << pAttr << "\" for element <" << mReader->getNodeName() << ">."); - } - - // attribute not found -> throw an exception - return index; -}*/ - -// ------------------------------------------------------------------------------------------------ -// Tests the present element for the presence of one attribute, returns its index or throws an exception if not found -/*int ColladaParser::TestAttribute(const char *pAttr) const { - for (int a = 0; a < mReader->getAttributeCount(); a++) - if (strcmp(mReader->getAttributeName(a), pAttr) == 0) - return a; - - return -1; -}*/ - -// ------------------------------------------------------------------------------------------------ -// Reads the text contents of an element, throws an exception if not given. Skips leading whitespace. -/*const char *ColladaParser::GetTextContent() { - const char *sz = TestTextContent(); - if (!sz) { - ThrowException("Invalid contents in element \"n\"."); - } - return sz; -}*/ - -// ------------------------------------------------------------------------------------------------ -// Reads the text contents of an element, returns nullptr if not given. Skips leading whitespace. -/*const char *ColladaParser::TestTextContent() { - // present node should be the beginning of an element - if (mReader->getNodeType() != irr::io::EXN_ELEMENT || mReader->isEmptyElement()) - return nullptr; - - // read contents of the element - if (!mReader->read()) { - return nullptr; - } - if (mReader->getNodeType() != irr::io::EXN_TEXT && mReader->getNodeType() != irr::io::EXN_CDATA) { - return nullptr; - } - - // skip leading whitespace - const char *text = mReader->getNodeData(); - SkipSpacesAndLineEnd(&text); - - return text; -}*/ - // ------------------------------------------------------------------------------------------------ // Calculates the resulting transformation from all the given transform steps aiMatrix4x4 ColladaParser::CalculateResultTransform(const std::vector &pTransforms) const { diff --git a/code/AssetLib/Collada/ColladaParser.h b/code/AssetLib/Collada/ColladaParser.h index e5b1e5971..40b4df054 100644 --- a/code/AssetLib/Collada/ColladaParser.h +++ b/code/AssetLib/Collada/ColladaParser.h @@ -247,43 +247,6 @@ protected: AI_WONT_RETURN void ThrowException(const std::string &pError) const AI_WONT_RETURN_SUFFIX; void ReportWarning(const char *msg, ...); - /** Skips all data until the end node of the current element */ - //void SkipElement(); - - /** Skips all data until the end node of the given element */ - //void SkipElement(const char *pElement); - - /** Compares the current xml element name to the given string and returns true if equal */ - bool IsElement(const char *pName) const; - - /** Tests for the opening tag of the given element, throws an exception if not found */ - //void TestOpening(const char *pName); - - /** Tests for the closing tag of the given element, throws an exception if not found */ - //void TestClosing(const char *pName); - - /** Checks the present element for the presence of the attribute, returns its index - or throws an exception if not found */ - int GetAttribute(const char *pAttr) const; - - /** Returns the index of the named attribute or -1 if not found. Does not throw, - therefore useful for optional attributes */ - int TestAttribute(const char *pAttr) const; - - /** Reads the text contents of an element, throws an exception if not given. - Skips leading whitespace. */ - const char *GetTextContent(); - - /** Reads the text contents of an element, returns nullptr if not given. - Skips leading whitespace. */ - const char *TestTextContent(); - - /** Reads a single bool from current text content */ - bool ReadBoolFromTextContent(); - - /** Reads a single float from current text content */ - ai_real ReadFloatFromTextContent(); - /** Calculates the resulting transformation from all the given transform steps */ aiMatrix4x4 CalculateResultTransform(const std::vector &pTransforms) const; diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 0c889a94d..8e457802d 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -1146,9 +1146,10 @@ IF(ASSIMP_HUNTER_ENABLED) RapidJSON::rapidjson utf8::utf8 zip::zip + pugixml::pugixml ) ELSE() - TARGET_LINK_LIBRARIES(assimp ${ZLIB_LIBRARIES} ${OPENDDL_PARSER_LIBRARIES} ${IRRXML_LIBRARY} ) + TARGET_LINK_LIBRARIES(assimp ${ZLIB_LIBRARIES} ${OPENDDL_PARSER_LIBRARIES} pugixml ) ENDIF() if(ASSIMP_ANDROID_JNIIOSYSTEM) diff --git a/include/assimp/XmlParser.h b/include/assimp/XmlParser.h index 7f8145b47..ff04c0d8c 100644 --- a/include/assimp/XmlParser.h +++ b/include/assimp/XmlParser.h @@ -199,6 +199,17 @@ public: return true; } + static inline bool getBoolAttribute( XmlNode &xmlNode, const char *name, bool &val ) { + pugi::xml_attribute attr = xmlNode.attribute(name); + if (attr.empty()) { + return false; + } + + val = attr.as_bool(); + return true; + + } + private: pugi::xml_document *mDoc; TNodeType *mRoot;