diff --git a/code/AssetLib/LWO/LWOLoader.cpp b/code/AssetLib/LWO/LWOLoader.cpp index 96fed248b..1bf39b2da 100644 --- a/code/AssetLib/LWO/LWOLoader.cpp +++ b/code/AssetLib/LWO/LWOLoader.cpp @@ -178,7 +178,7 @@ void LWOImporter::InternReadFile(const std::string &pFile, mLayers->push_back(Layer()); mCurLayer = &mLayers->back(); mCurLayer->mName = ""; - mCurLayer->mIndex = (uint16_t) -1; + mCurLayer->mIndex = 1; // old lightwave file format (prior to v6) mIsLWO2 = false; @@ -398,14 +398,6 @@ void LWOImporter::InternReadFile(const std::string &pFile, pvVC[w]++; } -#if 0 - // process vertex weights. We can't properly reconstruct the whole skeleton for now, - // but we can create dummy bones for all weight channels which we have. - for (unsigned int w = 0; w < layer.mWeightChannels.size();++w) - { - } -#endif - face.mIndices[q] = vert; } pf->mIndices = face.mIndices; @@ -429,7 +421,7 @@ void LWOImporter::InternReadFile(const std::string &pFile, // Generate nodes to render the mesh. Store the source layer in the mParent member of the nodes unsigned int num = static_cast(apcMeshes.size() - meshStart); if (layer.mName != "" || num > 0) { - aiNode *pcNode = new aiNode(); + std::unique_ptr pcNode(new aiNode()); pcNode->mName.Set(layer.mName); pcNode->mParent = (aiNode *)&layer; pcNode->mNumMeshes = num; @@ -439,7 +431,8 @@ void LWOImporter::InternReadFile(const std::string &pFile, for (unsigned int p = 0; p < pcNode->mNumMeshes; ++p) pcNode->mMeshes[p] = p + meshStart; } - apcNodes[layer.mIndex] = pcNode; + ASSIMP_LOG_DEBUG("insert apcNode for layer ", layer.mIndex, " \"", layer.mName, "\""); + apcNodes[layer.mIndex] = pcNode.release(); } } @@ -572,40 +565,64 @@ void LWOImporter::GenerateNodeGraph(std::map &apcNodes) { aiNode *root = mScene->mRootNode = new aiNode(); root->mName.Set(""); - //Set parent of all children, inserting pivots - std::map mapPivot; - for (auto itapcNodes = apcNodes.begin(); itapcNodes != apcNodes.end(); ++itapcNodes) { - - //Get the parent index - LWO::Layer *nodeLayer = (LWO::Layer *)(itapcNodes->second->mParent); - uint16_t parentIndex = nodeLayer->mParent; - - //Create pivot node, store it into the pivot map, and set the parent as the pivot - aiNode *pivotNode = new aiNode(); - pivotNode->mName.Set("Pivot-" + std::string(itapcNodes->second->mName.data)); - itapcNodes->second->mParent = pivotNode; - - //Look for the parent node to attach the pivot to - if (apcNodes.find(parentIndex) != apcNodes.end()) { - pivotNode->mParent = apcNodes[parentIndex]; - } else { - //If not, attach to the root node - pivotNode->mParent = root; - } - - //Set the node and the pivot node transformation - itapcNodes->second->mTransformation.a4 = -nodeLayer->mPivot.x; - itapcNodes->second->mTransformation.b4 = -nodeLayer->mPivot.y; - itapcNodes->second->mTransformation.c4 = -nodeLayer->mPivot.z; - pivotNode->mTransformation.a4 = nodeLayer->mPivot.x; - pivotNode->mTransformation.b4 = nodeLayer->mPivot.y; - pivotNode->mTransformation.c4 = nodeLayer->mPivot.z; - mapPivot[-(itapcNodes->first + 2)] = pivotNode; + ASSIMP_LOG_DEBUG("apcNodes initial size: ", apcNodes.size()); + if (!apcNodes.empty()) { + ASSIMP_LOG_DEBUG("first apcNode is: ", apcNodes.begin()->first, " \"", apcNodes.begin()->second->mName.C_Str(), "\""); } - //Merge pivot map into node map - for (auto itMapPivot = mapPivot.begin(); itMapPivot != mapPivot.end(); ++itMapPivot) { - apcNodes[itMapPivot->first] = itMapPivot->second; + //Set parent of all children, inserting pivots + { + std::map mapPivot; + for (auto itapcNodes = apcNodes.begin(); itapcNodes != apcNodes.end(); ++itapcNodes) { + + //Get the parent index + LWO::Layer *nodeLayer = (LWO::Layer *)(itapcNodes->second->mParent); + uint16_t parentIndex = nodeLayer->mParent; + + //Create pivot node, store it into the pivot map, and set the parent as the pivot + std::unique_ptr pivotNode(new aiNode()); + pivotNode->mName.Set("Pivot-" + std::string(itapcNodes->second->mName.data)); + itapcNodes->second->mParent = pivotNode.get(); + + //Look for the parent node to attach the pivot to + if (apcNodes.find(parentIndex) != apcNodes.end()) { + pivotNode->mParent = apcNodes[parentIndex]; + } else { + //If not, attach to the root node + pivotNode->mParent = root; + } + + //Set the node and the pivot node transformation + itapcNodes->second->mTransformation.a4 = -nodeLayer->mPivot.x; + itapcNodes->second->mTransformation.b4 = -nodeLayer->mPivot.y; + itapcNodes->second->mTransformation.c4 = -nodeLayer->mPivot.z; + pivotNode->mTransformation.a4 = nodeLayer->mPivot.x; + pivotNode->mTransformation.b4 = nodeLayer->mPivot.y; + pivotNode->mTransformation.c4 = nodeLayer->mPivot.z; + uint16_t pivotNodeId = static_cast(-(itapcNodes->first + 2)); + ASSIMP_LOG_DEBUG("insert pivot node: ", pivotNodeId); + auto oldNodeIt = mapPivot.find(pivotNodeId); + if (oldNodeIt != mapPivot.end()) { + ASSIMP_LOG_ERROR("attempted to insert pivot node which already exists in pivot map ", pivotNodeId, " \"", pivotNode->mName.C_Str(), "\""); + } else { + mapPivot.emplace(pivotNodeId, pivotNode.release()); + } + } + + ASSIMP_LOG_DEBUG("pivot nodes: ", mapPivot.size()); + //Merge pivot map into node map + for (auto itMapPivot = mapPivot.begin(); itMapPivot != mapPivot.end();) { + uint16_t pivotNodeId = itMapPivot->first; + auto oldApcNodeIt = apcNodes.find(pivotNodeId); + if (oldApcNodeIt != apcNodes.end()) { + ASSIMP_LOG_ERROR("attempted to insert pivot node which already exists in apc nodes ", pivotNodeId, " \"", itMapPivot->second->mName.C_Str(), "\""); + } else { + apcNodes.emplace(pivotNodeId, itMapPivot->second); + } + itMapPivot->second = nullptr; + itMapPivot = mapPivot.erase(itMapPivot); + } + ASSIMP_LOG_DEBUG("total nodes: ", apcNodes.size()); } //Set children of all parents @@ -627,8 +644,15 @@ void LWOImporter::GenerateNodeGraph(std::map &apcNodes) { } } - if (!mScene->mRootNode->mNumChildren) + if (!mScene->mRootNode->mNumChildren) { + ASSIMP_LOG_DEBUG("All apcNodes:"); + for (auto nodeIt = apcNodes.begin(); nodeIt != apcNodes.end(); ) { + ASSIMP_LOG_DEBUG("Node ", nodeIt->first, " \"", nodeIt->second->mName.C_Str(), "\""); + nodeIt->second = nullptr; + nodeIt = apcNodes.erase(nodeIt); + } throw DeadlyImportError("LWO: Unable to build a valid node graph"); + } // Remove a single root node with no meshes assigned to it ... if (1 == mScene->mRootNode->mNumChildren) { diff --git a/test/unit/utLWOImportExport.cpp b/test/unit/utLWOImportExport.cpp index 266105030..2ab1c4722 100644 --- a/test/unit/utLWOImportExport.cpp +++ b/test/unit/utLWOImportExport.cpp @@ -75,3 +75,315 @@ TEST_F(utLWOImportExport, importLWOformatdetection) { EXPECT_NE(nullptr, scene); } + + +TEST_F(utLWOImportExport, importLWOempty) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/invalid/empty.lwo", aiProcess_ValidateDataStructure); + + EXPECT_EQ(nullptr, scene); +} + + +TEST_F(utLWOImportExport, importLWObox_2uv_1unused) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/LWO/LWO2/box_2uv_1unused.lwo", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(utLWOImportExport, importLWObox_2vc_1unused) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/LWO/LWO2/box_2vc_1unused.lwo", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(utLWOImportExport, importLWOconcave_polygon) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/LWO/LWO2/concave_polygon.lwo", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(utLWOImportExport, importLWOconcave_self_intersecting) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/LWO/LWO2/concave_self_intersecting.lwo", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(utLWOImportExport, importLWOhierarchy) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/LWO/LWO2/hierarchy.lwo", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(utLWOImportExport, importLWOhierarchy_smoothed) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/LWO/LWO2/hierarchy_smoothed.lwo", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(utLWOImportExport, importLWOearth_cylindrical_x) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/LWO/LWO2/MappingModes/earth_cylindrical_x.lwo", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(utLWOImportExport, importLWOearth_cylindrical_x_scale_222_wrap_21) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/LWO/LWO2/MappingModes/earth_cylindrical_x_scale_222_wrap_21.lwo", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(utLWOImportExport, importLWOearth_cylindrical_y) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/LWO/LWO2/MappingModes/earth_cylindrical_y.lwo", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(utLWOImportExport, importLWOearth_cylindrical_y_scale_111) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/LWO/LWO2/MappingModes/earth_cylindrical_y_scale_111.lwo", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(utLWOImportExport, importLWOearth_cylindrical_y_scale_111_wrap_21) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/LWO/LWO2/MappingModes/earth_cylindrical_y_scale_111_wrap_21.lwo", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(utLWOImportExport, importLWOearth_cylindrical_z) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/LWO/LWO2/MappingModes/earth_cylindrical_z.lwo", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(utLWOImportExport, importLWOearth_planar_x) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/LWO/LWO2/MappingModes/earth_planar_x.lwo", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(utLWOImportExport, importLWOearth_planar_y) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/LWO/LWO2/MappingModes/earth_planar_y.lwo", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(utLWOImportExport, importLWOearth_planar_z) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/LWO/LWO2/MappingModes/earth_planar_z.lwo", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(utLWOImportExport, importLWOearth_planar_z_scale_111) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/LWO/LWO2/MappingModes/earth_planar_z_scale_111.lwo", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(utLWOImportExport, importLWOearth_spherical_x) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/LWO/LWO2/MappingModes/earth_spherical_x.lwo", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(utLWOImportExport, importLWOearth_spherical_x_scale_222_wrap_22) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/LWO/LWO2/MappingModes/earth_spherical_x_scale_222_wrap_22.lwo", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(utLWOImportExport, importLWOearth_spherical_y) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/LWO/LWO2/MappingModes/earth_spherical_y.lwo", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(utLWOImportExport, importLWOearth_spherical_) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/LWO/LWO2/MappingModes/earth_spherical_z.lwo", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(utLWOImportExport, importLWOearth_spherical_z_wrap_22) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/LWO/LWO2/MappingModes/earth_spherical_z_wrap_22.lwo", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(utLWOImportExport, importLWOearth_uv_cylindrical_y) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/LWO/LWO2/MappingModes/earth_uv_cylindrical_y.lwo", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(utLWOImportExport, importLWOModoExport_vertNormals) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/LWO/LWO2/ModoExport_vertNormals.lwo", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(utLWOImportExport, importLWOnonplanar_polygon) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/LWO/LWO2/nonplanar_polygon.lwo", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(utLWOImportExport, importLWOCellShader) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/LWO/LWO2/shader_test/CellShader.lwo", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(utLWOImportExport, importLWOfastFresne) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/LWO/LWO2/shader_test/fastFresnel.lwo", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(utLWOImportExport, importLWOrealFresnel) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/LWO/LWO2/shader_test/realFresnel.lwo", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(utLWOImportExport, importLWOSuperCellShader) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/LWO/LWO2/shader_test/SuperCellShader.lwo", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(utLWOImportExport, importLWOsphere_with_gradient) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/LWO/LWO2/sphere_with_gradient.lwo", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(utLWOImportExport, importLWOsphere_with_mat_gloss_10pc) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/LWO/LWO2/sphere_with_mat_gloss_10pc.lwo", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(utLWOImportExport, importLWOSubdivision) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/LWO/LWO2/Subdivision.lwo", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(utLWOImportExport, importLWOtransparency) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/LWO/LWO2/transparency.lwo", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(utLWOImportExport, importLWOUglyVertexColors) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/LWO/LWO2/UglyVertexColors.lwo", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(utLWOImportExport, importLWOuvtest) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/LWO/LWO2/uvtest.lwo", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(utLWOImportExport, importLWOBConcavePolygon) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/LWO/LWOB/ConcavePolygon.lwo", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(utLWOImportExport, importLWOBbluewithcylindrictex) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/LWO/LWOB/MappingModes/bluewithcylindrictexz.lwo", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(utLWOImportExport, importLWOBsphere_with_mat_gloss_10pc) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/LWO/LWOB/sphere_with_mat_gloss_10pc.lwo", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + + +TEST_F(utLWOImportExport, importLWOBsphere_with_mat_gloss_50pc) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/LWO/LWOB/sphere_with_mat_gloss_50pc.lwo", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +}