mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-05-07 06:16:04 +00:00
Groundwork
Adds the same sort of model for registering loaders and exporters as is set out on gbitmap Added a bit more safety around the assimp matrix fix to convert incoming models to torques coordinate system.
This commit is contained in:
parent
8407fa360c
commit
ee04b0cf15
9 changed files with 238 additions and 358 deletions
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,12 +56,13 @@
|
|||
#undef new
|
||||
#endif
|
||||
#endif
|
||||
// assimp include files.
|
||||
// assimp include files.
|
||||
#include <assimp/cimport.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/postprocess.h>
|
||||
#include <assimp/types.h>
|
||||
#include <assimp/config.h>
|
||||
#include <assimp/Exporter.hpp>
|
||||
#include <exception>
|
||||
|
||||
#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<String> 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)
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
// 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),
|
||||
|
|
|
|||
|
|
@ -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 @@ public:
|
|||
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);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
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)
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,8 +34,6 @@ struct AnimChannels;
|
|||
//-----------------------------------------------------------------------------
|
||||
class ColladaShapeLoader : public TSShapeLoader
|
||||
{
|
||||
friend TSShape* loadColladaShape(const Torque::Path &path);
|
||||
|
||||
domCOLLADA* root;
|
||||
Vector<AnimChannels*> animations; ///< Holds all animation channels for deletion after loading
|
||||
|
||||
|
|
@ -53,7 +51,6 @@ public:
|
|||
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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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::ShapeRegistration> 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<ShapeFormat>& 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,11 +2183,41 @@ template<> void *Resource<TSShape>::create(const Torque::Path &path)
|
|||
TSShape * ret = 0;
|
||||
bool readSuccess = false;
|
||||
const String extension = path.getExtension();
|
||||
bool canLoadCached = false;
|
||||
|
||||
if ( extension.equal( "dts", String::NoCase ) )
|
||||
// Generate the cached filename
|
||||
Torque::Path cachedPath(path);
|
||||
cachedPath.setExtension("cached.dts");
|
||||
|
||||
// Check if a cached DTS 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)))
|
||||
{
|
||||
// Non DTS not found, or cached DTS is newer
|
||||
canLoadCached = 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))
|
||||
canLoadCached = true;
|
||||
}
|
||||
|
||||
if (extension.equal("dts", String::NoCase) || canLoadCached)
|
||||
{
|
||||
FileStream stream;
|
||||
stream.open( path.getFullPath(), Torque::FS::File::Read );
|
||||
stream.open(canLoadCached ? cachedPath.getFullPath() : path.getFullPath(), Torque::FS::File::Read);
|
||||
if ( stream.getStatus() != Stream::Ok )
|
||||
{
|
||||
Con::errorf( "Resource<TSShape>::create - Could not open '%s'", path.getFullPath().c_str() );
|
||||
|
|
@ -2180,46 +2227,16 @@ template<> void *Resource<TSShape>::create(const Torque::Path &path)
|
|||
ret = new TSShape;
|
||||
readSuccess = ret->read(&stream);
|
||||
}
|
||||
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");
|
||||
|
||||
FileStream stream;
|
||||
stream.open( cachedPath.getFullPath(), Torque::FS::File::Read );
|
||||
if ( stream.getStatus() != Stream::Ok )
|
||||
{
|
||||
Con::errorf( "Resource<TSShape>::create - Could not open '%s'", cachedPath.getFullPath().c_str() );
|
||||
return NULL;
|
||||
}
|
||||
ret = new TSShape;
|
||||
readSuccess = ret->read(&stream);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
//Con::errorf( "Resource<TSShape>::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<TSShape>::create - '%s' has an unknown file format", path.getFullPath().c_str());
|
||||
delete ret;
|
||||
return NULL;
|
||||
readSuccess = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
readSuccess = regInfo->readFunc(path, ret);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<ShapeFormat> extensions; ///< the list of file extensions for this Loader [these should be lower case]
|
||||
Vector<ShapeFormat> 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<ShapeRegistration> sRegistrations;
|
||||
|
||||
/// Nodes hold the transforms in the shape's tree. They are the bones of the skeleton.
|
||||
struct Node
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue