From 0730eebe6fa3276fd217c40c57eb1a5a577209ca Mon Sep 17 00:00:00 2001 From: kimkulling Date: Fri, 28 Aug 2020 16:17:56 +0200 Subject: [PATCH] fix collada handling of xml nodes. --- code/AssetLib/3MF/D3MFImporter.cpp | 19 ++--- code/AssetLib/3MF/D3MFOpcPackage.cpp | 9 ++- code/AssetLib/Collada/ColladaParser.cpp | 95 +++++++++++++------------ code/Common/DefaultIOSystem.cpp | 2 - test/unit/ut3DImportExport.cpp | 2 - test/unit/utIssues.cpp | 3 +- 6 files changed, 61 insertions(+), 69 deletions(-) diff --git a/code/AssetLib/3MF/D3MFImporter.cpp b/code/AssetLib/3MF/D3MFImporter.cpp index cbb2d4a27..ba7a64342 100644 --- a/code/AssetLib/3MF/D3MFImporter.cpp +++ b/code/AssetLib/3MF/D3MFImporter.cpp @@ -93,8 +93,9 @@ public: std::vector children; std::string nodeName; - XmlNode *root = mXmlParser->getRootNode(); - for (XmlNode ¤tNode : root->children()) { + XmlNode node = *mXmlParser->getRootNode(); + + for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { const std::string ¤tNodeName = currentNode.name(); if (currentNodeName == D3MF::XmlTag::object) { children.push_back(ReadObject(currentNode, scene)); @@ -160,7 +161,7 @@ private: size_t meshIdx = mMeshes.size(); - for (pugi::xml_node ¤tNode : node.children()) { + for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { const std::string ¤tName = currentNode.name(); if (currentName == D3MF::XmlTag::mesh) { auto mesh = ReadMesh(currentNode); @@ -182,7 +183,7 @@ private: aiMesh *ReadMesh(XmlNode &node) { aiMesh *mesh = new aiMesh(); - for (pugi::xml_node ¤tNode : node.children()) { + for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { const std::string ¤tName = currentNode.name(); if (currentName == D3MF::XmlTag::vertices) { ImportVertices(currentNode, mesh); @@ -211,7 +212,7 @@ private: void ImportVertices(XmlNode &node, aiMesh *mesh) { std::vector vertices; - for (pugi::xml_node ¤tNode : node.children()) { + for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { const std::string ¤tName = currentNode.name(); if (currentName == D3MF::XmlTag::vertex) { vertices.push_back(ReadVertex(currentNode)); @@ -234,7 +235,7 @@ private: void ImportTriangles(XmlNode &node, aiMesh *mesh) { std::vector faces; - for (pugi::xml_node ¤tNode : node.children()) { + for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { const std::string ¤tName = currentNode.name(); if (currentName == D3MF::XmlTag::triangle) { faces.push_back(ReadTriangle(currentNode)); @@ -337,7 +338,6 @@ private: void assignDiffuseColor(XmlNode &node, aiMaterial *mat) { const char *color = node.attribute(D3MF::XmlTag::basematerials_displaycolor.c_str()).as_string(); - //const char *color = xmlReader->getAttributeValue(D3MF::XmlTag::basematerials_displaycolor.c_str()); aiColor4D diffuse; if (parseColor(color, diffuse)) { mat->AddProperty(&diffuse, 1, AI_MATKEY_COLOR_DIFFUSE); @@ -348,10 +348,8 @@ private: aiMaterial *mat(nullptr); const char *name(nullptr); const std::string nodeName = node.name(); - //const std::string nodeName(xmlReader->getNodeName()); if (nodeName == D3MF::XmlTag::basematerials_base) { name = node.attribute(D3MF::XmlTag::basematerials_name.c_str()).as_string(); - //name = xmlReader->getAttributeValue(D3MF::XmlTag::basematerials_name.c_str()); std::string stdMatName; aiString matName; std::string strId(to_string(mActiveMatGroup)); @@ -440,9 +438,6 @@ const aiImporterDesc *D3MFImporter::GetInfo() const { void D3MFImporter::InternReadFile(const std::string &filename, aiScene *pScene, IOSystem *pIOHandler) { D3MF::D3MFOpcPackage opcPackage(pIOHandler, filename); - //std::unique_ptr xmlStream(new CIrrXML_IOStreamReader(opcPackage.RootStream())); - //std::unique_ptr xmlReader(irr::io::createIrrXMLReader(xmlStream.get())); - XmlParser xmlParser; if (xmlParser.parse(opcPackage.RootStream())) { D3MF::XmlSerializer xmlSerializer(&xmlParser); diff --git a/code/AssetLib/3MF/D3MFOpcPackage.cpp b/code/AssetLib/3MF/D3MFOpcPackage.cpp index d9508603e..4c2c70799 100644 --- a/code/AssetLib/3MF/D3MFOpcPackage.cpp +++ b/code/AssetLib/3MF/D3MFOpcPackage.cpp @@ -71,16 +71,15 @@ public: OpcPackageRelationshipReader(XmlParser &parser) { XmlNode *root = parser.getRootNode(); if (nullptr != root) { - ParseRootNode(*root); + XmlNode node = * root; + ParseRootNode(node); } } void ParseRootNode(XmlNode &node) { ParseAttributes(node); - - for (XmlNode currentNode : node.children()) { + for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { ParseChildNode(currentNode); - } } @@ -97,7 +96,7 @@ public: void ParseChildNode(XmlNode &node) { OpcPackageRelationshipPtr relPtr(new OpcPackageRelationship()); - + std::string name = node.name(); relPtr->id = node.attribute(XmlTag::RELS_ATTRIB_ID.c_str()).as_string(); relPtr->type = node.attribute(XmlTag::RELS_ATTRIB_TYPE.c_str()).as_string(); relPtr->target = node.attribute(XmlTag::RELS_ATTRIB_TARGET.c_str()).as_string(); diff --git a/code/AssetLib/Collada/ColladaParser.cpp b/code/AssetLib/Collada/ColladaParser.cpp index de2e92d4e..7b30f4c3e 100644 --- a/code/AssetLib/Collada/ColladaParser.cpp +++ b/code/AssetLib/Collada/ColladaParser.cpp @@ -121,18 +121,20 @@ ColladaParser::ColladaParser(IOSystem *pIOHandler, const std::string &pFile) : if (nullptr == rootPtr) { ThrowException("Unable to read file, malformed XML"); } - bool res = rootPtr->empty(); - if (!res) { - XmlNode node = *rootPtr; - for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { +// bool res = rootPtr->empty(); + //if (!res) { + //XmlNode node = *rootPtr; + /*for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { const std::string nm = currentNode.name(); - } + }*/ //XmlNode node = root->first_child(); //std::string name = node.name(); - } + //} // start reading - ReadContents(*rootPtr); + XmlNode node = *rootPtr; + std::string name = rootPtr->name(); + ReadContents(node); // read embedded textures if (zip_archive && zip_archive->isOpen()) { @@ -234,9 +236,10 @@ void ColladaParser::UriDecodePath(aiString &ss) { // ------------------------------------------------------------------------------------------------ // Reads the contents of the file void ColladaParser::ReadContents(XmlNode &node) { - for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + const std::string name = node.name(); + if (name == "COLLADA") { std::string version; - if (XmlParser::getStdStrAttribute(currentNode, "version", version)) { + if (XmlParser::getStdStrAttribute(node, "version", version)) { aiString v; v.Set(version.c_str()); mAssetMetaData.emplace(AI_METADATA_SOURCE_FORMAT_VERSION, v); @@ -251,7 +254,7 @@ void ColladaParser::ReadContents(XmlNode &node) { ASSIMP_LOG_DEBUG("Collada schema version is 1.3.n"); } } - ReadStructure(currentNode); + ReadStructure(node); } } @@ -496,8 +499,8 @@ void ColladaParser::ReadAnimation(XmlNode &node, Collada::Animation *pParent) { animID = idAttr.as_string(); } - for (XmlNode ¤tNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { - const std::string currentName = curNode.name(); + for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + const std::string currentName = currentNode.name(); if (currentName == "animation") { if (!anim) { anim = new Animation; @@ -506,20 +509,20 @@ void ColladaParser::ReadAnimation(XmlNode &node, Collada::Animation *pParent) { } // recurse into the sub-element - ReadAnimation(curNode, anim); + ReadAnimation(currentNode, anim); } else if (currentName == "source") { - ReadSource(curNode); + ReadSource(currentNode); } else if (currentName == "sampler") { - pugi::xml_attribute sampler_id = curNode.attribute("id"); + pugi::xml_attribute sampler_id = currentNode.attribute("id"); if (sampler_id) { std::string id = sampler_id.as_string(); ChannelMap::iterator newChannel = channels.insert(std::make_pair(id, AnimationChannel())).first; // have it read into a channel - ReadAnimationSampler(curNode, newChannel->second); + ReadAnimationSampler(currentNode, newChannel->second); } else if (currentName == "channel") { - pugi::xml_attribute target = curNode.attribute("target"); - pugi::xml_attribute source = curNode.attribute("source"); + pugi::xml_attribute target = currentNode.attribute("target"); + pugi::xml_attribute source = currentNode.attribute("source"); std::string source_name = source.as_string(); if (source_name[0] == '#') { source_name = source_name.substr(1, source_name.size() - 1); @@ -567,13 +570,13 @@ 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.first_child(); currentNode; currentNode = currentNode.next_sibling()) { - const std::string currentName = curNode.name(); + for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + const std::string currentName = currentNode.name(); if (currentName == "input") { - pugi::xml_attribute semanticAttr = curNode.attribute("semantic"); + pugi::xml_attribute semanticAttr = currentNode.attribute("semantic"); if (!semanticAttr.empty()) { const char *semantic = semanticAttr.as_string(); - pugi::xml_attribute sourceAttr = curNode.attribute("source"); + pugi::xml_attribute sourceAttr = currentNode.attribute("source"); if (!sourceAttr.empty()) { const char *source = sourceAttr.as_string(); if (source[0] != '#') @@ -611,7 +614,7 @@ void ColladaParser::ReadControllerLibrary(XmlNode &node) { int attrId = node.attribute("id").as_int(); std::string id = node.value(); mControllerLibrary[id] = Controller(); - for (XmlNode ¤tNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { const std::string currentName = currentNode.name(); if (currentName == "controller") { attrId = currentNode.attribute("id").as_int(); @@ -627,7 +630,7 @@ void ColladaParser::ReadController(XmlNode &node, Collada::Controller &pControll // initial values pController.mType = Skin; pController.mMethod = Normalized; - for (XmlNode ¤tNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { const std::string ¤tName = currentNode.name(); if (currentName == "morph") { pController.mType = Morph; @@ -656,7 +659,7 @@ void ColladaParser::ReadController(XmlNode &node, Collada::Controller &pControll } else if (currentName == "vertex_weights") { ReadControllerWeights(currentNode, pController); } else if (currentName == "targets") { - for (XmlNode ¤tChildNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + for (XmlNode currentChildNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { const std::string ¤tChildName = currentChildNode.name(); if (currentChildName == "input") { const char *semantics = currentChildNode.attribute("semantic").as_string(); @@ -675,7 +678,7 @@ void ColladaParser::ReadController(XmlNode &node, Collada::Controller &pControll // ------------------------------------------------------------------------------------------------ // Reads the joint definitions for the given controller void ColladaParser::ReadControllerJoints(XmlNode &node, Collada::Controller &pController) { - for (XmlNode ¤tNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { const std::string currentName = currentNode.name(); if (currentName == "input") { const char *attrSemantic = currentNode.attribute("semantic").as_string(); @@ -703,7 +706,7 @@ void ColladaParser::ReadControllerWeights(XmlNode &node, Collada::Controller &pC int vertexCount; XmlParser::getIntAttribute(node, "count", vertexCount); - for (XmlNode ¤tNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { std::string currentName = currentNode.name(); if (currentName == "input") { InputChannel channel; @@ -765,7 +768,7 @@ void ColladaParser::ReadImageLibrary(XmlNode &node) { return; } - for (XmlNode ¤tNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { const std::string name = currentNode.name(); if (name == "image") { std::string id = currentNode.attribute("id").as_string(); @@ -780,7 +783,7 @@ void ColladaParser::ReadImageLibrary(XmlNode &node) { // ------------------------------------------------------------------------------------------------ // Reads an image entry into the given image void ColladaParser::ReadImage(XmlNode &node, Collada::Image &pImage) { - for (XmlNode ¤tNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { const std::string currentName = currentNode.name(); if (currentName == "image") { // Ignore @@ -864,7 +867,7 @@ void ColladaParser::ReadMaterialLibrary(XmlNode &node) { } std::map names; - for (XmlNode ¤tNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { const std::string currentName = currentNode.name(); std::string id = currentNode.attribute("id").as_string(); std::string name = currentNode.attribute("name").as_string(); @@ -894,7 +897,7 @@ void ColladaParser::ReadLightLibrary(XmlNode &node) { return; } - for (XmlNode ¤tNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { const std::string ¤tName = currentNode.name(); if (currentName == "light") { std::string id = currentNode.attribute("id").as_string(); @@ -910,7 +913,7 @@ void ColladaParser::ReadCameraLibrary(XmlNode &node) { return; } - for (XmlNode ¤tNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { const std::string ¤tName = currentNode.name(); if (currentName == "camera") { std::string id = currentNode.attribute("id").as_string(); @@ -929,7 +932,7 @@ 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.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { const std::string ¤tName = currentNode.name(); if (currentName == "material") { const char *url = currentNode.attribute("url").as_string(); @@ -944,7 +947,7 @@ void ColladaParser::ReadMaterial(XmlNode &node, Collada::Material &pMaterial) { // ------------------------------------------------------------------------------------------------ // Reads a light entry into the given light void ColladaParser::ReadLight(XmlNode &node, Collada::Light &pLight) { - for (XmlNode ¤tNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { const std::string ¤tName = currentNode.name(); if (currentName == "spot") { pLight.mType = aiLightSource_SPOT; @@ -1001,7 +1004,7 @@ void ColladaParser::ReadLight(XmlNode &node, Collada::Light &pLight) { // ------------------------------------------------------------------------------------------------ // Reads a camera entry into the given light void ColladaParser::ReadCamera(XmlNode &node, Collada::Camera &camera) { - for (XmlNode ¤tNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { const std::string ¤tName = currentNode.name(); if (currentName == "orthographic") { camera.mOrtho = true; @@ -1026,12 +1029,12 @@ void ColladaParser::ReadEffectLibrary(XmlNode &node) { return; } - for (XmlNode ¤tNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { const std::string ¤tName = currentNode.name(); if (currentName == "effect") { + // read ID. Do I have to repeat my ranting about "optional" attributes? std::string id; XmlParser::getStdStrAttribute(currentNode, "id", id); - // read ID. Do I have to repeat my ranting about "optional" attributes? // create an entry and store it in the library under its ID mEffectLibrary[id] = Effect(); @@ -1153,7 +1156,7 @@ void ColladaParser::ReadSamplerProperties(XmlNode &node, Sampler &out) { if (node.empty()) { return; } - for (XmlNode ¤tNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { const std::string ¤tName = currentNode.name(); // MAYA extensions // ------------------------------------------------------- @@ -1212,7 +1215,7 @@ void ColladaParser::ReadEffectColor(XmlNode &node, aiColor4D &pColor, Sampler &p return; } - for (XmlNode ¤tNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { const std::string ¤tName = currentNode.name(); if (currentName == "color") { // text content contains 4 floats @@ -1332,7 +1335,7 @@ void ColladaParser::ReadGeometry(XmlNode &node, Collada::Mesh &pMesh) { if (node.empty()) { return; } - for (XmlNode ¤tNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { const std::string ¤tName = currentNode.name(); if (currentName == "mesh") { ReadMesh(currentNode, pMesh); @@ -1531,7 +1534,7 @@ void ColladaParser::ReadAccessor(XmlNode &node, const std::string &pID) { void ColladaParser::ReadVertexData(XmlNode &node, Mesh &pMesh) { // extract the ID of the element. Not that we care, but to catch strange referencing schemes we should warn about XmlParser::getStdStrAttribute(node, "id", pMesh.mVertexID); - for (XmlNode ¤tNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { const std::string ¤tName = currentNode.name(); if (currentName == "input") { ReadInputChannel(currentNode, pMesh.mPerVertexData); @@ -1981,21 +1984,19 @@ void ColladaParser::ReadSceneLibrary(XmlNode &node) { if (node.empty()) { return; } - /*if (mReader->isEmptyElement()) - return;*/ - for (XmlNode ¤tNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { 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); + // read name if given. std::string attrName = "Scene"; if (XmlParser::hasAttribute(currentNode, "name")) { XmlParser::getStdStrAttribute(currentNode, "name", attrName); } - // read name if given. // create a node and store it in the library under its ID Node *sceneNode = new Node; @@ -2016,7 +2017,7 @@ void ColladaParser::ReadSceneNode(XmlNode &node, Node *pNode) { return; } - for (XmlNode ¤tNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { const std::string ¤tName = currentNode.name(); if (currentName == "node") { Node *child = new Node; @@ -2208,7 +2209,7 @@ void ColladaParser::ReadNodeGeometry(XmlNode &node, Node *pNode) { Collada::MeshInstance instance; instance.mMeshOrController = url.c_str() + 1; // skipping the leading # - for (XmlNode ¤tNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { + for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) { const std::string ¤tName = currentNode.name(); if (currentName == "instance_material") { // read ID of the geometry subgroup and the target material diff --git a/code/Common/DefaultIOSystem.cpp b/code/Common/DefaultIOSystem.cpp index 31e76bdc9..2512e57c8 100644 --- a/code/Common/DefaultIOSystem.cpp +++ b/code/Common/DefaultIOSystem.cpp @@ -5,8 +5,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2020, assimp team - - All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/test/unit/ut3DImportExport.cpp b/test/unit/ut3DImportExport.cpp index f77c4181e..17117d706 100644 --- a/test/unit/ut3DImportExport.cpp +++ b/test/unit/ut3DImportExport.cpp @@ -44,10 +44,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include - using namespace Assimp; - TEST(ut3DImportExport, importBoxA) { Assimp::Importer importer; const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/3D/box_a.3d", aiProcess_ValidateDataStructure); diff --git a/test/unit/utIssues.cpp b/test/unit/utIssues.cpp index 19d1815cb..2083c15b1 100644 --- a/test/unit/utIssues.cpp +++ b/test/unit/utIssues.cpp @@ -66,10 +66,11 @@ TEST_F( utIssues, OpacityBugWhenExporting_727 ) { std::string path = "dae"; const aiExportFormatDesc *desc( exporter.GetExportFormatDescription( 0 ) ); EXPECT_NE( desc, nullptr ); + path.append("."); path.append( desc->fileExtension ); EXPECT_EQ( AI_SUCCESS, exporter.Export( scene, desc->id, path ) ); const aiScene *newScene( importer.ReadFile( path, aiProcess_ValidateDataStructure ) ); - EXPECT_TRUE( NULL != newScene ); + ASSERT_NE( nullptr, newScene ); float newOpacity; if ( newScene->mNumMaterials > 0 ) { std::cout << "Desc = " << desc->description << "\n";