From ec2a55c535559d1a468925e9f95869ea66bcb9a8 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Sun, 24 May 2026 13:23:46 +0100 Subject: [PATCH] few fixes Only export DSQ if we have a realmesh to pair with it. When looking for the companion shape use the last '_' to strip instead of the first --- .../source/gui/editor/guiShapeEdPreview.cpp | 2 +- Engine/source/ts/assimp/assimpShapeLoader.cpp | 20 ++++- .../source/ts/collada/colladaShapeLoader.cpp | 18 ++++- Engine/source/ts/tsShape.cpp | 80 ++++++++++++++++++- 4 files changed, 113 insertions(+), 7 deletions(-) diff --git a/Engine/source/gui/editor/guiShapeEdPreview.cpp b/Engine/source/gui/editor/guiShapeEdPreview.cpp index d5c0e2b6c..41a17d786 100644 --- a/Engine/source/gui/editor/guiShapeEdPreview.cpp +++ b/Engine/source/gui/editor/guiShapeEdPreview.cpp @@ -410,7 +410,7 @@ bool GuiShapeEdPreview::findCompanionShape(const Torque::Path& dsqPath, Torque:: // AssimpLoader and ColladaLoader exports as "modelname_sequencename.dsq" alongside "modelname.cached.dts" // so strip everything from the last underscore to find the base name String fileName = dsqPath.getFileName(); - String::SizeType sep = fileName.find('_'); + String::SizeType sep = fileName.find('_',0, String::Right); if (sep != String::NPos) { diff --git a/Engine/source/ts/assimp/assimpShapeLoader.cpp b/Engine/source/ts/assimp/assimpShapeLoader.cpp index 5a52d4e44..d0560345a 100644 --- a/Engine/source/ts/assimp/assimpShapeLoader.cpp +++ b/Engine/source/ts/assimp/assimpShapeLoader.cpp @@ -991,7 +991,22 @@ static bool sReadAssimp(const Torque::Path &path, TSShape*& res_shape) if (tss) { TSShapeLoader::updateProgress(TSShapeLoader::Load_Complete, "Import complete"); - Con::printf("[ASSIMP] Shape created successfully."); + + bool realMesh = false; + for (U32 i = 0; i < tss->meshes.size(); ++i) + { + if (tss->meshes[i] && tss->meshes[i]->getMeshType() != TSMesh::NullMeshType) + { + realMesh = true; + break; + } + } + + + if (realMesh) + Con::printf("[ASSIMP] Shape created successfully."); + else + Con::printf("[ASSIMP] Animation created successfully."); Torque::Path cachedPath(path); // Cache the model to a DTS file for faster loading next time. @@ -1004,7 +1019,8 @@ static bool sReadAssimp(const Torque::Path &path, TSShape*& res_shape) tss->write(&dtsStream); } - if (tss->sequences.size() > 0) + // only save dsq if we have a real mesh to pair with it. + if (tss->sequences.size() > 0 && realMesh) { Torque::Path dsqPath(cachedPath); dsqPath.setExtension("dsq"); diff --git a/Engine/source/ts/collada/colladaShapeLoader.cpp b/Engine/source/ts/collada/colladaShapeLoader.cpp index 65ea667aa..b94e5aa11 100644 --- a/Engine/source/ts/collada/colladaShapeLoader.cpp +++ b/Engine/source/ts/collada/colladaShapeLoader.cpp @@ -700,7 +700,21 @@ static bool sReadCollada(const Torque::Path& path, TSShape*& res_shape) if (tss) { TSShapeLoader::updateProgress(TSShapeLoader::Load_Complete, "Import complete"); - Con::printf("[COLLADA] Shape created successfully."); + + bool realMesh = false; + for (U32 i = 0; i < tss->meshes.size(); ++i) + { + if (tss->meshes[i] && tss->meshes[i]->getMeshType() != TSMesh::NullMeshType) + { + realMesh = true; + break; + } + } + + if(realMesh) + Con::printf("[COLLADA] Shape created successfully."); + else + Con::printf("[COLLADA] Animation created successfully."); Torque::Path cachedPath(path); // Cache the model to a DTS file for faster loading next time. @@ -716,7 +730,7 @@ static bool sReadCollada(const Torque::Path& path, TSShape*& res_shape) // Add collada materials to materials.tscript updateMaterialsScript(path, isSketchup); - if (tss->sequences.size() > 0) + if (tss->sequences.size() > 0 && realMesh) { Torque::Path dsqPath(cachedPath); dsqPath.setExtension("dsq"); diff --git a/Engine/source/ts/tsShape.cpp b/Engine/source/ts/tsShape.cpp index 72cc8af52..dc218ad72 100644 --- a/Engine/source/ts/tsShape.cpp +++ b/Engine/source/ts/tsShape.cpp @@ -204,11 +204,11 @@ void TSShape::compressionKey(U8* keyOut, U32 keyLen) } } -void TSShape::xorBufferAtOffset(void* data, U32 byteCount, +void TSShape::xorBufferAtOffset(void* buffer, U32 byteCount, U32 startOffset, const U8* key, U32 keyLen) { - U8* p = (U8*)data; + U8* p = (U8*)buffer; for (U32 i = 0; i < byteCount; ++i) p[i] ^= key[(startOffset + i) % keyLen]; } @@ -2280,6 +2280,82 @@ template<> void *Resource::create(const Torque::Path &path) ret = new TSShape; readSuccess = ret->read(&stream); } + else if (extension.equal("dsq", String::NoCase)) + { + // DSQ is an animation-only file. Try to find a companion shape to load + // sequences into; if none exists, create a minimal empty shape instead. + Torque::Path companionPath(path); + bool foundCompanion = false; + + // Look for basename.cached.dts or basename.dts alongside the DSQ + String fileName = path.getFileName(); + String::SizeType sep = fileName.find('_', 0, String::Right); + if (sep != String::NPos) + { + companionPath.setFileName(fileName.substr(0, sep)); + companionPath.setExtension("cached.dts"); + if (Torque::FS::IsFile(companionPath.getFullPath())) + foundCompanion = true; + + if (!foundCompanion) + { + companionPath.setExtension("dts"); + if (Torque::FS::IsFile(companionPath.getFullPath())) + foundCompanion = true; + } + } + + if (!foundCompanion) + { + companionPath.setFileName(fileName); + companionPath.setExtension("cached.dts"); + if (Torque::FS::IsFile(companionPath.getFullPath())) + foundCompanion = true; + } + + if (!foundCompanion) + { + companionPath.setExtension("dts"); + if (Torque::FS::IsFile(companionPath.getFullPath())) + foundCompanion = true; + } + + if (foundCompanion) + { + FileStream shapeStream; + shapeStream.open(companionPath.getFullPath(), Torque::FS::File::Read); + if (shapeStream.getStatus() == Stream::Ok) + { + ret = new TSShape; + if (!ret->read(&shapeStream)) + { + delete ret; + ret = NULL; + } + } + } + + if (!ret || !foundCompanion) + { + // No companion shape found; build a minimal empty shape so sequences + // have somewhere to live (matches ShapeAnimationAsset's expectations). + ret = new TSShape; + ret->createEmptyShape(); + } + + FileStream dsqStream; + dsqStream.open(path.getFullPath(), Torque::FS::File::Read); + if (dsqStream.getStatus() != Stream::Ok) + { + Con::errorf("Resource::create - Could not open DSQ '%s'", path.getFullPath().c_str()); + delete ret; + return NULL; + } + + readSuccess = ret->importSequences(&dsqStream, path); + if (!readSuccess) + Con::errorf("Resource::create - Failed to import sequences from '%s'", path.getFullPath().c_str()); + } else { const TSShape::ShapeRegistration* regInfo = TSShape::sFindRegInfo(extension);