diff --git a/code/AssetLib/Assjson/json_exporter.cpp b/code/AssetLib/Assjson/json_exporter.cpp index b9099d392..7b2c8ec81 100644 --- a/code/AssetLib/Assjson/json_exporter.cpp +++ b/code/AssetLib/Assjson/json_exporter.cpp @@ -41,12 +41,17 @@ public: enum { Flag_DoNotIndent = 0x1, Flag_WriteSpecialFloats = 0x2, + Flag_SkipWhitespaces = 0x4 }; - + JSONWriter(Assimp::IOStream &out, unsigned int flags = 0u) : - out(out), first(), flags(flags) { + out(out), indent (""), newline("\n"), space(" "), buff (), first(false), flags(flags) { // make sure that all formatting happens using the standard, C locale and not the user's current locale buff.imbue(std::locale("C")); + if (flags & Flag_SkipWhitespaces) { + newline = ""; + space = ""; + } } ~JSONWriter() { @@ -70,7 +75,7 @@ public: void Key(const std::string &name) { AddIndentation(); Delimit(); - buff << '\"' + name + "\": "; + buff << '\"' + name + "\":" << space; } template @@ -78,12 +83,12 @@ public: AddIndentation(); Delimit(); - LiteralToString(buff, name) << '\n'; + LiteralToString(buff, name) << newline; } template void SimpleValue(const Literal &s) { - LiteralToString(buff, s) << '\n'; + LiteralToString(buff, s) << newline; } void SimpleValue(const void *buffer, size_t len) { @@ -102,7 +107,7 @@ public: } } - buff << '\"' << cur_out << "\"\n"; + buff << '\"' << cur_out << "\"" << newline; delete[] cur_out; } @@ -115,7 +120,7 @@ public: } } first = true; - buff << "{\n"; + buff << "{" << newline; PushIndent(); } @@ -123,7 +128,7 @@ public: PopIndent(); AddIndentation(); first = false; - buff << "}\n"; + buff << "}" << newline; } void StartArray(bool is_element = false) { @@ -135,19 +140,19 @@ public: } } first = true; - buff << "[\n"; + buff << "[" << newline; PushIndent(); } void EndArray() { PopIndent(); AddIndentation(); - buff << "]\n"; + buff << "]" << newline; first = false; } void AddIndentation() { - if (!(flags & Flag_DoNotIndent)) { + if (!(flags & Flag_DoNotIndent) && !(flags & Flag_SkipWhitespaces)) { buff << indent; } } @@ -156,7 +161,7 @@ public: if (!first) { buff << ','; } else { - buff << ' '; + buff << space; first = false; } } @@ -227,7 +232,9 @@ private: private: Assimp::IOStream &out; - std::string indent, newline; + std::string indent; + std::string newline; + std::string space; std::stringstream buff; bool first; @@ -765,7 +772,7 @@ void Write(JSONWriter &out, const aiScene &ai) { out.EndObj(); } -void ExportAssimp2Json(const char *file, Assimp::IOSystem *io, const aiScene *scene, const Assimp::ExportProperties *) { +void ExportAssimp2Json(const char *file, Assimp::IOSystem *io, const aiScene *scene, const Assimp::ExportProperties *pProperties) { std::unique_ptr str(io->Open(file, "wt")); if (!str) { throw DeadlyExportError("could not open output file"); @@ -782,7 +789,12 @@ void ExportAssimp2Json(const char *file, Assimp::IOSystem *io, const aiScene *sc splitter.Execute(scenecopy_tmp); // XXX Flag_WriteSpecialFloats is turned on by default, right now we don't have a configuration interface for exporters - JSONWriter s(*str, JSONWriter::Flag_WriteSpecialFloats); + + unsigned int flags = JSONWriter::Flag_WriteSpecialFloats; + if (pProperties->GetPropertyBool("JSON_SKIP_WHITESPACES", false)) { + flags |= JSONWriter::Flag_SkipWhitespaces; + } + JSONWriter s(*str, flags); Write(s, *scenecopy_tmp); } catch (...) { diff --git a/code/AssetLib/FBX/FBXConverter.cpp b/code/AssetLib/FBX/FBXConverter.cpp index a92745fb6..fa7ee3986 100644 --- a/code/AssetLib/FBX/FBXConverter.cpp +++ b/code/AssetLib/FBX/FBXConverter.cpp @@ -917,8 +917,10 @@ void FBXConverter::ConvertModel(const Model &model, aiNode *parent, aiNode *root } else if (line) { const std::vector &indices = ConvertLine(*line, root_node); std::copy(indices.begin(), indices.end(), std::back_inserter(meshes)); - } else { + } else if (geo) { FBXImporter::LogWarn("ignoring unrecognized geometry: ", geo->Name()); + } else { + FBXImporter::LogWarn("skipping null geometry"); } } diff --git a/code/AssetLib/glTF2/glTF2Importer.cpp b/code/AssetLib/glTF2/glTF2Importer.cpp index 08573bce7..ada7aa046 100644 --- a/code/AssetLib/glTF2/glTF2Importer.cpp +++ b/code/AssetLib/glTF2/glTF2Importer.cpp @@ -1337,6 +1337,17 @@ std::unordered_map GatherSamplers(Animation &an } auto& animsampler = anim.samplers[channel.sampler]; + + if (!animsampler.input) { + ASSIMP_LOG_WARN("Animation ", anim.name, ": Missing sampler input. Skipping."); + continue; + } + + if (!animsampler.output) { + ASSIMP_LOG_WARN("Animation ", anim.name, ": Missing sampler output. Skipping."); + continue; + } + if (animsampler.input->count > animsampler.output->count) { ASSIMP_LOG_WARN("Animation ", anim.name, ": Number of keyframes in sampler input ", animsampler.input->count, " exceeds number of keyframes in sampler output ", animsampler.output->count); continue; diff --git a/code/Common/DefaultIOSystem.cpp b/code/Common/DefaultIOSystem.cpp index 1ed615b84..de93909de 100644 --- a/code/Common/DefaultIOSystem.cpp +++ b/code/Common/DefaultIOSystem.cpp @@ -173,7 +173,7 @@ inline static std::string MakeAbsolutePath(const char *in) { free(ret); } #endif - if (!ret) { + else { // preserve the input path, maybe someone else is able to fix // the path before it is accessed (e.g. our file system filter) ASSIMP_LOG_WARN("Invalid path: ", std::string(in)); diff --git a/code/Common/ScenePreprocessor.cpp b/code/Common/ScenePreprocessor.cpp index 132b32df7..2ea17c643 100644 --- a/code/Common/ScenePreprocessor.cpp +++ b/code/Common/ScenePreprocessor.cpp @@ -89,6 +89,9 @@ void ScenePreprocessor::ProcessScene() { ASSIMP_LOG_DEBUG("ScenePreprocessor: Adding default material \'" AI_DEFAULT_MATERIAL_NAME "\'"); for (unsigned int i = 0; i < scene->mNumMeshes; ++i) { + if (nullptr == scene->mMeshes[i]) { + continue; + } scene->mMeshes[i]->mMaterialIndex = scene->mNumMaterials; } diff --git a/code/Material/MaterialSystem.cpp b/code/Material/MaterialSystem.cpp index c35a1aa93..23d198953 100644 --- a/code/Material/MaterialSystem.cpp +++ b/code/Material/MaterialSystem.cpp @@ -555,17 +555,23 @@ uint32_t Assimp::ComputeMaterialHash(const aiMaterial *mat, bool includeMatName } // ------------------------------------------------------------------------------------------------ -void aiMaterial::CopyPropertyList(aiMaterial *pcDest, +void aiMaterial::CopyPropertyList(aiMaterial *const pcDest, const aiMaterial *pcSrc) { ai_assert(nullptr != pcDest); ai_assert(nullptr != pcSrc); + ai_assert(pcDest->mNumProperties <= pcDest->mNumAllocated); + ai_assert(pcSrc->mNumProperties <= pcSrc->mNumAllocated); - unsigned int iOldNum = pcDest->mNumProperties; + const unsigned int iOldNum = pcDest->mNumProperties; pcDest->mNumAllocated += pcSrc->mNumAllocated; pcDest->mNumProperties += pcSrc->mNumProperties; + const unsigned int numAllocated = pcDest->mNumAllocated; aiMaterialProperty **pcOld = pcDest->mProperties; - pcDest->mProperties = new aiMaterialProperty *[pcDest->mNumAllocated]; + pcDest->mProperties = new aiMaterialProperty *[numAllocated]; + + ai_assert(!iOldNum || pcOld); + ai_assert(iOldNum < numAllocated); if (iOldNum && pcOld) { for (unsigned int i = 0; i < iOldNum; ++i) { diff --git a/code/PostProcessing/OptimizeGraph.cpp b/code/PostProcessing/OptimizeGraph.cpp index e33c2ab18..d7bcf3fec 100644 --- a/code/PostProcessing/OptimizeGraph.cpp +++ b/code/PostProcessing/OptimizeGraph.cpp @@ -170,7 +170,7 @@ void OptimizeGraphProcess::CollectNewChildren(aiNode *nd, std::list &n ++it; } if (join_master && !join.empty()) { - join_master->mName.length = ::ai_snprintf(join_master->mName.data, MAXLEN, "$MergedNode_%i", count_merged++); + join_master->mName.length = ::ai_snprintf(join_master->mName.data, MAXLEN, "$MergedNode_%u", count_merged++); unsigned int out_meshes = 0; for (std::list::const_iterator it = join.cbegin(); it != join.cend(); ++it) { diff --git a/code/PostProcessing/PretransformVertices.cpp b/code/PostProcessing/PretransformVertices.cpp index e9a3af0d2..fa95319ff 100644 --- a/code/PostProcessing/PretransformVertices.cpp +++ b/code/PostProcessing/PretransformVertices.cpp @@ -481,7 +481,7 @@ void PretransformVertices::Execute(aiScene *pScene) { pScene->mMeshes[i]->mNumBones = 0; } } else { - apcOutMeshes.reserve(pScene->mNumMaterials << 1u); + apcOutMeshes.reserve(static_cast(pScene->mNumMaterials) << 1u); std::list aiVFormats; std::vector s(pScene->mNumMeshes, 0); diff --git a/code/PostProcessing/SortByPTypeProcess.cpp b/code/PostProcessing/SortByPTypeProcess.cpp index 20ab63249..3787be51e 100644 --- a/code/PostProcessing/SortByPTypeProcess.cpp +++ b/code/PostProcessing/SortByPTypeProcess.cpp @@ -127,7 +127,7 @@ void SortByPTypeProcess::Execute(aiScene *pScene) { unsigned int aiNumMeshesPerPType[4] = { 0, 0, 0, 0 }; std::vector outMeshes; - outMeshes.reserve(pScene->mNumMeshes << 1u); + outMeshes.reserve(static_cast(pScene->mNumMeshes) << 1u); bool bAnyChanges = false; diff --git a/test/unit/ImportExport/utAssjsonImportExport.cpp b/test/unit/ImportExport/utAssjsonImportExport.cpp index 7987804a9..13724f755 100644 --- a/test/unit/ImportExport/utAssjsonImportExport.cpp +++ b/test/unit/ImportExport/utAssjsonImportExport.cpp @@ -58,7 +58,18 @@ public: Exporter exporter; aiReturn res = exporter.Export(scene, "assjson", "./spider_test.json"); - return aiReturn_SUCCESS == res; + if (aiReturn_SUCCESS != res) { + return false; + } + + Assimp::ExportProperties exportProperties; + exportProperties.SetPropertyBool("JSON_SKIP_WHITESPACES", true); + aiReturn resNoWhitespace = exporter.Export(scene, "assjson", "./spider_test_nowhitespace.json", 0u, &exportProperties); + if (aiReturn_SUCCESS != resNoWhitespace) { + return false; + } + + return true; } };