diff --git a/Engine/source/T3D/assets/assetImporter.cpp b/Engine/source/T3D/assets/assetImporter.cpp index 7abdaeeb5f..bb40a5ccff 100644 --- a/Engine/source/T3D/assets/assetImporter.cpp +++ b/Engine/source/T3D/assets/assetImporter.cpp @@ -2011,7 +2011,7 @@ void AssetImporter::processShapeAsset(AssetImportObject* assetItem) { enumColladaForImport(filePath, shapeInfo, false); } - else if ((fileExt.compare("dts") == 0) || (fileExt.compare("dsq") == 0)) + else if ((fileExt.compare("dts") == 0)) { enumDTSForImport(filePath, shapeInfo); } diff --git a/Engine/source/ts/assimp/assimpShapeLoader.cpp b/Engine/source/ts/assimp/assimpShapeLoader.cpp index 4bcc1df91d..822b1b1b92 100644 --- a/Engine/source/ts/assimp/assimpShapeLoader.cpp +++ b/Engine/source/ts/assimp/assimpShapeLoader.cpp @@ -56,12 +56,13 @@ #undef new #endif #endif -// assimp include files. +// assimp include files. #include #include #include #include #include +#include #include #if !defined(TORQUE_DISABLE_MEMORY_MANAGER) @@ -69,12 +70,75 @@ # define new _new #endif -extern bool gTryUseDSQs; +static bool sReadAssimp(const Torque::Path& path, TSShape*& shape); + +static struct _privateRegisterAssimp +{ + _privateRegisterAssimp() + { + TSShape::ShapeRegistration reg; + + Assimp::Importer importer; + for (U32 i = 0; i < importer.GetImporterCount(); i++) + { + const aiImporterDesc* desc = importer.GetImporterInfo(i); + + String extensions(desc->mFileExtensions); + + Vector tokens; + extensions.split(" ", tokens); + for (U32 t = 0; t < tokens.size(); ++t) + { + const String& ext = tokens[t]; + + if (ext.isEmpty() || + ext.equal("dae", String::NoCase) || // filter out collada importer formats (for now). + ext.equal("zae", String::NoCase) || + ext.equal("xml", String::NoCase) + ) + continue; + + reg.extensions.push_back({ + String(desc->mName), // convert from const char* + ext + }); + } + + } + + Assimp::Exporter exporter; + + for (U32 i = 0; i < exporter.GetExportFormatCount(); ++i) + { + const aiExportFormatDesc* desc = exporter.GetExportFormatDescription(i); + String ext(desc->fileExtension); + + if (ext.isEmpty() || + ext.equal("dae", String::NoCase) || // filter out collada importer formats (for now). + ext.equal("zae", String::NoCase) || + ext.equal("xml", String::NoCase) + ) + continue; + + reg.export_extensions.push_back({ + String(desc->description), + ext + }); + } + + reg.readFunc = sReadAssimp; + reg.writeFunc = NULL; + + TSShape::sRegisterFormat(reg); + } +} sStaticRegisterAssimp; MODULE_BEGIN( AssimpShapeLoader ) MODULE_INIT_AFTER( ShapeLoader ) MODULE_INIT { + // These are only ever used from script. with the TSShapeLoader::isSupportedFormat. + // Handy to have and should probably be a think for the other loaders to register formats. TSShapeLoader::addFormat("DirectX X", "x"); TSShapeLoader::addFormat("Autodesk FBX", "fbx"); TSShapeLoader::addFormat("Blender 3D", "blend" ); @@ -391,54 +455,34 @@ void AssimpShapeLoader::getRootAxisTransform() MatrixF rot(true); - // ===== Y-UP SOURCE ===== - if (upAxis == 1) + // Build source basis + auto axisToVector = [](int axis, int sign) -> Point3F { - if (frontAxis == 2) - { - // Y-up, Z-forward → Z-up, Y-forward - // Rotate 180° Y, then 90° X - rot(0, 0) = -1.0f; - rot(1, 1) = 0.0f; rot(2, 1) = 1.0f; - rot(1, 2) = 1.0f; rot(2, 2) = 0.0f; - } - else if (frontAxis == 0) - { - // Y-up, X-forward → Z-up, Y-forward - // Rotate -90° around Z then 90° around X - rot(0, 0) = 0.0f; rot(0, 1) = -1.0f; - rot(1, 0) = 1.0f; rot(1, 1) = 0.0f; - rot(2, 2) = 1.0f; - } - } + Point3F v(0, 0, 0); + v[axis] = (F32)sign; + return v; + }; - // ===== Z-UP SOURCE ===== - if (upAxis == 2) - { - if (frontAxis == 1) - { - // Already Z-up, Y-forward → no change - } - else if (frontAxis == 0) - { - // Z-up, X-forward → rotate -90° around Z - rot(0, 0) = 0.0f; rot(0, 1) = -1.0f; - rot(1, 0) = 1.0f; rot(1, 1) = 0.0f; - } - } + Point3F forward = axisToVector(frontAxis, frontSign); + Point3F up = axisToVector(upAxis, upSign); + Point3F right = mCross(forward, up); - // ===== X-UP SOURCE ===== - if (upAxis == 0) - { - if (frontAxis == 2) - { - // X-up, Z-forward → Z-up, Y-forward - // Rotate -90° around Y then -90° around Z - rot(0, 0) = 0.0f; rot(0, 1) = 0.0f; rot(0, 2) = -1.0f; - rot(1, 0) = 1.0f; rot(1, 1) = 0.0f; rot(1, 2) = 0.0f; - rot(2, 0) = 0.0f; rot(2, 1) = -1.0f; rot(2, 2) = 0.0f; - } - } + // Recompute forward + forward = mCross(up, right); + + // Normalize (defensive, though they should already be unit) + right.normalize(); + forward.normalize(); + up.normalize(); + + MatrixF srcBasis(true); + srcBasis.setColumn(0, right); + srcBasis.setColumn(1, forward); + srcBasis.setColumn(2, up); + + // Convert to Torque space + rot = srcBasis; + rot.inverse(); ColladaUtils::getOptions().axisCorrectionMat = rot; } @@ -689,30 +733,6 @@ bool AssimpShapeLoader::canLoadCachedDTS(const Torque::Path& path) return false; } -/// Check if an up-to-date cached DSQ is available for this file -bool AssimpShapeLoader::canLoadCachedDSQ(const Torque::Path& path) -{ - // Generate the cached filename - Torque::Path cachedPath(path); - cachedPath.setExtension("dsq"); - - // Check if a cached DTS newer than this file is available - FileTime cachedModifyTime; - if (Platform::getFileTimes(cachedPath.getFullPath(), NULL, &cachedModifyTime)) - { - bool forceLoad = Con::getBoolVariable("$assimp::forceLoad", false); - - FileTime daeModifyTime; - if (!Platform::getFileTimes(path.getFullPath(), NULL, &daeModifyTime) || - (!forceLoad && (Platform::compareFileTimes(cachedModifyTime, daeModifyTime) >= 0))) - { - // Original file not found, or cached DTS is newer - return true; - } - } - return false; -} - void AssimpShapeLoader::assimpLogCallback(const char* message, char* user) { Con::printf("[Assimp log message] %s", StringUnit::getUnit(message, 0, "\n")); @@ -992,65 +1012,12 @@ bool AssimpShapeLoader::getMetaString(const char* key, String& stringVal) } //----------------------------------------------------------------------------- /// This function is invoked by the resource manager based on file extension. -TSShape* assimpLoadShape(const Torque::Path &path) +static bool sReadAssimp(const Torque::Path &path, TSShape*& res_shape) { - // TODO: add .cached.dts generation. - // Generate the cached filename - Torque::Path cachedPath(path); - bool canLoadCached = false; - bool canLoadDSQ = false; - - // Check if an up-to-date cached DTS version of this file exists, and - // if so, use that instead. - if (AssimpShapeLoader::canLoadCachedDTS(path)) - { - cachedPath.setExtension("cached.dts"); - canLoadCached = true; - } - else if (gTryUseDSQs && AssimpShapeLoader::canLoadCachedDSQ(path)) - { - cachedPath.setExtension("dsq"); - canLoadDSQ = true; - } - if (canLoadCached || canLoadDSQ) - { - FileStream cachedStream; - cachedStream.open(cachedPath.getFullPath(), Torque::FS::File::Read); - if (cachedStream.getStatus() == Stream::Ok) - { - TSShape *shape = new TSShape; - bool readSuccess = false; - if (canLoadCached) - { - readSuccess = shape->read(&cachedStream); - } - else - { - readSuccess = shape->importSequences(&cachedStream, cachedPath); - } - cachedStream.close(); - - if (readSuccess) - { - #ifdef TORQUE_DEBUG - Con::printf("Loaded cached shape from %s", cachedPath.getFullPath().c_str()); - #endif - return shape; - } - else - { - #ifdef TORQUE_DEBUG - Con::errorf("assimpLoadShape: Load sequence file '%s' failed", cachedPath.getFullPath().c_str()); - #endif - delete shape; - } - } - } - if (!Torque::FS::IsFile(path)) { // File does not exist, bail. - return NULL; + return false; } // Allow TSShapeConstructor object to override properties @@ -1068,40 +1035,20 @@ TSShape* assimpLoadShape(const Torque::Path &path) 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; - } - - if (!realMesh && gTryUseDSQs) - { - Torque::Path dsqPath(cachedPath); - dsqPath.setExtension("dsq"); - FileStream animOutStream; - dsqPath.setFileName(cachedPath.getFileName()); - if (animOutStream.open(dsqPath.getFullPath(), Torque::FS::File::Write)) - { - Con::printf("Writing DSQ Animation File for '%s'", dsqPath.getFileName().c_str()); - tss->exportSequences(&animOutStream); - } - } - else + Torque::Path cachedPath(path); + // Cache the model to a DTS file for faster loading next time. + cachedPath.setExtension("cached.dts"); + // Cache the model to a DTS file for faster loading next time. + FileStream dtsStream; + if (dtsStream.open(cachedPath.getFullPath(), Torque::FS::File::Write)) { - // Cache the model to a DTS file for faster loading next time. - cachedPath.setExtension("cached.dts"); - // Cache the model to a DTS file for faster loading next time. - FileStream dtsStream; - if (dtsStream.open(cachedPath.getFullPath(), Torque::FS::File::Write)) - { - Con::printf("Writing cached shape to %s", cachedPath.getFullPath().c_str()); - tss->write(&dtsStream); - } + Con::printf("Writing cached shape to %s", cachedPath.getFullPath().c_str()); + tss->write(&dtsStream); } } loader.releaseImport(); - return tss; + res_shape = tss; + return true; } DefineEngineFunction(GetShapeInfo, bool, (const char* shapePath, const char* ctrl, bool loadCachedDts), ("", "", true), diff --git a/Engine/source/ts/assimp/assimpShapeLoader.h b/Engine/source/ts/assimp/assimpShapeLoader.h index ac81c5d857..37c4aa308e 100644 --- a/Engine/source/ts/assimp/assimpShapeLoader.h +++ b/Engine/source/ts/assimp/assimpShapeLoader.h @@ -41,8 +41,6 @@ struct aiMetadata; //----------------------------------------------------------------------------- class AssimpShapeLoader : public TSShapeLoader { - friend TSShape* assimpLoadShape(const Torque::Path &path); - protected: Assimp::Importer mImporter; const aiScene* mScene; @@ -79,7 +77,6 @@ class AssimpShapeLoader : public TSShapeLoader bool fillGuiTreeView(const char* shapePath, GuiTreeViewCtrl* tree); static bool canLoadCachedDTS(const Torque::Path& path); - static bool canLoadCachedDSQ(const Torque::Path& path); static void assimpLogCallback(const char* message, char* user); }; diff --git a/Engine/source/ts/collada/colladaShapeLoader.cpp b/Engine/source/ts/collada/colladaShapeLoader.cpp index 66a8599348..264a7fe885 100644 --- a/Engine/source/ts/collada/colladaShapeLoader.cpp +++ b/Engine/source/ts/collada/colladaShapeLoader.cpp @@ -50,7 +50,24 @@ #include "core/util/zip/zipVolume.h" #include "gfx/bitmap/gBitmap.h" -extern bool gTryUseDSQs; +static bool sReadCollada(const Torque::Path& path, TSShape*& shape); + +static struct _privateRegisterCollada +{ + _privateRegisterCollada() + { + TSShape::ShapeRegistration reg; + reg.extensions.push_back({ "Collada", "dae" }); + reg.export_extensions.push_back({ "Collada", "dae" }); + reg.extensions.push_back({ "Google Earth", "kmz" }); + + reg.readFunc = sReadCollada; + reg.writeFunc = NULL; + + TSShape::sRegisterFormat(reg); + } +} sStaticRegisterCollada; + MODULE_BEGIN( ColladaShapeLoader ) MODULE_INIT_AFTER( ShapeLoader ) MODULE_INIT @@ -549,39 +566,6 @@ bool ColladaShapeLoader::canLoadCachedDTS(const Torque::Path& path) return false; } -bool ColladaShapeLoader::canLoadCachedDSQ(const Torque::Path& path) -{ - // Generate the cached filename - Torque::Path cachedPath(path); - cachedPath.setExtension("dsq"); - - // Check if a cached DSQ newer than this file is available - FileTime cachedModifyTime; - if (Platform::getFileTimes(cachedPath.getFullPath(), NULL, &cachedModifyTime)) - { - bool forceLoadDAE = Con::getBoolVariable("$collada::forceLoadDAE", false); - - FileTime daeModifyTime; - if (!Platform::getFileTimes(path.getFullPath(), NULL, &daeModifyTime) || - (!forceLoadDAE && (Platform::compareFileTimes(cachedModifyTime, daeModifyTime) >= 0))) - { - // DAE not found, or cached DTS is newer - return true; - } - } - - //assume the dts is good since it was zipped on purpose - Torque::FS::FileSystemRef ref = Torque::FS::GetFileSystem(cachedPath); - if (ref && !String::compare("Zip", ref->getTypeStr().c_str())) - { - bool forceLoadDAE = Con::getBoolVariable("$collada::forceLoadDAE", false); - - if (!forceLoadDAE && Torque::FS::IsFile(cachedPath)) - return true; - } - - return false; -} bool ColladaShapeLoader::checkAndMountSketchup(const Torque::Path& path, String& mountPoint, Torque::Path& daePath) { bool isSketchup = path.getExtension().equal("kmz", String::NoCase); @@ -683,61 +667,8 @@ domCOLLADA* ColladaShapeLoader::readColladaFile(const String& path) //----------------------------------------------------------------------------- /// This function is invoked by the resource manager based on file extension. -TSShape* loadColladaShape(const Torque::Path &path) +static bool sReadCollada(const Torque::Path& path, TSShape*& res_shape) { -#ifndef DAE2DTS_TOOL - // Generate the cached filename - Torque::Path cachedPath(path); - bool canLoadCached = false; - bool canLoadDSQ = false; - // Check if an up-to-date cached DTS version of this file exists, and - // if so, use that instead. - if (ColladaShapeLoader::canLoadCachedDTS(path)) - { - cachedPath.setExtension("cached.dts"); - canLoadCached = true; - } - else if (gTryUseDSQs && ColladaShapeLoader::canLoadCachedDSQ(path)) - { - cachedPath.setExtension("dsq"); - canLoadDSQ = true; - } - if (canLoadCached || canLoadDSQ) - { - FileStream cachedStream; - cachedStream.open(cachedPath.getFullPath(), Torque::FS::File::Read); - if (cachedStream.getStatus() == Stream::Ok) - { - TSShape *shape = new TSShape; - bool readSuccess = false; - if (canLoadCached) - { - readSuccess = shape->read(&cachedStream); - } - else - { - readSuccess = shape->importSequences(&cachedStream, cachedPath); - } - cachedStream.close(); - - if (readSuccess) - { - #ifdef TORQUE_DEBUG - Con::printf("Loaded cached Collada shape from %s", cachedPath.getFullPath().c_str()); - #endif - return shape; - } - else - { - #ifdef TORQUE_DEBUG - Con::errorf("loadColladaShape: Load sequence file '%s' failed", cachedPath.getFullPath().c_str()); - #endif - delete shape; - } - } - } -#endif // DAE2DTS_TOOL - if (!Torque::FS::IsFile(path)) { // DAE file does not exist, bail. @@ -777,58 +708,31 @@ TSShape* loadColladaShape(const Torque::Path &path) tss = loader.generateShape(daePath); if (tss) { -#ifndef DAE2DTS_TOOL - - bool realMesh = false; - for (U32 i = 0; i < tss->meshes.size(); ++i) + TSShapeLoader::updateProgress(TSShapeLoader::Load_Complete, "Import complete"); + Con::printf("[COLLADA] Shape created successfully."); + + Torque::Path cachedPath(path); + // Cache the model to a DTS file for faster loading next time. + cachedPath.setExtension("cached.dts"); + // Cache the model to a DTS file for faster loading next time. + FileStream dtsStream; + if (dtsStream.open(cachedPath.getFullPath(), Torque::FS::File::Write)) { - if (tss->meshes[i] && tss->meshes[i]->getMeshType() != TSMesh::NullMeshType) - realMesh = true; + Con::printf("Writing cached shape to %s", cachedPath.getFullPath().c_str()); + tss->write(&dtsStream); } - if (!realMesh && gTryUseDSQs) - { - Torque::Path dsqPath(cachedPath); - dsqPath.setExtension("dsq"); - FileStream animOutStream; - dsqPath.setFileName(cachedPath.getFileName()); - if (animOutStream.open(dsqPath.getFullPath(), Torque::FS::File::Write)) - { - Con::printf("Writing DSQ Animation File for '%s'", dsqPath.getFileName().c_str()); - tss->exportSequences(&animOutStream); - animOutStream.close(); - } - } - else - { - // Cache the Collada model to a DTS file for faster loading next time. - cachedPath.setExtension("cached.dts"); - FileStream dtsStream; - if (dtsStream.open(cachedPath.getFullPath(), Torque::FS::File::Write)) - { - Torque::FS::FileSystemRef ref = Torque::FS::GetFileSystem(daePath); - if (ref && !String::compare("Zip", ref->getTypeStr().c_str())) - Con::errorf("No cached dts file found in archive for %s. Forcing cache to disk.", daePath.getFullFileName().c_str()); - - Con::printf("Writing cached COLLADA shape to %s", cachedPath.getFullPath().c_str()); - tss->write(&dtsStream); - } - } -#endif // DAE2DTS_TOOL - // Add collada materials to materials.tscript updateMaterialsScript(path, isSketchup); } } - // Close progress dialog - TSShapeLoader::updateProgress(TSShapeLoader::Load_Complete, "Import complete"); - if (isSketchup) { // Unmount the zip if we mounted it Torque::FS::Unmount(mountPoint); } - return tss; + res_shape = tss; + return true; } diff --git a/Engine/source/ts/collada/colladaShapeLoader.h b/Engine/source/ts/collada/colladaShapeLoader.h index 54cb2e70f0..780b403db3 100644 --- a/Engine/source/ts/collada/colladaShapeLoader.h +++ b/Engine/source/ts/collada/colladaShapeLoader.h @@ -34,8 +34,6 @@ struct AnimChannels; //----------------------------------------------------------------------------- class ColladaShapeLoader : public TSShapeLoader { - friend TSShape* loadColladaShape(const Torque::Path &path); - domCOLLADA* root; Vector animations; ///< Holds all animation channels for deletion after loading @@ -53,7 +51,6 @@ class ColladaShapeLoader : public TSShapeLoader void computeBounds(Box3F& bounds) override; static bool canLoadCachedDTS(const Torque::Path& path); - static bool canLoadCachedDSQ(const Torque::Path& path); static bool checkAndMountSketchup(const Torque::Path& path, String& mountPoint, Torque::Path& daePath); static domCOLLADA* getDomCOLLADA(const Torque::Path& path); static domCOLLADA* readColladaFile(const String& path); diff --git a/Engine/source/ts/loader/tsShapeLoader.cpp b/Engine/source/ts/loader/tsShapeLoader.cpp index 7baceec710..0ef81a639f 100644 --- a/Engine/source/ts/loader/tsShapeLoader.cpp +++ b/Engine/source/ts/loader/tsShapeLoader.cpp @@ -36,11 +36,9 @@ MODULE_BEGIN( ShapeLoader ) MODULE_INIT { TSShapeLoader::addFormat("Torque DTS", "dts"); - TSShapeLoader::addFormat("Torque DSQ", "dsq"); } MODULE_END; -bool gTryUseDSQs = false; const F32 TSShapeLoader::DefaultTime = -1.0f; const F64 TSShapeLoader::MinFrameRate = 15.0f; const F64 TSShapeLoader::MaxFrameRate = 60.0f; diff --git a/Engine/source/ts/tsShape.cpp b/Engine/source/ts/tsShape.cpp index 19b873a336..f5c9c027d1 100644 --- a/Engine/source/ts/tsShape.cpp +++ b/Engine/source/ts/tsShape.cpp @@ -38,13 +38,30 @@ #include "core/stream/fileStream.h" #include "core/fileObject.h" -#ifdef TORQUE_COLLADA -extern TSShape* loadColladaShape(const Torque::Path &path); -#endif +Vector TSShape::sRegistrations(__FILE__, __LINE__); -#ifdef TORQUE_ASSIMP -extern TSShape* assimpLoadShape(const Torque::Path &path); -#endif +void TSShape::sRegisterFormat(const ShapeRegistration& reg) +{ + U32 insert = sRegistrations.size(); + sRegistrations.insert(insert, reg); +} + +const TSShape::ShapeRegistration* TSShape::sFindRegInfo(const String& extension, bool exporting) +{ + for (U32 i = 0; i < TSShape::sRegistrations.size(); i++) + { + const TSShape::ShapeRegistration& reg = TSShape::sRegistrations[i]; + const Vector& extensions = exporting ? reg.export_extensions : reg.extensions; + + for (U32 j = 0; j < extensions.size(); j++) + { + if (extensions[j].mExtension.equal(extension, String::NoCase)) + return ® + } + } + + return NULL; +} /// most recent version -- this is the version we write S32 TSShape::smVersion = 28; @@ -2166,60 +2183,60 @@ template<> void *Resource::create(const Torque::Path &path) TSShape * ret = 0; bool readSuccess = false; const String extension = path.getExtension(); + bool canLoadCached = false; + + // Generate the cached filename + Torque::Path cachedPath(path); + cachedPath.setExtension("cached.dts"); - if ( extension.equal( "dts", String::NoCase ) ) + // Check if a cached DTS newer than this file is available + FileTime cachedModifyTime; + if (Platform::getFileTimes(cachedPath.getFullPath(), NULL, &cachedModifyTime)) { - FileStream stream; - stream.open( path.getFullPath(), Torque::FS::File::Read ); - if ( stream.getStatus() != Stream::Ok ) + bool forceLoadDAE = Con::getBoolVariable("$collada::forceLoadDAE", false); + + FileTime daeModifyTime; + if (!Platform::getFileTimes(path.getFullPath(), NULL, &daeModifyTime) || + (!forceLoadDAE && (Platform::compareFileTimes(cachedModifyTime, daeModifyTime) >= 0))) { - Con::errorf( "Resource::create - Could not open '%s'", path.getFullPath().c_str() ); - return NULL; + // Non DTS not found, or cached DTS is newer + canLoadCached = true; } + } - ret = new TSShape; - readSuccess = ret->read(&stream); + //assume the dts is good since it was zipped on purpose + Torque::FS::FileSystemRef ref = Torque::FS::GetFileSystem(cachedPath); + if (ref && !String::compare("Zip", ref->getTypeStr().c_str())) + { + bool forceLoadDAE = Con::getBoolVariable("$collada::forceLoadDAE", false); + + if (!forceLoadDAE && Torque::FS::IsFile(cachedPath)) + canLoadCached = true; } - else if ( extension.equal( "dae", String::NoCase ) || extension.equal( "kmz", String::NoCase ) ) - { -#ifdef TORQUE_COLLADA - // Attempt to load the DAE file - ret = loadColladaShape(path); - readSuccess = (ret != NULL); -#else - // No COLLADA support => attempt to load the cached DTS file instead - Torque::Path cachedPath = path; - cachedPath.setExtension("cached.dts"); - + + if (extension.equal("dts", String::NoCase) || canLoadCached) + { FileStream stream; - stream.open( cachedPath.getFullPath(), Torque::FS::File::Read ); + stream.open(canLoadCached ? cachedPath.getFullPath() : path.getFullPath(), Torque::FS::File::Read); if ( stream.getStatus() != Stream::Ok ) { - Con::errorf( "Resource::create - Could not open '%s'", cachedPath.getFullPath().c_str() ); + Con::errorf( "Resource::create - Could not open '%s'", path.getFullPath().c_str() ); return NULL; } + ret = new TSShape; readSuccess = ret->read(&stream); -#endif } else { - //Con::errorf( "Resource::create - '%s' has an unknown file format", path.getFullPath().c_str() ); - //delete ret; - //return NULL; - - // andrewmac: Open Asset Import Library -#ifdef TORQUE_ASSIMP - ret = assimpLoadShape(path); - readSuccess = (ret != NULL); -#endif - - // andrewmac : I could have used another conditional macro but I think this is suffice: - if (!readSuccess) + const TSShape::ShapeRegistration* regInfo = TSShape::sFindRegInfo(extension); + if (regInfo == NULL) { - Con::errorf("Resource::create - '%s' has an unknown file format", path.getFullPath().c_str()); - delete ret; - return NULL; + readSuccess = false; + } + else + { + readSuccess = regInfo->readFunc(path, ret); } } diff --git a/Engine/source/ts/tsShape.h b/Engine/source/ts/tsShape.h index 8e2071fb26..87a40d24ed 100644 --- a/Engine/source/ts/tsShape.h +++ b/Engine/source/ts/tsShape.h @@ -83,18 +83,47 @@ struct TSShapeVertexArray /// @see TSShapeInstance for a further discussion of the 3space system. class TSShape { - public: - enum +public: + enum + { + UniformScale = BIT(0), + AlignedScale = BIT(1), + ArbitraryScale = BIT(2), + Blend = BIT(3), + Cyclic = BIT(4), + MakePath = BIT(5), + HasTranslucency= BIT(6), + AnyScale = UniformScale | AlignedScale | ArbitraryScale + }; + + struct ShapeFormat + { + String mName; + String mExtension; + }; + + struct ShapeRegistration + { + typedef bool(*ReadShape)(const Torque::Path& path, TSShape*& shape); + typedef bool(*WriteShape)(const Torque::Path& path, TSShape* shape); + Vector extensions; ///< the list of file extensions for this Loader [these should be lower case] + Vector export_extensions; ///< the list of file extensions for this Loader [these should be lower case] + + ReadShape readFunc; ///< the read function to read from a file. + WriteShape writeFunc; ///< the write function to write to a file. + + ShapeRegistration() { - UniformScale = BIT(0), - AlignedScale = BIT(1), - ArbitraryScale = BIT(2), - Blend = BIT(3), - Cyclic = BIT(4), - MakePath = BIT(5), - HasTranslucency= BIT(6), - AnyScale = UniformScale | AlignedScale | ArbitraryScale - }; + readFunc = NULL; + writeFunc = NULL; + VECTOR_SET_ASSOCIATION(extensions); + VECTOR_SET_ASSOCIATION(export_extensions); + } + }; + + static void sRegisterFormat(const ShapeRegistration& reg); + static const ShapeRegistration* sFindRegInfo(const String& extension, bool exporting = false); + static Vector sRegistrations; /// Nodes hold the transforms in the shape's tree. They are the bones of the skeleton. struct Node diff --git a/Engine/source/ts/tsShapeEdit.cpp b/Engine/source/ts/tsShapeEdit.cpp index db4c615493..042fb130fb 100644 --- a/Engine/source/ts/tsShapeEdit.cpp +++ b/Engine/source/ts/tsShapeEdit.cpp @@ -1361,16 +1361,7 @@ bool TSShape::isShapeFileType(Torque::Path filePath) { String fileExt = filePath.getExtension(); - if ( - fileExt.equal("dts", String::NoCase) || - fileExt.equal("dsq", String::NoCase) || - fileExt.equal("dae", String::NoCase) || - fileExt.equal("fbx", String::NoCase) || - fileExt.equal("blend", String::NoCase) || - fileExt.equal("obj", String::NoCase) || - fileExt.equal("gltf", String::NoCase) || - fileExt.equal("glb", String::NoCase) - ) + if (TSShape::sFindRegInfo(fileExt)) return true; return false;