Merge branch 'Assimp_Settings' of https://github.com/OTHGMars/Torque3D into Preview4_0

This commit is contained in:
Areloch 2019-05-25 01:08:16 -05:00
commit ef226f6a65
25 changed files with 4541 additions and 1508 deletions

View file

@ -1,4 +1,4 @@
/*
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
@ -1047,6 +1047,9 @@ namespace glTF2
{
bool KHR_materials_pbrSpecularGlossiness;
bool KHR_materials_unlit;
//T3D_CHANGE_BEGIN
bool KHR_draco_mesh_compression;
//T3D_CHANGE_END
} extensionsUsed;

View file

@ -1360,6 +1360,14 @@ inline void Asset::Load(const std::string& pFile, bool isBinary)
// Load the metadata
asset.Read(doc);
ReadExtensionsUsed(doc);
//T3D_CHANGE_BEGIN
if (extensionsUsed.KHR_draco_mesh_compression)
{
ASSIMP_LOG_ERROR("GLTF: Draco mesh compression is not supported by Torque3D.");
throw DeadlyImportError("GLTF: Draco mesh compression is not supported by Torque3D.");
}
//T3D_CHANGE_END
// Prepare the dictionaries
for (size_t i = 0; i < mDicts.size(); ++i) {
@ -1425,6 +1433,9 @@ inline void Asset::ReadExtensionsUsed(Document& doc)
CHECK_EXT(KHR_materials_pbrSpecularGlossiness);
CHECK_EXT(KHR_materials_unlit);
//T3D_CHANGE_BEGIN
CHECK_EXT(KHR_draco_mesh_compression);
//T3D_CHANGE_END
#undef CHECK_EXT
}

View file

@ -0,0 +1,5 @@
### Asset Import Library Usage Notes
No single set of default values will be appropriate for all import formats and many do not provide any metadata to draw the information from, so Shape Import Settings (.sis) files have been added as a way to save and reuse import settings. You can create default settings for each shape file type that you will be importing by setting all of the values in the import options gui and selecting `Save Settings`. Save the file in the default settings location (game/tools, editable in EditorSettings) using the shape file extension as the file name i.e. fbx.sis, blend.sis, obj.sis. Default settings files have been provided for gltf files.
Shapes can be re-imported via the Shape Editor by checking the `Source Art` box at the top of the inspector pane. Note: If the shape is currently loaded in the level, or is preloaded in any active datablock, the source art cannot be reloaded because the existing shape reference will not be released.

View file

@ -27,6 +27,7 @@
#include "ts/assimp/assimpAppMesh.h"
#include "materials/materialManager.h"
#include "ts/tsMaterialList.h"
#include "core/stream/fileStream.h"
// assimp include files.
#include <assimp/cimport.h>
@ -34,6 +35,8 @@
#include <assimp/postprocess.h>
#include <assimp/types.h>
U32 AssimpAppMaterial::sDefaultMatNumber = 0;
String AppMaterial::cleanString(const String& str)
{
String cleanStr(str);
@ -52,7 +55,8 @@ String AppMaterial::cleanString(const String& str)
AssimpAppMaterial::AssimpAppMaterial(const char* matName)
{
name = matName;
name = ColladaUtils::getOptions().matNamePrefix;
name += matName;
// Set some defaults
flags |= TSMaterialList::S_Wrap;
@ -67,9 +71,12 @@ AssimpAppMaterial::AssimpAppMaterial(aiMaterial* mtl) :
name = matName.C_Str();
if (name.isEmpty())
{
name = cleanString(TSShapeLoader::getShapePath().getFileName());;
name = cleanString(TSShapeLoader::getShapePath().getFileName());
name += "_defMat";
name += String::ToString("%d", sDefaultMatNumber);
sDefaultMatNumber++;
}
name = ColladaUtils::getOptions().matNamePrefix + name;
Con::printf("[ASSIMP] Loading Material: %s", name.c_str());
#ifdef TORQUE_DEBUG
enumerateMaterialProperties(mtl);
@ -125,7 +132,7 @@ void AssimpAppMaterial::initMaterial(const Torque::Path& path, Material* mat) co
if (dStrcmp("MASK", opacityMode.C_Str()) == 0)
{
translucent = true;
blendOp = Material::LerpAlpha;
blendOp = Material::None;
float cutoff;
if (AI_SUCCESS == mAIMat->Get("$mat.gltf.alphaCutoff", 0, 0, cutoff))
@ -134,10 +141,16 @@ void AssimpAppMaterial::initMaterial(const Torque::Path& path, Material* mat) co
mat->mAlphaTest = true;
}
}
else if (dStrcmp("OPAQUE", opacityMode.C_Str()) != 0)
else if (dStrcmp("BLEND", opacityMode.C_Str()) == 0)
{
translucent = true;
blendOp = Material::LerpAlpha;
mat->mAlphaTest = false;
}
else
{ // OPAQUE
translucent = false;
blendOp = Material::LerpAlpha; // Make default so it doesn't get written to materials.cs
}
}
}
@ -157,14 +170,14 @@ void AssimpAppMaterial::initMaterial(const Torque::Path& path, Material* mat) co
{
torquePath = texName.C_Str();
if (!torquePath.isEmpty())
mat->mDiffuseMapFilename[0] = cleanTextureName(torquePath, cleanFile);
mat->mDiffuseMapFilename[0] = cleanTextureName(torquePath, cleanFile, path, false);
}
if (AI_SUCCESS == mAIMat->Get(AI_MATKEY_TEXTURE(aiTextureType_NORMALS, 0), texName))
{
torquePath = texName.C_Str();
if (!torquePath.isEmpty())
mat->mNormalMapFilename[0] = cleanTextureName(torquePath, cleanFile);
mat->mNormalMapFilename[0] = cleanTextureName(torquePath, cleanFile, path, false);
}
#ifdef TORQUE_PBR_MATERIALS
@ -177,27 +190,25 @@ void AssimpAppMaterial::initMaterial(const Torque::Path& path, Material* mat) co
if (AI_SUCCESS == mAIMat->Get(AI_MATKEY_TEXTURE(aiTextureType_UNKNOWN, 0), texName))
rmName = texName.C_Str();
//if (aoName.isNotEmpty() && (aoName == rmName))
// mat->mOrmMapFilename[0] = cleanTextureName(aoName, cleanFile); // It's an ORM map
//else if (aoName.isNotEmpty() || rmName.isNotEmpty())
mat->mIsSRGb[0] = true;
if (aoName.isNotEmpty() || rmName.isNotEmpty())
{ // If we have either map, fill all three slots
if (rmName.isNotEmpty())
{
mat->mRoughMapFilename[0] = cleanTextureName(rmName, cleanFile); // Roughness
mat->mRoughMapFilename[0] = cleanTextureName(rmName, cleanFile, path, false); // Roughness
mat->mSmoothnessChan[0] = 1.0f;
mat->mInvertSmoothness = (floatVal == 1.0f);
mat->mMetalMapFilename[0] = cleanTextureName(rmName, cleanFile); // Metallic
mat->mMetalMapFilename[0] = cleanTextureName(rmName, cleanFile, path, false); // Metallic
mat->mMetalChan[0] = 2.0f;
}
if (aoName.isNotEmpty())
{
mat->mAOMapFilename[0] = cleanTextureName(aoName, cleanFile); // occlusion
mat->mAOMapFilename[0] = cleanTextureName(aoName, cleanFile, path, false); // occlusion
mat->mAOChan[0] = 0.0f;
}
else
{
mat->mAOMapFilename[0] = cleanTextureName(rmName, cleanFile); // occlusion
mat->mAOMapFilename[0] = cleanTextureName(rmName, cleanFile, path, false); // occlusion
mat->mAOChan[0] = 0.0f;
}
}
@ -207,7 +218,7 @@ void AssimpAppMaterial::initMaterial(const Torque::Path& path, Material* mat) co
{
torquePath = texName.C_Str();
if (!torquePath.isEmpty())
mat->mSpecularMapFilename[0] = cleanTextureName(torquePath, cleanFile);
mat->mSpecularMapFilename[0] = cleanTextureName(torquePath, cleanFile, path, false);
}
/*LinearColorF specularColor(1.0f, 1.0f, 1.0f, 1.0f);
@ -234,22 +245,70 @@ void AssimpAppMaterial::initMaterial(const Torque::Path& path, Material* mat) co
mat->mDoubleSided = doubleSided;
}
String AssimpAppMaterial::cleanTextureName(String& texName, String& shapeName)
String AssimpAppMaterial::cleanTextureName(String& texName, String& shapeName, const Torque::Path& path, bool nameOnly /*= false*/)
{
Torque::Path foundPath;
String cleanStr;
if (texName[0] == '*')
{
{ // It's an embedded texture reference. Make the cached name and return
cleanStr = shapeName;
cleanStr += "_cachedTex";
cleanStr += texName.substr(1);
return cleanStr;
}
// See if the file exists
bool fileFound = false;
String testPath = path.getPath();
testPath += '/';
testPath += texName;
testPath.replace('\\', '/');
fileFound = Torque::FS::IsFile(testPath);
cleanStr = texName;
cleanStr.replace('\\', '/');
if (fileFound)
{
if (cleanStr.equal(texName))
return cleanStr;
foundPath = testPath;
}
else
{
cleanStr = texName;
cleanStr.replace('\\', '/');
// See if the file is in a sub-directory of the shape
Vector<String> foundFiles;
Torque::Path inPath(cleanStr);
String mainDotCsDir = Platform::getMainDotCsDir();
mainDotCsDir += "/";
S32 results = Torque::FS::FindByPattern(Torque::Path(mainDotCsDir + path.getPath() + "/"), inPath.getFullFileName(), true, foundFiles);
if (results == 0 || foundFiles.size() == 0) // Not under shape directory, try the full tree
results = Torque::FS::FindByPattern(Torque::Path(mainDotCsDir), inPath.getFullFileName(), true, foundFiles);
if (results > 0 && foundFiles.size() > 0)
{
fileFound = true;
foundPath = foundFiles[0];
}
}
if (fileFound)
{
if (nameOnly)
cleanStr = foundPath.getFullFileName();
else
{ // Unless the file is in the same directory as the materials.cs (covered above)
// we need to set the full path from the root directory. If we use "subdirectory/file.ext",
// the material manager won't find the image file, but it will be found the next time the
// material is loaded from file. If we use "./subdirectory/file.ext", the image will be found
// now, but not the next time it's loaded from file...
S32 rootLength = dStrlen(Platform::getMainDotCsDir());
cleanStr = foundPath.getFullPathWithoutRoot().substr(rootLength-1);
}
}
else if (nameOnly)
cleanStr += " (Not Found)";
return cleanStr;
}

View file

@ -40,7 +40,6 @@ class AssimpAppMaterial : public AppMaterial
#ifdef TORQUE_DEBUG
void enumerateMaterialProperties(aiMaterial* mtl);
#endif
static String cleanTextureName(String& texName, String& shapeName);
public:
@ -51,6 +50,9 @@ public:
String getName() const { return name; }
Material* createMaterial(const Torque::Path& path) const;
void initMaterial(const Torque::Path& path, Material* mat) const;
static String cleanTextureName(String& texName, String& shapeName, const Torque::Path& path, bool nameOnly = false);
static U32 sDefaultMatNumber;
};
#endif // _ASSIMP_APPMATERIAL_H_

View file

@ -79,7 +79,7 @@ void AssimpAppMesh::lockMesh(F32 t, const MatrixF& objOffset)
uvs.reserve(mMeshData->mNumVertices);
normals.reserve(mMeshData->mNumVertices);
bool flipNormals = Con::getBoolVariable("$Assimp::FlipNormals", false);
bool flipNormals = ColladaUtils::getOptions().invertNormals;
bool noUVFound = false;
for (U32 i = 0; i<mMeshData->mNumVertices; i++)
@ -203,14 +203,17 @@ void AssimpAppMesh::lockMesh(F32 t, const MatrixF& objOffset)
MatrixF boneTransform;
AssimpAppNode::assimpToTorqueMat(mMeshData->mBones[b]->mOffsetMatrix, boneTransform);
Point3F boneScale = boneTransform.getScale();
if (boneScale != Point3F::One)
Point3F bonePos = boneTransform.getPosition();
if (boneScale != Point3F::One && ColladaUtils::getOptions().ignoreNodeScale)
{
Point3F scaleMult = Point3F::One / boneScale;
Point3F scalePos = boneTransform.getPosition();
boneTransform.scale(scaleMult);
scalePos /= scaleMult;
boneTransform.setPosition(scalePos);
bonePos /= scaleMult;
}
bonePos *= ColladaUtils::getOptions().unit;
boneTransform.setPosition(bonePos);
initialTransforms.push_back(boneTransform);
//Weights

View file

@ -91,22 +91,30 @@ MatrixF AssimpAppNode::getTransform(F32 time)
else {
// no parent (ie. root level) => scale by global shape <unit>
mLastTransform.identity();
mLastTransform.scale(ColladaUtils::getOptions().unit);
if (!isBounds())
convertMat(mLastTransform);
//mLastTransform.scale(ColladaUtils::getOptions().unit);
}
// If this node is animated in the active sequence, fetch the animated transform
MatrixF mat(true);
if (sActiveSequence)
{
MatrixF mat(true);
getAnimatedTransform(mat, time, sActiveSequence);
mLastTransform.mul(mat);
}
else
mLastTransform.mul(mNodeTransform);
mat = mNodeTransform;
// Remove node scaling?
Point3F nodeScale = mat.getScale();
if (nodeScale != Point3F::One && appParent && ColladaUtils::getOptions().ignoreNodeScale)
{
nodeScale.x = nodeScale.x ? (1.0f / nodeScale.x) : 0;
nodeScale.y = nodeScale.y ? (1.0f / nodeScale.y) : 0;
nodeScale.z = nodeScale.z ? (1.0f / nodeScale.z) : 0;
mat.scale(nodeScale);
}
mLastTransform.mul(mat);
mLastTransformTime = time;
return mLastTransform;
}
@ -280,12 +288,9 @@ void AssimpAppNode::convertMat(MatrixF& outMat)
{
MatrixF rot(true);
// This is copied directly from ColladaUtils::convertTransform()
// ColladaUtils::getOptions().upAxis has been temporarily replaced with $Assimp::OverrideUpAxis for testing
// We need a plan for how the full set of assimp import options and settings is going to be managed.
switch (Con::getIntVariable("$Assimp::OverrideUpAxis", 2))
switch (ColladaUtils::getOptions().upAxis)
{
case 0: //UPAXISTYPE_X_UP:
case UPAXISTYPE_X_UP:
// rotate 90 around Y-axis, then 90 around Z-axis
rot(0, 0) = 0.0f; rot(1, 0) = 1.0f;
rot(1, 1) = 0.0f; rot(2, 1) = 1.0f;
@ -295,7 +300,7 @@ void AssimpAppNode::convertMat(MatrixF& outMat)
outMat.mulL(rot);
break;
case 1: //UPAXISTYPE_Y_UP:
case UPAXISTYPE_Y_UP:
// rotate 180 around Y-axis, then 90 around X-axis
rot(0, 0) = -1.0f;
rot(1, 1) = 0.0f; rot(2, 1) = 1.0f;
@ -305,7 +310,7 @@ void AssimpAppNode::convertMat(MatrixF& outMat)
outMat.mulL(rot);
break;
case 2: //UPAXISTYPE_Z_UP:
case UPAXISTYPE_Z_UP:
default:
// nothing to do
break;

View file

@ -58,8 +58,8 @@ AssimpAppSequence::AssimpAppSequence(aiAnimation *a) :
}
}
S32 timeFactor = Con::getIntVariable("$Assimp::AnimTiming", 1);
S32 fpsRequest = Con::getIntVariable("$Assimp::AnimFPS", 30);
S32 timeFactor = ColladaUtils::getOptions().animTiming;
S32 fpsRequest = ColladaUtils::getOptions().animFPS;
if (timeFactor == 0)
{ // Timing specified in frames
fps = mClamp(fpsRequest, 5 /*TSShapeLoader::MinFrameRate*/, TSShapeLoader::MaxFrameRate);
@ -70,10 +70,7 @@ AssimpAppSequence::AssimpAppSequence(aiAnimation *a) :
else
{ // Timing specified in seconds or ms depending on format
if (maxEndTime > 1000.0f || mAnim->mDuration > 1000.0f)
{
timeFactor = 1000.0f; // If it's more than 1000 seconds, assume it's ms.
Con::setIntVariable("$Assimp::AnimTiming", 1000);
}
timeFactor = mClamp(timeFactor, 1, 1000);
minFrameTime /= (F32)timeFactor;

View file

@ -39,6 +39,7 @@
#include "core/util/tVector.h"
#include "core/strings/findMatch.h"
#include "core/strings/stringUnit.h"
#include "core/stream/fileStream.h"
#include "core/fileObject.h"
#include "ts/tsShape.h"
@ -133,29 +134,16 @@ void AssimpShapeLoader::enumerateScene()
// Post-Processing
unsigned int ppsteps =
Con::getBoolVariable("$Assimp::ConvertToLeftHanded", false) ? aiProcess_ConvertToLeftHanded : 0 |
Con::getBoolVariable("$Assimp::CalcTangentSpace", false) ? aiProcess_CalcTangentSpace : 0 |
Con::getBoolVariable("$Assimp::JoinIdenticalVertices", false) ? aiProcess_JoinIdenticalVertices : 0 |
Con::getBoolVariable("$Assimp::ValidateDataStructure", false) ? aiProcess_ValidateDataStructure : 0 |
Con::getBoolVariable("$Assimp::ImproveCacheLocality", false) ? aiProcess_ImproveCacheLocality : 0 |
Con::getBoolVariable("$Assimp::RemoveRedundantMaterials", false) ? aiProcess_RemoveRedundantMaterials : 0 |
Con::getBoolVariable("$Assimp::FindDegenerates", false) ? aiProcess_FindDegenerates : 0 |
Con::getBoolVariable("$Assimp::FindInvalidData", false) ? aiProcess_FindInvalidData : 0 |
Con::getBoolVariable("$Assimp::GenUVCoords", false) ? aiProcess_GenUVCoords : 0 |
Con::getBoolVariable("$Assimp::TransformUVCoords", false) ? aiProcess_TransformUVCoords : 0 |
Con::getBoolVariable("$Assimp::FindInstances", false) ? aiProcess_FindInstances : 0 |
Con::getBoolVariable("$Assimp::LimitBoneWeights", false) ? aiProcess_LimitBoneWeights : 0 |
Con::getBoolVariable("$Assimp::OptimizeMeshes", false) ? aiProcess_OptimizeMeshes | aiProcess_OptimizeGraph : 0 |
0;
if(Con::getBoolVariable("$Assimp::FlipUVs", true))
ppsteps |= aiProcess_FlipUVs;
if(Con::getBoolVariable("$Assimp::FlipWindingOrder", false))
ppsteps |= aiProcess_FlipWindingOrder;
if(Con::getBoolVariable("$Assimp::Triangulate", true))
ppsteps |= aiProcess_Triangulate;
(ColladaUtils::getOptions().convertLeftHanded ? aiProcess_MakeLeftHanded : 0) |
(ColladaUtils::getOptions().reverseWindingOrder ? aiProcess_FlipWindingOrder : 0) |
(ColladaUtils::getOptions().calcTangentSpace ? aiProcess_CalcTangentSpace : 0) |
(ColladaUtils::getOptions().joinIdenticalVerts ? aiProcess_JoinIdenticalVertices : 0) |
(ColladaUtils::getOptions().removeRedundantMats ? aiProcess_RemoveRedundantMaterials : 0) |
(ColladaUtils::getOptions().genUVCoords ? aiProcess_GenUVCoords : 0) |
(ColladaUtils::getOptions().transformUVCoords ? aiProcess_TransformUVCoords : 0) |
(ColladaUtils::getOptions().flipUVCoords ? aiProcess_FlipUVs : 0) |
(ColladaUtils::getOptions().findInstances ? aiProcess_FindInstances : 0) |
(ColladaUtils::getOptions().limitBoneWeights ? aiProcess_LimitBoneWeights : 0);
if (Con::getBoolVariable("$Assimp::OptimizeMeshes", false))
ppsteps |= aiProcess_OptimizeMeshes | aiProcess_OptimizeGraph;
@ -163,34 +151,21 @@ void AssimpShapeLoader::enumerateScene()
if (Con::getBoolVariable("$Assimp::SplitLargeMeshes", false))
ppsteps |= aiProcess_SplitLargeMeshes;
// Mandatory options
//ppsteps |= aiProcess_ValidateDataStructure | aiProcess_Triangulate | aiProcess_ImproveCacheLocality;
ppsteps |= aiProcess_Triangulate;
//aiProcess_SortByPType | // make 'clean' meshes which consist of a single typ of primitives
aiPropertyStore* props = aiCreatePropertyStore();
//aiSetImportPropertyInteger(props, AI_CONFIG_IMPORT_TER_MAKE_UVS, 1);
//aiSetImportPropertyInteger(props, AI_CONFIG_PP_SBP_REMOVE, (aiProcessPreset_TargetRealtime_Quality
// | aiProcess_FlipWindingOrder | aiProcess_FlipUVs
// | aiProcess_CalcTangentSpace
// | aiProcess_FixInfacingNormals)
// & ~aiProcess_RemoveRedundantMaterials);
//aiSetImportPropertyInteger(props, AI_CONFIG_GLOB_MEASURE_TIME, 1);
//aiSetImportPropertyFloat(props, AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE, 80.f);
//aiSetImportPropertyInteger(props,AI_CONFIG_PP_PTV_KEEP_HIERARCHY,1);
struct aiLogStream shapeLog;
shapeLog = aiGetPredefinedLogStream(aiDefaultLogStream_FILE, "assimp.log");
struct aiLogStream shapeLog = aiGetPredefinedLogStream(aiDefaultLogStream_STDOUT, NULL);
shapeLog.callback = assimpLogCallback;
shapeLog.user = 0;
aiAttachLogStream(&shapeLog);
#ifdef TORQUE_DEBUG
aiEnableVerboseLogging(true);
#endif
//c = aiGetPredefinedLogStream(aiDefaultLogStream_STDOUT, NULL);
//aiAttachLogStream(&c);
// Attempt to import with Assimp.
//mScene = importer.ReadFile(shapePath.getFullPath().c_str(), (aiProcessPreset_TargetRealtime_Quality | aiProcess_FlipWindingOrder | aiProcess_FlipUVs | aiProcess_CalcTangentSpace)
// & ~aiProcess_RemoveRedundantMaterials);
mScene = (aiScene*)aiImportFileExWithProperties(shapePath.getFullPath().c_str(), ppsteps, NULL, props);
aiReleasePropertyStore(props);
@ -200,11 +175,38 @@ void AssimpShapeLoader::enumerateScene()
Con::printf("[ASSIMP] Mesh Count: %d", mScene->mNumMeshes);
Con::printf("[ASSIMP] Material Count: %d", mScene->mNumMaterials);
// Set import options (if they are not set to override)
if (ColladaUtils::getOptions().unit <= 0.0f)
{
F64 unit;
if (!getMetaDouble("UnitScaleFactor", unit))
{
F32 floatVal;
S32 intVal;
if (getMetaFloat("UnitScaleFactor", floatVal))
unit = (F64)floatVal;
else if (getMetaInt("UnitScaleFactor", intVal))
unit = (F64)intVal;
else
unit = 1.0;
}
ColladaUtils::getOptions().unit = (F32)unit;
}
if (ColladaUtils::getOptions().upAxis == UPAXISTYPE_COUNT)
{
S32 upAxis;
if (!getMetaInt("UpAxis", upAxis))
upAxis = UPAXISTYPE_Z_UP;
ColladaUtils::getOptions().upAxis = (domUpAxisType) upAxis;
}
// Extract embedded textures
for (U32 i = 0; i < mScene->mNumTextures; ++i)
extractTexture(i, mScene->mTextures[i]);
// Load all the materials.
AssimpAppMaterial::sDefaultMatNumber = 0;
for ( U32 i = 0; i < mScene->mNumMaterials; i++ )
AppMesh::appMaterials.push_back(new AssimpAppMaterial(mScene->mMaterials[i]));
@ -245,8 +247,8 @@ void AssimpShapeLoader::computeBounds(Box3F& bounds)
TSShapeLoader::computeBounds(bounds);
// Check if the model origin needs adjusting
bool adjustCenter = Con::getBoolVariable("$Assimp::adjustCenter", false); //ColladaUtils::getOptions().adjustCenter
bool adjustFloor = Con::getBoolVariable("$Assimp::adjustFloor", false); //ColladaUtils::getOptions().adjustFloor
bool adjustCenter = ColladaUtils::getOptions().adjustCenter;
bool adjustFloor = ColladaUtils::getOptions().adjustFloor;
if (bounds.isValidBox() && (adjustCenter || adjustFloor))
{
// Compute shape offset
@ -289,6 +291,126 @@ void AssimpShapeLoader::computeBounds(Box3F& bounds)
}
}
bool AssimpShapeLoader::fillGuiTreeView(const char* sourceShapePath, GuiTreeViewCtrl* tree)
{
Assimp::Importer importer;
Torque::Path path(sourceShapePath);
String cleanFile = AppMaterial::cleanString(path.getFileName());
// Attempt to import with Assimp.
const aiScene* shapeScene = importer.ReadFile(path.getFullPath().c_str(), (aiProcessPreset_TargetRealtime_Quality | aiProcess_CalcTangentSpace)
& ~aiProcess_RemoveRedundantMaterials & ~aiProcess_GenSmoothNormals);
if (!shapeScene)
return false;
mScene = shapeScene;
// Initialize tree
tree->removeItem(0);
S32 meshItem = tree->insertItem(0, "Meshes", String::ToString("%i", shapeScene->mNumMeshes));
S32 matItem = tree->insertItem(0, "Materials", String::ToString("%i", shapeScene->mNumMaterials));
S32 animItem = tree->insertItem(0, "Animations", String::ToString("%i", shapeScene->mNumAnimations));
//S32 lightsItem = tree->insertItem(0, "Lights", String::ToString("%i", shapeScene->mNumLights));
//S32 texturesItem = tree->insertItem(0, "Textures", String::ToString("%i", shapeScene->mNumTextures));
//Details!
U32 numPolys = 0;
U32 numVerts = 0;
for (U32 i = 0; i < shapeScene->mNumMeshes; i++)
{
tree->insertItem(meshItem, String::ToString("%s", shapeScene->mMeshes[i]->mName.C_Str()));
numPolys += shapeScene->mMeshes[i]->mNumFaces;
numVerts += shapeScene->mMeshes[i]->mNumVertices;
}
U32 defaultMatNumber = 0;
for (U32 i = 0; i < shapeScene->mNumMaterials; i++)
{
aiMaterial* aiMat = shapeScene->mMaterials[i];
aiString matName;
aiMat->Get(AI_MATKEY_NAME, matName);
String name = matName.C_Str();
if (name.isEmpty())
{
name = AppMaterial::cleanString(path.getFileName());
name += "_defMat";
name += String::ToString("%d", defaultMatNumber);
defaultMatNumber++;
}
aiString texPath;
aiMat->GetTexture(aiTextureType::aiTextureType_DIFFUSE, 0, &texPath);
String texName = texPath.C_Str();
if (texName.isEmpty())
{
aiColor3D read_color(1.f, 1.f, 1.f);
if (AI_SUCCESS == aiMat->Get(AI_MATKEY_COLOR_DIFFUSE, read_color))
texName = String::ToString("Color: (%0.3f, %0.3f, %0.3f)", (F32)read_color.r, (F32)read_color.g, (F32)read_color.b);
else
texName = "No Texture";
}
else
texName = AssimpAppMaterial::cleanTextureName(texName, cleanFile, sourceShapePath, true);
tree->insertItem(matItem, String::ToString("%s", name.c_str()), String::ToString("%s", texName.c_str()));
}
for (U32 i = 0; i < shapeScene->mNumAnimations; i++)
{
String sequenceName = shapeScene->mAnimations[i]->mName.C_Str();
if (sequenceName.isEmpty())
sequenceName = "ambient";
tree->insertItem(animItem, sequenceName.c_str());
}
U32 numNodes = 0;
if (shapeScene->mRootNode)
{
S32 nodesItem = tree->insertItem(0, "Nodes", "");
addNodeToTree(nodesItem, shapeScene->mRootNode, tree, numNodes);
tree->setItemValue(nodesItem, String::ToString("%i", numNodes));
}
U32 numMetaTags = shapeScene->mMetaData ? shapeScene->mMetaData->mNumProperties : 0;
if (numMetaTags)
addMetaDataToTree(shapeScene->mMetaData, tree);
F64 unit;
if (!getMetaDouble("UnitScaleFactor", unit))
unit = 1.0f;
S32 upAxis;
if (!getMetaInt("UpAxis", upAxis))
upAxis = UPAXISTYPE_Z_UP;
/*for (U32 i = 0; i < shapeScene->mNumLights; i++)
{
treeObj->insertItem(lightsItem, String::ToString("%s", shapeScene->mLights[i]->mType));
}*/
// Store shape information in the tree control
tree->setDataField(StringTable->insert("_nodeCount"), 0, avar("%d", numNodes));
tree->setDataField(StringTable->insert("_meshCount"), 0, avar("%d", shapeScene->mNumMeshes));
tree->setDataField(StringTable->insert("_polygonCount"), 0, avar("%d", numPolys));
tree->setDataField(StringTable->insert("_materialCount"), 0, avar("%d", shapeScene->mNumMaterials));
tree->setDataField(StringTable->insert("_lightCount"), 0, avar("%d", shapeScene->mNumLights));
tree->setDataField(StringTable->insert("_animCount"), 0, avar("%d", shapeScene->mNumAnimations));
tree->setDataField(StringTable->insert("_textureCount"), 0, avar("%d", shapeScene->mNumTextures));
tree->setDataField(StringTable->insert("_vertCount"), 0, avar("%d", numVerts));
tree->setDataField(StringTable->insert("_metaTagCount"), 0, avar("%d", numMetaTags));
tree->setDataField(StringTable->insert("_unit"), 0, avar("%g", (F32)unit));
if (upAxis == UPAXISTYPE_X_UP)
tree->setDataField(StringTable->insert("_upAxis"), 0, "X_AXIS");
else if (upAxis == UPAXISTYPE_Y_UP)
tree->setDataField(StringTable->insert("_upAxis"), 0, "Y_AXIS");
else
tree->setDataField(StringTable->insert("_upAxis"), 0, "Z_AXIS");
return true;
}
void AssimpShapeLoader::updateMaterialsScript(const Torque::Path &path)
{
Torque::Path scriptPath(path);
@ -306,7 +428,7 @@ void AssimpShapeLoader::updateMaterialsScript(const Torque::Path &path)
if ( Sim::findObject( MATMGR->getMapEntry( mat->getName() ), mappedMat ) )
{
// Only update existing materials if forced to
if (Con::getBoolVariable("$Assimp::ForceUpdateMats", false))
if (ColladaUtils::getOptions().forceUpdateMaterials)
{
mat->initMaterial(scriptPath, mappedMat);
persistMgr.setDirty(mappedMat);
@ -351,20 +473,37 @@ bool AssimpShapeLoader::canLoadCachedDTS(const Torque::Path& path)
return false;
}
void AssimpShapeLoader::assimpLogCallback(const char* message, char* user)
{
Con::printf("[Assimp log message] %s", StringUnit::getUnit(message, 0, "\n"));
}
bool AssimpShapeLoader::ignoreNode(const String& name)
{
// Do not add AssimpFbx dummy nodes to the TSShape. See: Assimp::FBX::ImportSettings::preservePivots
// https://github.com/assimp/assimp/blob/master/code/FBXImportSettings.h#L116-L135
if (name.find("_$AssimpFbx$_") != String::NPos)
return true;
return false;
if (FindMatch::isMatchMultipleExprs(ColladaUtils::getOptions().alwaysImport, name, false))
return false;
return FindMatch::isMatchMultipleExprs(ColladaUtils::getOptions().neverImport, name, false);
}
bool AssimpShapeLoader::ignoreMesh(const String& name)
{
if (FindMatch::isMatchMultipleExprs(ColladaUtils::getOptions().alwaysImportMesh, name, false))
return false;
else
return FindMatch::isMatchMultipleExprs(ColladaUtils::getOptions().neverImportMesh, name, false);
}
void AssimpShapeLoader::detectDetails()
{
// Set LOD option
bool singleDetail = true;
switch (Con::getIntVariable("$Assimp::lodType", 0))
switch (ColladaUtils::getOptions().lodType)
{
case ColladaUtils::ImportOptions::DetectDTS:
// Check for a baseXX->startXX hierarchy at the top-level, if we find
@ -395,7 +534,7 @@ void AssimpShapeLoader::detectDetails()
break;
}
AssimpAppMesh::fixDetailSize(singleDetail, Con::getIntVariable("$Assimp::singleDetailSize", 2));
AssimpAppMesh::fixDetailSize(singleDetail, ColladaUtils::getOptions().singleDetailSize);
}
void AssimpShapeLoader::extractTexture(U32 index, aiTexture* pTex)
@ -448,6 +587,148 @@ void AssimpShapeLoader::extractTexture(U32 index, aiTexture* pTex)
}
}
void AssimpShapeLoader::addNodeToTree(S32 parentItem, aiNode* node, GuiTreeViewCtrl* tree, U32& nodeCount)
{
// Add this node
S32 nodeItem = parentItem;
String nodeName = node->mName.C_Str();
if (!ignoreNode(nodeName))
{
if (nodeName.isEmpty())
nodeName = "null";
nodeItem = tree->insertItem(parentItem, nodeName.c_str(), String::ToString("%i", node->mNumChildren));
nodeCount++;
}
// Add any child nodes
for (U32 n = 0; n < node->mNumChildren; ++n)
addNodeToTree(nodeItem, node->mChildren[n], tree, nodeCount);
}
void AssimpShapeLoader::addMetaDataToTree(const aiMetadata* metaData, GuiTreeViewCtrl* tree)
{
S32 metaItem = tree->insertItem(0, "MetaData", String::ToString("%i", metaData->mNumProperties));
aiString valString;
aiVector3D valVec;
for (U32 n = 0; n < metaData->mNumProperties; ++n)
{
String keyStr = metaData->mKeys[n].C_Str();
keyStr += ": ";
switch (metaData->mValues[n].mType)
{
case AI_BOOL:
keyStr += ((bool)metaData->mValues[n].mData) ? "true" : "false";
break;
case AI_INT32:
keyStr += String::ToString(*((S32*)(metaData->mValues[n].mData)));
break;
case AI_UINT64:
keyStr += String::ToString("%I64u", *((U64*)metaData->mValues[n].mData));
break;
case AI_FLOAT:
keyStr += String::ToString(*((F32*)metaData->mValues[n].mData));
break;
case AI_DOUBLE:
keyStr += String::ToString(*((F64*)metaData->mValues[n].mData));
break;
case AI_AISTRING:
metaData->Get<aiString>(metaData->mKeys[n], valString);
keyStr += valString.C_Str();
break;
case AI_AIVECTOR3D:
metaData->Get<aiVector3D>(metaData->mKeys[n], valVec);
keyStr += String::ToString("%f, %f, %f", valVec.x, valVec.y, valVec.z);
break;
default:
break;
}
tree->insertItem(metaItem, keyStr.c_str(), String::ToString("%i", n));
}
}
bool AssimpShapeLoader::getMetabool(const char* key, bool& boolVal)
{
if (!mScene || !mScene->mMetaData)
return false;
String keyStr = key;
for (U32 n = 0; n < mScene->mMetaData->mNumProperties; ++n)
{
if (keyStr.equal(mScene->mMetaData->mKeys[n].C_Str(), String::NoCase))
{
if (mScene->mMetaData->mValues[n].mType == AI_BOOL)
{
boolVal = (bool)mScene->mMetaData->mValues[n].mData;
return true;
}
}
}
return false;
}
bool AssimpShapeLoader::getMetaInt(const char* key, S32& intVal)
{
if (!mScene || !mScene->mMetaData)
return false;
String keyStr = key;
for (U32 n = 0; n < mScene->mMetaData->mNumProperties; ++n)
{
if (keyStr.equal(mScene->mMetaData->mKeys[n].C_Str(), String::NoCase))
{
if (mScene->mMetaData->mValues[n].mType == AI_INT32)
{
intVal = *((S32*)(mScene->mMetaData->mValues[n].mData));
return true;
}
}
}
return false;
}
bool AssimpShapeLoader::getMetaFloat(const char* key, F32& floatVal)
{
if (!mScene || !mScene->mMetaData)
return false;
String keyStr = key;
for (U32 n = 0; n < mScene->mMetaData->mNumProperties; ++n)
{
if (keyStr.equal(mScene->mMetaData->mKeys[n].C_Str(), String::NoCase))
{
if (mScene->mMetaData->mValues[n].mType == AI_FLOAT)
{
floatVal = *((F32*)mScene->mMetaData->mValues[n].mData);
return true;
}
}
}
return false;
}
bool AssimpShapeLoader::getMetaDouble(const char* key, F64& doubleVal)
{
if (!mScene || !mScene->mMetaData)
return false;
String keyStr = key;
for (U32 n = 0; n < mScene->mMetaData->mNumProperties; ++n)
{
if (keyStr.equal(mScene->mMetaData->mKeys[n].C_Str(), String::NoCase))
{
if (mScene->mMetaData->mValues[n].mType == AI_DOUBLE)
{
doubleVal = *((F64*)mScene->mMetaData->mValues[n].mData);
return true;
}
}
}
return false;
}
//-----------------------------------------------------------------------------
/// This function is invoked by the resource manager based on file extension.
TSShape* assimpLoadShape(const Torque::Path &path)
@ -489,6 +770,14 @@ TSShape* assimpLoadShape(const Torque::Path &path)
return NULL;
}
// Allow TSShapeConstructor object to override properties
ColladaUtils::getOptions().reset();
TSShapeConstructor* tscon = TSShapeConstructor::findShapeConstructor(path.getFullPath());
if (tscon)
{
ColladaUtils::getOptions() = tscon->mOptions;
}
AssimpShapeLoader loader;
TSShape* tss = loader.generateShape(path);
if (tss)
@ -510,57 +799,30 @@ TSShape* assimpLoadShape(const Torque::Path &path)
return tss;
}
DefineEngineFunction(GetShapeInfo, GuiTreeViewCtrl*, (String filePath), ,
"Returns a list of supported shape formats in filter form.\n"
"Example output: DSQ Files|*.dsq|COLLADA Files|*.dae|")
DefineEngineFunction(GetShapeInfo, bool, (const char* shapePath, const char* ctrl), ,
"(string shapePath, GuiTreeViewCtrl ctrl) Collect scene information from "
"a shape file and store it in a GuiTreeView control. This function is "
"used by the assimp import gui to show a preview of the scene contents "
"prior to import, and is probably not much use for anything else.\n"
"@param shapePath shape filename\n"
"@param ctrl GuiTreeView control to add elements to\n"
"@return true if successful, false otherwise\n"
"@ingroup Editors\n"
"@internal")
{
Assimp::Importer importer;
GuiTreeViewCtrl* treeObj = new GuiTreeViewCtrl();
treeObj->registerObject();
Torque::Path path = Torque::Path(filePath);
// Attempt to import with Assimp.
const aiScene* shapeScene = importer.ReadFile(path.getFullPath().c_str(), (aiProcessPreset_TargetRealtime_Quality | aiProcess_CalcTangentSpace)
& ~aiProcess_RemoveRedundantMaterials & ~aiProcess_GenSmoothNormals);
//Populate info
S32 meshItem = treeObj->insertItem(0, "Shape", String::ToString("%i", shapeScene->mNumMeshes));
S32 matItem = treeObj->insertItem(0, "Materials", String::ToString("%i", shapeScene->mNumMaterials));
S32 animItem = treeObj->insertItem(0, "Animations", String::ToString("%i", shapeScene->mNumAnimations));
S32 lightsItem = treeObj->insertItem(0, "Lights", String::ToString("%i", shapeScene->mNumLights));
S32 texturesItem = treeObj->insertItem(0, "Textures", String::ToString("%i", shapeScene->mNumTextures));
//S32 meshItem = ->insertItem(0, "Cameras", String::ToString("%s", shapeScene->mNumCameras));
//Details!
for (U32 i = 0; i < shapeScene->mNumMeshes; i++)
GuiTreeViewCtrl* tree;
if (!Sim::findObject(ctrl, tree))
{
treeObj->insertItem(meshItem, String::ToString("%s", shapeScene->mMeshes[i]->mName.C_Str()));
Con::errorf("enumColladaScene::Could not find GuiTreeViewCtrl '%s'", ctrl);
return false;
}
for (U32 i = 0; i < shapeScene->mNumMaterials; i++)
{
aiMaterial* aiMat = shapeScene->mMaterials[i];
// Check if a cached DTS is available => no need to import the source file
// if we can load the DTS instead
Torque::Path path(shapePath);
if (AssimpShapeLoader::canLoadCachedDTS(path))
return false;
aiString matName;
aiMat->Get(AI_MATKEY_NAME, matName);
aiString texPath;
aiMat->GetTexture(aiTextureType::aiTextureType_DIFFUSE, 0, &texPath);
treeObj->insertItem(matItem, String::ToString("%s", matName.C_Str()), String::ToString("%s", texPath.C_Str()));
}
for (U32 i = 0; i < shapeScene->mNumAnimations; i++)
{
treeObj->insertItem(animItem, String::ToString("%s", shapeScene->mAnimations[i]->mName.C_Str()));
}
/*for (U32 i = 0; i < shapeScene->mNumLights; i++)
{
treeObj->insertItem(lightsItem, String::ToString("%s", shapeScene->mLights[i]->mType));
}*/
return treeObj;
}
AssimpShapeLoader loader;
return loader.fillGuiTreeView(shapePath, tree);
}

View file

@ -28,6 +28,9 @@
#endif
#include <assimp/texture.h>
class GuiTreeViewCtrl;
struct aiNode;
struct aiMetadata;
//-----------------------------------------------------------------------------
class AssimpShapeLoader : public TSShapeLoader
{
@ -37,9 +40,18 @@ protected:
const struct aiScene* mScene;
virtual bool ignoreNode(const String& name);
virtual bool ignoreMesh(const String& name);
void detectDetails();
void extractTexture(U32 index, aiTexture* pTex);
private:
void addNodeToTree(S32 parentItem, aiNode* node, GuiTreeViewCtrl* tree, U32& nodeCount);
void addMetaDataToTree(const aiMetadata* metaData, GuiTreeViewCtrl* tree);
bool getMetabool(const char* key, bool& boolVal);
bool getMetaInt(const char* key, S32& intVal);
bool getMetaFloat(const char* key, F32& floatVal);
bool getMetaDouble(const char* key, F64& doubleVal);
public:
AssimpShapeLoader();
~AssimpShapeLoader();
@ -51,7 +63,10 @@ public:
void computeBounds(Box3F& bounds);
bool fillGuiTreeView(const char* shapePath, GuiTreeViewCtrl* tree);
static bool canLoadCachedDTS(const Torque::Path& path);
static void assimpLogCallback(const char* message, char* user);
};
#endif // _ASSIMP_SHAPELOADER_H_

View file

@ -81,6 +81,13 @@ namespace ColladaUtils
NumLodTypes
};
enum eAnimTimingType
{
FrameCount = 0,
Seconds = 1,
Milliseconds = 1000
};
domUpAxisType upAxis; // Override for the collada <up_axis> element
F32 unit; // Override for the collada <unit> element
eLodType lodType; // LOD type option
@ -97,6 +104,22 @@ namespace ColladaUtils
bool forceUpdateMaterials; // Force update of materials.cs
bool useDiffuseNames; // Use diffuse texture as the material name
// Assimp specific preprocess import options
bool convertLeftHanded; // Convert to left handed coordinate system.
bool calcTangentSpace; // Calculate tangents and bitangents, if possible.
bool genUVCoords; // Convert spherical, cylindrical, box and planar mapping to proper UVs.
bool transformUVCoords; // Preprocess UV transformations (scaling, translation ...)
bool flipUVCoords; // This step flips all UV coordinates along the y-axis and adjusts material settings
// and bitangents accordingly.\nAssimp uses TL(0,0):BR(1,1). T3D uses TL(0,1):BR(1,0).
bool findInstances; // Search for instanced meshes and remove them by references to one master.
bool limitBoneWeights; // Limit bone weights to 4 per vertex.
bool joinIdenticalVerts; // Identifies and joins identical vertex data sets within all imported meshes.
bool reverseWindingOrder; // This step adjusts the output face winding order to be clockwise. The default face winding order is counter clockwise.
bool invertNormals; // Reverse the normal vector direction for all normals.
bool removeRedundantMats; // Removes redundant materials.
eAnimTimingType animTiming; // How to import timing data as frames, seconds or milliseconds
S32 animFPS; // FPS value to use if timing is set in frames and the animations does not have an fps set
ImportOptions()
{
reset();
@ -119,6 +142,20 @@ namespace ColladaUtils
adjustFloor = false;
forceUpdateMaterials = false;
useDiffuseNames = false;
convertLeftHanded = false;
calcTangentSpace = false;
genUVCoords = false;
transformUVCoords = false;
flipUVCoords = true;
findInstances = false;
limitBoneWeights = false;
joinIdenticalVerts = true;
reverseWindingOrder = true;
invertNormals = false;
removeRedundantMats = true;
animTiming = Seconds;
animFPS = 30;
}
};

View file

@ -71,6 +71,14 @@ ImplementEnumType( TSShapeConstructorLodType,
{ ColladaUtils::ImportOptions::TrailingNumber, "TrailingNumber" },
EndImplementEnumType;
ImplementEnumType(TSShapeConstructorAnimType,
"\n\n"
"@ingroup TSShapeConstructor" )
{ ColladaUtils::ImportOptions::FrameCount, "Frames" },
{ ColladaUtils::ImportOptions::Seconds, "Seconds" },
{ ColladaUtils::ImportOptions::Milliseconds, "Milliseconds" },
EndImplementEnumType;
//-----------------------------------------------------------------------------
@ -150,6 +158,21 @@ TSShapeConstructor::TSShapeConstructor()
mOptions.adjustFloor = false;
mOptions.forceUpdateMaterials = false;
mOptions.useDiffuseNames = false;
mOptions.convertLeftHanded = false;
mOptions.calcTangentSpace = false;
mOptions.genUVCoords = false;
mOptions.transformUVCoords = false;
mOptions.flipUVCoords = true;
mOptions.findInstances = false;
mOptions.limitBoneWeights = false;
mOptions.joinIdenticalVerts = true;
mOptions.reverseWindingOrder = true;
mOptions.invertNormals = false;
mOptions.removeRedundantMats = true;
mOptions.animTiming = ColladaUtils::ImportOptions::Seconds;
mOptions.animFPS = 30;
mShape = NULL;
}
@ -292,6 +315,35 @@ void TSShapeConstructor::initPersistFields()
"Forces update of the materials.cs file in the same folder as the COLLADA "
"(.dae) file, even if Materials already exist. No effect for DTS files.\n"
"Normally only Materials that are not already defined are written to materials.cs." );
// Fields added for assimp options
addField( "convertLeftHanded", TypeBool, Offset(mOptions.convertLeftHanded, TSShapeConstructor),
"Convert to left handed coordinate system." );
addField( "calcTangentSpace", TypeBool, Offset(mOptions.calcTangentSpace, TSShapeConstructor),
"Calculate tangents and bitangents, if possible." );
addField( "genUVCoords", TypeBool, Offset(mOptions.genUVCoords, TSShapeConstructor),
"Convert spherical, cylindrical, box and planar mapping to proper UVs." );
addField( "transformUVCoords", TypeBool, Offset(mOptions.transformUVCoords, TSShapeConstructor),
"Preprocess UV transformations (scaling, translation ...)." );
addField( "flipUVCoords", TypeBool, Offset(mOptions.flipUVCoords, TSShapeConstructor),
"This step flips all UV coordinates along the y-axis and adjusts material settings and bitangents accordingly.\n"
"Assimp uses TL(0,0):BR(1,1). T3D uses TL(0,1):BR(1,0). This will be needed for most textured models." );
addField( "findInstances", TypeBool, Offset(mOptions.findInstances, TSShapeConstructor),
"Search for instanced meshes and remove them by references to one master." );
addField( "limitBoneWeights", TypeBool, Offset(mOptions.limitBoneWeights, TSShapeConstructor),
"Limit bone weights to 4 per vertex." );
addField( "joinIdenticalVerts", TypeBool, Offset(mOptions.joinIdenticalVerts, TSShapeConstructor),
"Identifies and joins identical vertex data sets within all imported meshes." );
addField( "reverseWindingOrder", TypeBool, Offset(mOptions.reverseWindingOrder, TSShapeConstructor),
"This step adjusts the output face winding order to be clockwise. The default assimp face winding order is counter clockwise." );
addField( "invertNormals", TypeBool, Offset(mOptions.invertNormals, TSShapeConstructor),
"Reverse the normal vector direction for all normals." );
addField( "removeRedundantMats", TypeBool, Offset(mOptions.removeRedundantMats, TSShapeConstructor),
"Removes redundant materials." );
addField( "animTiming", TYPEID< ColladaUtils::ImportOptions::eAnimTimingType >(), Offset(mOptions.animTiming, TSShapeConstructor),
"How to import timing data as frames, seconds or milliseconds." );
addField("animFPS", TypeS32, Offset(mOptions.animFPS, TSShapeConstructor),
"FPS value to use if timing is set in frames and the animations does not have an fps set.");
endGroup( "Collada" );
addGroup( "Sequences" );

View file

@ -328,9 +328,11 @@ public:
typedef domUpAxisType TSShapeConstructorUpAxis;
typedef ColladaUtils::ImportOptions::eLodType TSShapeConstructorLodType;
typedef ColladaUtils::ImportOptions::eAnimTimingType TSShapeConstructorAnimType;
DefineEnumType( TSShapeConstructorUpAxis );
DefineEnumType(TSShapeConstructorLodType);
DefineEnumType(TSShapeConstructorAnimType);
class TSShapeConstructorMethodActionCallback
{

View file

@ -0,0 +1,29 @@
SISV1
lodType SingleSize
singleDetailSize 2
materialPrefix
alwaysImport
neverImport
alwaysImportMesh
neverImportMesh
upAxis Y_AXIS
scale 1
animTiming Milliseconds
animFPS 30
overrideUpAxis 1
overrideScale 0
ignoreNodeScale 0
adjustCenter 0
adjustFloor 0
forceUpdateMaterials 0
convertLeftHanded 0
calcTangentSpace 0
removeRedundantMats 1
genUVCoords 0
transformUVCoords 0
flipUVCoords 1
findInstances 0
limitBoneWeights 0
joinIdenticalVerts 1
reverseWindingOrder 1
invertNormals 0

View file

@ -0,0 +1,29 @@
SISV1
lodType SingleSize
singleDetailSize 2
materialPrefix
alwaysImport
neverImport
alwaysImportMesh
neverImportMesh
upAxis Y_AXIS
scale 1
animTiming Milliseconds
animFPS 30
overrideUpAxis 1
overrideScale 0
ignoreNodeScale 0
adjustCenter 0
adjustFloor 0
forceUpdateMaterials 0
convertLeftHanded 0
calcTangentSpace 0
removeRedundantMats 1
genUVCoords 0
transformUVCoords 0
flipUVCoords 1
findInstances 0
limitBoneWeights 0
joinIdenticalVerts 1
reverseWindingOrder 1
invertNormals 0

View file

@ -0,0 +1,540 @@
//------------------------------------------------------------------------------
// Fields that will be saved to settings
$Assimp::textFields = "lodType" TAB "singleDetailSize" TAB "materialPrefix" TAB
"alwaysImport" TAB "neverImport" TAB "alwaysImportMesh" TAB "neverImportMesh"
TAB "upAxis" TAB "scale" TAB "animTiming" TAB "animFPS";
$Assimp::checkboxFields = "overrideUpAxis" TAB "overrideScale" TAB "ignoreNodeScale"
TAB "adjustCenter" TAB "adjustFloor" TAB "forceUpdateMaterials" TAB "convertLeftHanded"
TAB "calcTangentSpace" TAB "removeRedundantMats" TAB "genUVCoords" TAB
"transformUVCoords" TAB "flipUVCoords" TAB "findInstances" TAB "limitBoneWeights"
TAB "joinIdenticalVerts" TAB "reverseWindingOrder" TAB "invertNormals";
//------------------------------------------------------------------------------
function ShapeImportTreeView::refresh(%this, %what)
{
%shapeRoot = %this.getFirstRootItem();
%materialsRoot = %this.getNextSibling(%shapeRoot);
%animRoot = %this.getNextSibling(%materialsRoot);
// Refresh nodes
if ((%what $= "all") || (%what $= "nodes"))
{
// Indicate whether nodes will be ignored on import
%this._alwaysImport = strreplace(AssimpImportDlg-->alwaysImport.getText(), ";", "\t");
%this._neverImport = strreplace(AssimpImportDlg-->neverImport.getText(), ";", "\t");
%this._alwaysImportMesh = strreplace(AssimpImportDlg-->alwaysImportMesh.getText(), ";", "\t");
%this._neverImportMesh = strreplace(AssimpImportDlg-->neverImportMesh.getText(), ";", "\t");
%this.refreshNode(%this.getChild(%shapeRoot));
}
// Refresh materials
if ((%what $= "all") || (%what $= "materials"))
{
%matPrefix = AssimpImportDlg-->materialPrefix.getText();
%id = %this.getChild(%materialsRoot);
while (%id > 0)
{
%baseName = %this.getItemValue(%id);
%name = %matPrefix @ %baseName;
// Indicate whether material name is already mapped
%this.editItem(%id, %name, %baseName);
%mapped = getMaterialMapping(%name);
if (%mapped $= "")
{
%this.setItemTooltip(%id, "A new material will be mapped to this name");
%this.setItemImages(%id, %this._imageMaterial, %this._imageMaterial);
}
else
{
%this.setItemTooltip(%id, %mapped SPC "is already mapped to this material name");
%this.setItemImages(%id, %this._imageExMaterial, %this._imageExMaterial);
}
%id = %this.getNextSibling(%id);
}
}
// Refresh animations
if ((%what $= "all") || (%what $= "animations"))
{
%id = %this.getChild(%animRoot);
while (%id > 0)
{
%this.setItemImages(%id, %this._imageAnim, %this._imageAnim);
%id = %this.getNextSibling(%id);
}
}
}
function ShapeImportTreeView::refreshNode(%this, %id)
{
while (%id > 0)
{
switch$ (%this.getItemValue(%id))
{
case "mesh":
// Check if this mesh will be ignored on import
if (strIsMatchMultipleExpr(%this._alwaysImportMesh, %this.getItemText(%id)) ||
!strIsMatchMultipleExpr(%this._neverImportMesh, %this.getItemText(%id)) )
{
%this.setItemTooltip(%id, "");
%this.setItemImages(%id, %this._imageMesh, %this._imageMesh);
}
else
{
%this.setItemTooltip(%id, "This mesh will be ignored on import");
%this.setItemImages(%id, %this._imageExNode, %this._imageExNode);
}
case "light":
%this.setItemImages(%id, %this._imageLight, %this._imageLight);
case "node":
// Check if this node will be ignored on import
if (strIsMatchMultipleExpr(%this._alwaysImport, %this.getItemText(%id)) ||
!strIsMatchMultipleExpr(%this._neverImport, %this.getItemText(%id)) )
{
%this.setItemTooltip(%id, "");
%this.setItemImages(%id, %this._imageNode, %this._imageNode);
}
else
{
%this.setItemTooltip(%id, "This node will be ignored on import");
%this.setItemImages(%id, %this._imageExNode, %this._imageExNode);
}
}
// recurse through children and siblings
%this.refreshNode(%this.getChild(%id));
%id = %this.getNextSibling(%id);
}
}
function ShapeImportTreeView::onDefineIcons(%this)
{
// Set the tree view icon indices and texture paths
%this._imageNone = 0;
%this._imageNode = 1;
%this._imageMesh = 2;
%this._imageMaterial = 3;
%this._imageLight = 4;
%this._imageAnimation = 5;
%this._imageExNode = 6;
%this._imageExMaterial = 7;
%icons = ":" @ // no icon
"tools/gui/images/ColladaImport/iconNode:" @ // normal node
"tools/gui/images/ColladaImport/iconMesh:" @ // mesh
"tools/gui/images/ColladaImport/iconMaterial:" @ // new material
"tools/gui/images/ColladaImport/iconLight:" @ // light
"tools/gui/images/ColladaImport/iconAnimation:" @ // sequence
"tools/gui/images/ColladaImport/iconIgnoreNode:" @ // ignored node
"tools/gui/images/ColladaImport/iconExistingMaterial"; // existing material
%this.buildIconTable( %icons );
}
function AssimpImportDlg::updateOverrideUpAxis(%this, %override)
{
%this-->overrideUpAxis.setStateOn(%override);
%this-->upAxis.setActive(%override);
if (!%override)
%this-->upAxis.setText(ShapeImportTreeView._upAxis);
}
function AssimpImportDlg::updateOverrideScale(%this, %override)
{
%this-->overrideScale.setStateOn(%override);
%this-->scale.setActive(%override);
if (!%override)
%this-->scale.setText(ShapeImportTreeView._unit);
}
function AssimpImportDlg::initFromConstructor(%this)
{
if (%this.constructor.upAxis !$= "DEFAULT")
{
%this-->upAxis.setText(%this.constructor.upAxis);
%this.updateOverrideUpAxis(true);
}
else
%this.updateOverrideUpAxis(false);
if (%this.constructor.unit > 0)
{
%this-->scale.setText(%this.constructor.unit);
%this.updateOverrideScale(true);
}
else
%this.updateOverrideScale(false);
%this-->lodType.setText(%this.constructor.lodType);
%this-->singleDetailSize.setText(%this.constructor.singleDetailSize);
%this-->materialPrefix.setText(%this.constructor.matNamePrefix);
%this-->alwaysImport.setText(strreplace(%this.constructor.alwaysImport, "\t", ";"));
%this-->neverImport.setText(strreplace(%this.constructor.neverImport, "\t", ";"));
%this-->alwaysImportMesh.setText(strreplace(%this.constructor.alwaysImportMesh, "\t", ";"));
%this-->neverImportMesh.setText(strreplace(%this.constructor.neverImportMesh, "\t", ";"));
%this-->ignoreNodeScale.setStateOn(%this.constructor.ignoreNodeScale);
%this-->adjustCenter.setStateOn(%this.constructor.adjustCenter);
%this-->adjustFloor.setStateOn(%this.constructor.adjustFloor);
%this-->forceUpdateMaterials.setStateOn(%this.constructor.forceUpdateMaterials);
%this-->animTiming.setText(%this.constructor.animTiming);
%this-->animFPS.setText(%this.constructor.animFPS);
%this-->convertLeftHanded.setStateOn(%this.constructor.convertLeftHanded);
%this-->calcTangentSpace.setStateOn(%this.constructor.calcTangentSpace);
%this-->genUVCoords.setStateOn(%this.constructor.genUVCoords);
%this-->transformUVCoords.setStateOn(%this.constructor.transformUVCoords);
%this-->flipUVCoords.setStateOn(%this.constructor.flipUVCoords);
%this-->findInstances.setStateOn(%this.constructor.findInstances);
%this-->limitBoneWeights.setStateOn(%this.constructor.limitBoneWeights);
%this-->joinIdenticalVerts.setStateOn(%this.constructor.joinIdenticalVerts);
%this-->reverseWindingOrder.setStateOn(%this.constructor.reverseWindingOrder);
%this-->invertNormals.setStateOn(%this.constructor.invertNormals);
%this-->removeRedundantMats.setStateOn(%this.constructor.removeRedundantMats);
}
function AssimpImportDlg::initFromDefaults(%this)
{
%this.updateOverrideUpAxis(false);
%this.updateOverrideScale(false);
%this-->lodType.setText("TrailingNumber");
%this-->singleDetailSize.setText("2");
%this-->materialPrefix.setText("");
%this-->alwaysImport.setText("");
%this-->neverImport.setText("");
%this-->alwaysImportMesh.setText("");
%this-->neverImportMesh.setText("");
%this-->ignoreNodeScale.setStateOn(0);
%this-->adjustCenter.setStateOn(0);
%this-->adjustFloor.setStateOn(0);
%this-->forceUpdateMaterials.setStateOn(0);
%this-->animTiming.setText("Seconds");
%this-->animFPS.setText("30");
%this-->convertLeftHanded.setStateOn(0);
%this-->calcTangentSpace.setStateOn(0);
%this-->genUVCoords.setStateOn(0);
%this-->transformUVCoords.setStateOn(0);
%this-->flipUVCoords.setStateOn(1);
%this-->findInstances.setStateOn(0);
%this-->limitBoneWeights.setStateOn(0);
%this-->joinIdenticalVerts.setStateOn(1);
%this-->reverseWindingOrder.setStateOn(1);
%this-->invertNormals.setStateOn(0);
%this-->removeRedundantMats.setStateOn(1);
}
function AssimpImportDlg::saveToConstructor(%this)
{
// Store values from GUI
if (%this-->overrideUpAxis.getValue())
%this.constructor.upAxis = %this-->upAxis.getText();
else
%this.constructor.upAxis = "DEFAULT";
if (%this-->overrideScale.getValue())
%this.constructor.unit = %this-->scale.getText();
else
%this.constructor.unit = -1;
%this.constructor.lodType = %this-->lodType.getText();
%this.constructor.singleDetailSize = %this-->singleDetailSize.getText();
%this.constructor.matNamePrefix = %this-->materialPrefix.getText();
%this.constructor.alwaysImport = strreplace(%this-->alwaysImport.getText(), ";", "\t");
%this.constructor.neverImport = strreplace(%this-->neverImport.getText(), ";", "\t");
%this.constructor.alwaysImportMesh = strreplace(%this-->alwaysImportMesh.getText(), ";", "\t");
%this.constructor.neverImportMesh = strreplace(%this-->neverImportMesh.getText(), ";", "\t");
%this.constructor.ignoreNodeScale = %this-->ignoreNodeScale.getValue();
%this.constructor.adjustCenter = %this-->adjustCenter.getValue();
%this.constructor.adjustFloor = %this-->adjustFloor.getValue();
%this.constructor.forceUpdateMaterials = %this-->forceUpdateMaterials.getValue();
%this.constructor.animTiming = %this-->animTiming.getText();
%this.constructor.animFPS = %this-->animFPS.getText();
%this.constructor.convertLeftHanded = %this-->convertLeftHanded.getValue();
%this.constructor.calcTangentSpace = %this-->calcTangentSpace.getValue();
%this.constructor.genUVCoords = %this-->genUVCoords.getValue();
%this.constructor.transformUVCoords = %this-->transformUVCoords.getValue();
%this.constructor.flipUVCoords = %this-->flipUVCoords.getValue();
%this.constructor.findInstances = %this-->findInstances.getValue();
%this.constructor.limitBoneWeights = %this-->limitBoneWeights.getValue();
%this.constructor.joinIdenticalVerts = %this-->joinIdenticalVerts.getValue();
%this.constructor.reverseWindingOrder = %this-->reverseWindingOrder.getValue();
%this.constructor.invertNormals = %this-->invertNormals.getValue();
%this.constructor.removeRedundantMats = %this-->removeRedundantMats.getValue();
}
function AssimpImportDlg::showDialog(%this, %shapePath, %cmd)
{
%this.settingVersion = 1.0;
%this.path = %shapePath;
%this.cmd = %cmd;
// Check for an existing TSShapeConstructor object. Need to exec the script
// manually as the resource may not have been loaded yet
%csPath = filePath(%this.path) @ "/" @ fileBase(%this.path) @ ".cs";
if (isFile(%csPath))
exec(%csPath);
%this.constructor = ShapeEditor.findConstructor(%this.path);
// Only show the import dialog if required. Note that 'GetShapeInfo' will
// fail if the source file is missing, or a cached.dts is available.
$assimp::forceLoad = EditorSettings.value("forceLoadDAE");
if (!GetShapeInfo(%shapePath, "ShapeImportTreeView"))
{
eval(%cmd);
$assimp::forceLoad = false;
return;
}
$assimp::forceLoad = false;
// Initialise GUI
ShapeImportTreeView.onDefineIcons();
// Window Title
%this-->window.text = "Shape Import:" SPC %this.path;
// Fill Popups
%this-->upAxis.clear();
%this-->upAxis.add("X_AXIS", 1);
%this-->upAxis.add("Y_AXIS", 2);
%this-->upAxis.add("Z_AXIS", 3);
%this-->lodType.clear();
%this-->lodType.add("DetectDTS", 1);
%this-->lodType.add("SingleSize", 2);
%this-->lodType.add("TrailingNumber", 3);
%this-->animTiming.clear();
%this-->animTiming.add("Frames", 0);
%this-->animTiming.add("Seconds", 1);
%this-->animTiming.add("Milliseconds", 1000);
// Set model details
%this-->nodes.setText(ShapeImportTreeView._nodeCount);
%this-->meshes.setText(ShapeImportTreeView._meshCount);
%this-->lights.setText(ShapeImportTreeView._lightCount);
%this-->materials.setText(ShapeImportTreeView._materialCount);
%this-->polygons.setText(ShapeImportTreeView._polygonCount);
%this-->animations.setText(ShapeImportTreeView._animCount);
%this-->textures.setText(ShapeImportTreeView._textureCount);
%this-->vertices.setText(ShapeImportTreeView._vertCount);
%metaText = (ShapeImportTreeView._metaTagCount == 0) ? "No Records" : ShapeImportTreeView._metaTagCount;
%this-->metadata.setText(%metaText);
if (%this.constructor > 0)
%this.initFromConstructor();
else
{
%this.initFromDefaults();
// If there's a default settings file for the file type, load it
%defaultSISPath = EditorSettings.value("defaultSettingsPath", "Tools");
%settingsFile = %defaultSISPath @ "/" @ getSubStr(fileExt(%shapePath),1) @ ".sis";
if (isFile(%settingsFile))
%this.loadSettingsFrom(%settingsFile);
}
Canvas.pushDialog(%this);
ShapeImportTreeView.refresh("all");
}
function AssimpImportDlg::onLoadSettings(%this)
{
%defaultSISPath = EditorSettings.value("defaultSettingsPath", "Tools");
%dlg = new OpenFileDialog()
{
Filters = "Shape Import Settings (*.sis)|*.sis|";
DefaultPath = %defaultSISPath;
DefaultFile = "";
ChangePath = false;
MustExist = true;
};
%ret = %dlg.Execute();
if ( %ret )
%fileName = %dlg.FileName;
%dlg.delete();
if ( !%ret )
return;
%this.loadSettingsFrom(%fileName);
}
function AssimpImportDlg::onSaveSettings(%this)
{
%defaultSISPath = EditorSettings.value("defaultSettingsPath", "Tools");
%dlg = new SaveFileDialog()
{
Filters = "Shape Import Settings (*.sis)|*.sis|";
DefaultPath = %defaultSISPath;
DefaultFile = "";
ChangePath = false;
MustExist = true;
};
%ret = %dlg.Execute();
if ( %ret )
{
%saveFile = %dlg.FileName;
if(fileExt( %saveFile ) !$= ".sis")
%saveFile = %saveFile @ ".sis";
}
%dlg.delete();
if (!%ret)
return;
%this.saveSettingsTo(%saveFile);
}
function AssimpImportDlg::onCancel(%this)
{
Canvas.popDialog(%this);
ShapeImportTreeView.clear();
}
function AssimpImportDlg::onOK(%this)
{
Canvas.popDialog(%this);
ShapeImportTreeView.clear();
if (%this.needsSave())
{
if (!isObject(%this.constructor))
{ // Create a new TSShapeConstructor object
%this.constructor = ShapeEditor.createConstructor(%this.path);
}
}
if (%this.constructor > 0)
{
%this.saveToConstructor();
// Save new settings to file
ShapeEditor.saveConstructor(%this.constructor);
}
// Load the shape (always from the DAE)
$assimp::forceLoad = true;
eval(%this.cmd);
$assimp::forceLoad = false;
}
function AssimpImportDlg::needsSave(%this)
{
if ((%this-->overrideUpAxis.getValue() != 0) ||
(%this-->overrideScale.getValue() != 0) ||
(%this-->lodType.getText() !$= "DetectDTS") ||
(%this-->singleDetailSize.getText() !$= "2") ||
(%this-->materialPrefix.getText() !$= "") ||
(%this-->alwaysImport.getText() !$= "") ||
(%this-->neverImport.getText() !$= "") ||
(%this-->alwaysImportMesh.getText() !$= "") ||
(%this-->neverImportMesh.getText() !$= "") ||
(%this-->ignoreNodeScale.getValue() != 0) ||
(%this-->adjustCenter.getValue() != 0) ||
(%this-->adjustFloor.getValue() != 0) ||
(%this-->forceUpdateMaterials.getValue() != 0))
return true;
if ((%this-->animTiming.getText() !$= "Seconds") ||
(%this-->animFPS.getText() !$= "30") ||
(%this-->convertLeftHanded.getValue() != 0) ||
(%this-->calcTangentSpace.getValue() != 0) ||
(%this-->genUVCoords.getValue() != 0) ||
(%this-->transformUVCoords.getValue() != 0) ||
(%this-->flipUVCoords.getValue() != 1) ||
(%this-->findInstances.getValue() != 0) ||
(%this-->limitBoneWeights.getValue() != 0) ||
(%this-->joinIdenticalVerts.getValue() != 1) ||
(%this-->reverseWindingOrder.getValue() != 1) ||
(%this-->invertNormals.getValue() != 0) ||
(%this-->removeRedundantMats.getValue() != 1))
return true;
return false;
}
function AssimpImportDlg::loadSettingsFrom(%this, %filename)
{
%fileObj = new FileObject();
if (!%fileObj.OpenForRead(%fileName))
{
error("Error opening file to write settings (" @ %fileName @ ").");
%fileObj.delete();
return;
}
%line = %fileObj.ReadLine();
if (getSubStr(%line, 0, 4) !$= "SISV")
return; // ? not sis file
while( !%fileObj.isEOF() )
{
%line = %fileObj.ReadLine();
%key = getField(%line, 0);
%data = getFields(%line, 1);
%ctrl = %this.findObjectByInternalName(%key, true);
if (isObject(%ctrl))
{
%name = %ctrl.getClassName();
if (%ctrl.getClassName() $= "GuiCheckBoxCtrl")
%ctrl.setStateOn(%data);
else
%ctrl.setText(%data);
}
}
%this.updateOverrideUpAxis(%this-->overrideUpAxis.getValue());
%this.updateOverrideScale(%this-->overrideScale.getValue());
%fileObj.close();
%fileObj.delete();
}
function AssimpImportDlg::saveSettingsTo(%this, %filename)
{
%fileObj = new FileObject();
if (!%fileObj.openForWrite(%fileName))
{
error("Error opening file to write settings (" @ %fileName @ ").");
%fileObj.delete();
return;
}
%fileObj.writeLine("SISV" @ %this.settingVersion);
foreach$ (%key in $Assimp::textFields)
{
%ctrl = %this.findObjectByInternalName(%key, true);
if (isObject(%ctrl))
{
%data = %ctrl.getText();
%fileObj.writeLine(%key TAB %data);
}
}
foreach$ (%key in $Assimp::checkboxFields)
{
%ctrl = %this.findObjectByInternalName(%key, true);
if (isObject(%ctrl))
{
%data = %ctrl.getValue();
%fileObj.writeLine(%key TAB %data);
}
}
%fileObj.close();
%fileObj.delete();
}

File diff suppressed because it is too large Load diff

View file

@ -489,14 +489,14 @@
Profile = "ToolsGuiCheckBoxProfile";
HorizSizing = "left";
VertSizing = "bottom";
Position = "135 27";
Position = "133 27";
Extent = "72 13";
Variable = "EWorldEditor.forceLoadDAE";
Command = "EWorldEditor.forceLoadDAE = $ThisControl.getValue(); EditorSettings.setValue(\"forceLoadDAE\", EWorldEditor.forceLoadDAE);";
tooltipprofile = "ToolsGuiToolTipProfile";
ToolTip = "Forces loading of DAE files (ignores cached.dts if present)";
hovertime = "1000";
text = " Force DAE";
text = " Source Art";
};
};

View file

@ -227,6 +227,9 @@ function ShapeEditor::saveChanges( %this )
function ShapeEditor::findConstructor( %this, %path )
{
if (!isObject(TSShapeConstructorGroup))
return -1;
%count = TSShapeConstructorGroup.getCount();
for ( %i = 0; %i < %count; %i++ )
{

View file

@ -0,0 +1,29 @@
SISV1
lodType SingleSize
singleDetailSize 2
materialPrefix
alwaysImport
neverImport
alwaysImportMesh
neverImportMesh
upAxis Y_AXIS
scale 1
animTiming Milliseconds
animFPS 30
overrideUpAxis 1
overrideScale 0
ignoreNodeScale 0
adjustCenter 0
adjustFloor 0
forceUpdateMaterials 0
convertLeftHanded 0
calcTangentSpace 0
removeRedundantMats 1
genUVCoords 0
transformUVCoords 0
flipUVCoords 1
findInstances 0
limitBoneWeights 0
joinIdenticalVerts 1
reverseWindingOrder 1
invertNormals 0

View file

@ -0,0 +1,29 @@
SISV1
lodType SingleSize
singleDetailSize 2
materialPrefix
alwaysImport
neverImport
alwaysImportMesh
neverImportMesh
upAxis Y_AXIS
scale 1
animTiming Milliseconds
animFPS 30
overrideUpAxis 1
overrideScale 0
ignoreNodeScale 0
adjustCenter 0
adjustFloor 0
forceUpdateMaterials 0
convertLeftHanded 0
calcTangentSpace 0
removeRedundantMats 1
genUVCoords 0
transformUVCoords 0
flipUVCoords 1
findInstances 0
limitBoneWeights 0
joinIdenticalVerts 1
reverseWindingOrder 1
invertNormals 0

View file

@ -0,0 +1,540 @@
//------------------------------------------------------------------------------
// Fields that will be saved to settings
$Assimp::textFields = "lodType" TAB "singleDetailSize" TAB "materialPrefix" TAB
"alwaysImport" TAB "neverImport" TAB "alwaysImportMesh" TAB "neverImportMesh"
TAB "upAxis" TAB "scale" TAB "animTiming" TAB "animFPS";
$Assimp::checkboxFields = "overrideUpAxis" TAB "overrideScale" TAB "ignoreNodeScale"
TAB "adjustCenter" TAB "adjustFloor" TAB "forceUpdateMaterials" TAB "convertLeftHanded"
TAB "calcTangentSpace" TAB "removeRedundantMats" TAB "genUVCoords" TAB
"transformUVCoords" TAB "flipUVCoords" TAB "findInstances" TAB "limitBoneWeights"
TAB "joinIdenticalVerts" TAB "reverseWindingOrder" TAB "invertNormals";
//------------------------------------------------------------------------------
function ShapeImportTreeView::refresh(%this, %what)
{
%shapeRoot = %this.getFirstRootItem();
%materialsRoot = %this.getNextSibling(%shapeRoot);
%animRoot = %this.getNextSibling(%materialsRoot);
// Refresh nodes
if ((%what $= "all") || (%what $= "nodes"))
{
// Indicate whether nodes will be ignored on import
%this._alwaysImport = strreplace(AssimpImportDlg-->alwaysImport.getText(), ";", "\t");
%this._neverImport = strreplace(AssimpImportDlg-->neverImport.getText(), ";", "\t");
%this._alwaysImportMesh = strreplace(AssimpImportDlg-->alwaysImportMesh.getText(), ";", "\t");
%this._neverImportMesh = strreplace(AssimpImportDlg-->neverImportMesh.getText(), ";", "\t");
%this.refreshNode(%this.getChild(%shapeRoot));
}
// Refresh materials
if ((%what $= "all") || (%what $= "materials"))
{
%matPrefix = AssimpImportDlg-->materialPrefix.getText();
%id = %this.getChild(%materialsRoot);
while (%id > 0)
{
%baseName = %this.getItemValue(%id);
%name = %matPrefix @ %baseName;
// Indicate whether material name is already mapped
%this.editItem(%id, %name, %baseName);
%mapped = getMaterialMapping(%name);
if (%mapped $= "")
{
%this.setItemTooltip(%id, "A new material will be mapped to this name");
%this.setItemImages(%id, %this._imageMaterial, %this._imageMaterial);
}
else
{
%this.setItemTooltip(%id, %mapped SPC "is already mapped to this material name");
%this.setItemImages(%id, %this._imageExMaterial, %this._imageExMaterial);
}
%id = %this.getNextSibling(%id);
}
}
// Refresh animations
if ((%what $= "all") || (%what $= "animations"))
{
%id = %this.getChild(%animRoot);
while (%id > 0)
{
%this.setItemImages(%id, %this._imageAnim, %this._imageAnim);
%id = %this.getNextSibling(%id);
}
}
}
function ShapeImportTreeView::refreshNode(%this, %id)
{
while (%id > 0)
{
switch$ (%this.getItemValue(%id))
{
case "mesh":
// Check if this mesh will be ignored on import
if (strIsMatchMultipleExpr(%this._alwaysImportMesh, %this.getItemText(%id)) ||
!strIsMatchMultipleExpr(%this._neverImportMesh, %this.getItemText(%id)) )
{
%this.setItemTooltip(%id, "");
%this.setItemImages(%id, %this._imageMesh, %this._imageMesh);
}
else
{
%this.setItemTooltip(%id, "This mesh will be ignored on import");
%this.setItemImages(%id, %this._imageExNode, %this._imageExNode);
}
case "light":
%this.setItemImages(%id, %this._imageLight, %this._imageLight);
case "node":
// Check if this node will be ignored on import
if (strIsMatchMultipleExpr(%this._alwaysImport, %this.getItemText(%id)) ||
!strIsMatchMultipleExpr(%this._neverImport, %this.getItemText(%id)) )
{
%this.setItemTooltip(%id, "");
%this.setItemImages(%id, %this._imageNode, %this._imageNode);
}
else
{
%this.setItemTooltip(%id, "This node will be ignored on import");
%this.setItemImages(%id, %this._imageExNode, %this._imageExNode);
}
}
// recurse through children and siblings
%this.refreshNode(%this.getChild(%id));
%id = %this.getNextSibling(%id);
}
}
function ShapeImportTreeView::onDefineIcons(%this)
{
// Set the tree view icon indices and texture paths
%this._imageNone = 0;
%this._imageNode = 1;
%this._imageMesh = 2;
%this._imageMaterial = 3;
%this._imageLight = 4;
%this._imageAnimation = 5;
%this._imageExNode = 6;
%this._imageExMaterial = 7;
%icons = ":" @ // no icon
"tools/gui/images/ColladaImport/iconNode:" @ // normal node
"tools/gui/images/ColladaImport/iconMesh:" @ // mesh
"tools/gui/images/ColladaImport/iconMaterial:" @ // new material
"tools/gui/images/ColladaImport/iconLight:" @ // light
"tools/gui/images/ColladaImport/iconAnimation:" @ // sequence
"tools/gui/images/ColladaImport/iconIgnoreNode:" @ // ignored node
"tools/gui/images/ColladaImport/iconExistingMaterial"; // existing material
%this.buildIconTable( %icons );
}
function AssimpImportDlg::updateOverrideUpAxis(%this, %override)
{
%this-->overrideUpAxis.setStateOn(%override);
%this-->upAxis.setActive(%override);
if (!%override)
%this-->upAxis.setText(ShapeImportTreeView._upAxis);
}
function AssimpImportDlg::updateOverrideScale(%this, %override)
{
%this-->overrideScale.setStateOn(%override);
%this-->scale.setActive(%override);
if (!%override)
%this-->scale.setText(ShapeImportTreeView._unit);
}
function AssimpImportDlg::initFromConstructor(%this)
{
if (%this.constructor.upAxis !$= "DEFAULT")
{
%this-->upAxis.setText(%this.constructor.upAxis);
%this.updateOverrideUpAxis(true);
}
else
%this.updateOverrideUpAxis(false);
if (%this.constructor.unit > 0)
{
%this-->scale.setText(%this.constructor.unit);
%this.updateOverrideScale(true);
}
else
%this.updateOverrideScale(false);
%this-->lodType.setText(%this.constructor.lodType);
%this-->singleDetailSize.setText(%this.constructor.singleDetailSize);
%this-->materialPrefix.setText(%this.constructor.matNamePrefix);
%this-->alwaysImport.setText(strreplace(%this.constructor.alwaysImport, "\t", ";"));
%this-->neverImport.setText(strreplace(%this.constructor.neverImport, "\t", ";"));
%this-->alwaysImportMesh.setText(strreplace(%this.constructor.alwaysImportMesh, "\t", ";"));
%this-->neverImportMesh.setText(strreplace(%this.constructor.neverImportMesh, "\t", ";"));
%this-->ignoreNodeScale.setStateOn(%this.constructor.ignoreNodeScale);
%this-->adjustCenter.setStateOn(%this.constructor.adjustCenter);
%this-->adjustFloor.setStateOn(%this.constructor.adjustFloor);
%this-->forceUpdateMaterials.setStateOn(%this.constructor.forceUpdateMaterials);
%this-->animTiming.setText(%this.constructor.animTiming);
%this-->animFPS.setText(%this.constructor.animFPS);
%this-->convertLeftHanded.setStateOn(%this.constructor.convertLeftHanded);
%this-->calcTangentSpace.setStateOn(%this.constructor.calcTangentSpace);
%this-->genUVCoords.setStateOn(%this.constructor.genUVCoords);
%this-->transformUVCoords.setStateOn(%this.constructor.transformUVCoords);
%this-->flipUVCoords.setStateOn(%this.constructor.flipUVCoords);
%this-->findInstances.setStateOn(%this.constructor.findInstances);
%this-->limitBoneWeights.setStateOn(%this.constructor.limitBoneWeights);
%this-->joinIdenticalVerts.setStateOn(%this.constructor.joinIdenticalVerts);
%this-->reverseWindingOrder.setStateOn(%this.constructor.reverseWindingOrder);
%this-->invertNormals.setStateOn(%this.constructor.invertNormals);
%this-->removeRedundantMats.setStateOn(%this.constructor.removeRedundantMats);
}
function AssimpImportDlg::initFromDefaults(%this)
{
%this.updateOverrideUpAxis(false);
%this.updateOverrideScale(false);
%this-->lodType.setText("TrailingNumber");
%this-->singleDetailSize.setText("2");
%this-->materialPrefix.setText("");
%this-->alwaysImport.setText("");
%this-->neverImport.setText("");
%this-->alwaysImportMesh.setText("");
%this-->neverImportMesh.setText("");
%this-->ignoreNodeScale.setStateOn(0);
%this-->adjustCenter.setStateOn(0);
%this-->adjustFloor.setStateOn(0);
%this-->forceUpdateMaterials.setStateOn(0);
%this-->animTiming.setText("Seconds");
%this-->animFPS.setText("30");
%this-->convertLeftHanded.setStateOn(0);
%this-->calcTangentSpace.setStateOn(0);
%this-->genUVCoords.setStateOn(0);
%this-->transformUVCoords.setStateOn(0);
%this-->flipUVCoords.setStateOn(1);
%this-->findInstances.setStateOn(0);
%this-->limitBoneWeights.setStateOn(0);
%this-->joinIdenticalVerts.setStateOn(1);
%this-->reverseWindingOrder.setStateOn(1);
%this-->invertNormals.setStateOn(0);
%this-->removeRedundantMats.setStateOn(1);
}
function AssimpImportDlg::saveToConstructor(%this)
{
// Store values from GUI
if (%this-->overrideUpAxis.getValue())
%this.constructor.upAxis = %this-->upAxis.getText();
else
%this.constructor.upAxis = "DEFAULT";
if (%this-->overrideScale.getValue())
%this.constructor.unit = %this-->scale.getText();
else
%this.constructor.unit = -1;
%this.constructor.lodType = %this-->lodType.getText();
%this.constructor.singleDetailSize = %this-->singleDetailSize.getText();
%this.constructor.matNamePrefix = %this-->materialPrefix.getText();
%this.constructor.alwaysImport = strreplace(%this-->alwaysImport.getText(), ";", "\t");
%this.constructor.neverImport = strreplace(%this-->neverImport.getText(), ";", "\t");
%this.constructor.alwaysImportMesh = strreplace(%this-->alwaysImportMesh.getText(), ";", "\t");
%this.constructor.neverImportMesh = strreplace(%this-->neverImportMesh.getText(), ";", "\t");
%this.constructor.ignoreNodeScale = %this-->ignoreNodeScale.getValue();
%this.constructor.adjustCenter = %this-->adjustCenter.getValue();
%this.constructor.adjustFloor = %this-->adjustFloor.getValue();
%this.constructor.forceUpdateMaterials = %this-->forceUpdateMaterials.getValue();
%this.constructor.animTiming = %this-->animTiming.getText();
%this.constructor.animFPS = %this-->animFPS.getText();
%this.constructor.convertLeftHanded = %this-->convertLeftHanded.getValue();
%this.constructor.calcTangentSpace = %this-->calcTangentSpace.getValue();
%this.constructor.genUVCoords = %this-->genUVCoords.getValue();
%this.constructor.transformUVCoords = %this-->transformUVCoords.getValue();
%this.constructor.flipUVCoords = %this-->flipUVCoords.getValue();
%this.constructor.findInstances = %this-->findInstances.getValue();
%this.constructor.limitBoneWeights = %this-->limitBoneWeights.getValue();
%this.constructor.joinIdenticalVerts = %this-->joinIdenticalVerts.getValue();
%this.constructor.reverseWindingOrder = %this-->reverseWindingOrder.getValue();
%this.constructor.invertNormals = %this-->invertNormals.getValue();
%this.constructor.removeRedundantMats = %this-->removeRedundantMats.getValue();
}
function AssimpImportDlg::showDialog(%this, %shapePath, %cmd)
{
%this.settingVersion = 1.0;
%this.path = %shapePath;
%this.cmd = %cmd;
// Check for an existing TSShapeConstructor object. Need to exec the script
// manually as the resource may not have been loaded yet
%csPath = filePath(%this.path) @ "/" @ fileBase(%this.path) @ ".cs";
if (isFile(%csPath))
exec(%csPath);
%this.constructor = ShapeEditor.findConstructor(%this.path);
// Only show the import dialog if required. Note that 'GetShapeInfo' will
// fail if the source file is missing, or a cached.dts is available.
$assimp::forceLoad = EditorSettings.value("forceLoadDAE");
if (!GetShapeInfo(%shapePath, "ShapeImportTreeView"))
{
eval(%cmd);
$assimp::forceLoad = false;
return;
}
$assimp::forceLoad = false;
// Initialise GUI
ShapeImportTreeView.onDefineIcons();
// Window Title
%this-->window.text = "Shape Import:" SPC %this.path;
// Fill Popups
%this-->upAxis.clear();
%this-->upAxis.add("X_AXIS", 1);
%this-->upAxis.add("Y_AXIS", 2);
%this-->upAxis.add("Z_AXIS", 3);
%this-->lodType.clear();
%this-->lodType.add("DetectDTS", 1);
%this-->lodType.add("SingleSize", 2);
%this-->lodType.add("TrailingNumber", 3);
%this-->animTiming.clear();
%this-->animTiming.add("Frames", 0);
%this-->animTiming.add("Seconds", 1);
%this-->animTiming.add("Milliseconds", 1000);
// Set model details
%this-->nodes.setText(ShapeImportTreeView._nodeCount);
%this-->meshes.setText(ShapeImportTreeView._meshCount);
%this-->lights.setText(ShapeImportTreeView._lightCount);
%this-->materials.setText(ShapeImportTreeView._materialCount);
%this-->polygons.setText(ShapeImportTreeView._polygonCount);
%this-->animations.setText(ShapeImportTreeView._animCount);
%this-->textures.setText(ShapeImportTreeView._textureCount);
%this-->vertices.setText(ShapeImportTreeView._vertCount);
%metaText = (ShapeImportTreeView._metaTagCount == 0) ? "No Records" : ShapeImportTreeView._metaTagCount;
%this-->metadata.setText(%metaText);
if (%this.constructor > 0)
%this.initFromConstructor();
else
{
%this.initFromDefaults();
// If there's a default settings file for the file type, load it
%defaultSISPath = EditorSettings.value("defaultSettingsPath", "Tools");
%settingsFile = %defaultSISPath @ "/" @ getSubStr(fileExt(%shapePath),1) @ ".sis";
if (isFile(%settingsFile))
%this.loadSettingsFrom(%settingsFile);
}
Canvas.pushDialog(%this);
ShapeImportTreeView.refresh("all");
}
function AssimpImportDlg::onLoadSettings(%this)
{
%defaultSISPath = EditorSettings.value("defaultSettingsPath", "Tools");
%dlg = new OpenFileDialog()
{
Filters = "Shape Import Settings (*.sis)|*.sis|";
DefaultPath = %defaultSISPath;
DefaultFile = "";
ChangePath = false;
MustExist = true;
};
%ret = %dlg.Execute();
if ( %ret )
%fileName = %dlg.FileName;
%dlg.delete();
if ( !%ret )
return;
%this.loadSettingsFrom(%fileName);
}
function AssimpImportDlg::onSaveSettings(%this)
{
%defaultSISPath = EditorSettings.value("defaultSettingsPath", "Tools");
%dlg = new SaveFileDialog()
{
Filters = "Shape Import Settings (*.sis)|*.sis|";
DefaultPath = %defaultSISPath;
DefaultFile = "";
ChangePath = false;
MustExist = true;
};
%ret = %dlg.Execute();
if ( %ret )
{
%saveFile = %dlg.FileName;
if(fileExt( %saveFile ) !$= ".sis")
%saveFile = %saveFile @ ".sis";
}
%dlg.delete();
if (!%ret)
return;
%this.saveSettingsTo(%saveFile);
}
function AssimpImportDlg::onCancel(%this)
{
Canvas.popDialog(%this);
ShapeImportTreeView.clear();
}
function AssimpImportDlg::onOK(%this)
{
Canvas.popDialog(%this);
ShapeImportTreeView.clear();
if (%this.needsSave())
{
if (!isObject(%this.constructor))
{ // Create a new TSShapeConstructor object
%this.constructor = ShapeEditor.createConstructor(%this.path);
}
}
if (%this.constructor > 0)
{
%this.saveToConstructor();
// Save new settings to file
ShapeEditor.saveConstructor(%this.constructor);
}
// Load the shape (always from the DAE)
$assimp::forceLoad = true;
eval(%this.cmd);
$assimp::forceLoad = false;
}
function AssimpImportDlg::needsSave(%this)
{
if ((%this-->overrideUpAxis.getValue() != 0) ||
(%this-->overrideScale.getValue() != 0) ||
(%this-->lodType.getText() !$= "DetectDTS") ||
(%this-->singleDetailSize.getText() !$= "2") ||
(%this-->materialPrefix.getText() !$= "") ||
(%this-->alwaysImport.getText() !$= "") ||
(%this-->neverImport.getText() !$= "") ||
(%this-->alwaysImportMesh.getText() !$= "") ||
(%this-->neverImportMesh.getText() !$= "") ||
(%this-->ignoreNodeScale.getValue() != 0) ||
(%this-->adjustCenter.getValue() != 0) ||
(%this-->adjustFloor.getValue() != 0) ||
(%this-->forceUpdateMaterials.getValue() != 0))
return true;
if ((%this-->animTiming.getText() !$= "Seconds") ||
(%this-->animFPS.getText() !$= "30") ||
(%this-->convertLeftHanded.getValue() != 0) ||
(%this-->calcTangentSpace.getValue() != 0) ||
(%this-->genUVCoords.getValue() != 0) ||
(%this-->transformUVCoords.getValue() != 0) ||
(%this-->flipUVCoords.getValue() != 1) ||
(%this-->findInstances.getValue() != 0) ||
(%this-->limitBoneWeights.getValue() != 0) ||
(%this-->joinIdenticalVerts.getValue() != 1) ||
(%this-->reverseWindingOrder.getValue() != 1) ||
(%this-->invertNormals.getValue() != 0) ||
(%this-->removeRedundantMats.getValue() != 1))
return true;
return false;
}
function AssimpImportDlg::loadSettingsFrom(%this, %filename)
{
%fileObj = new FileObject();
if (!%fileObj.OpenForRead(%fileName))
{
error("Error opening file to write settings (" @ %fileName @ ").");
%fileObj.delete();
return;
}
%line = %fileObj.ReadLine();
if (getSubStr(%line, 0, 4) !$= "SISV")
return; // ? not sis file
while( !%fileObj.isEOF() )
{
%line = %fileObj.ReadLine();
%key = getField(%line, 0);
%data = getFields(%line, 1);
%ctrl = %this.findObjectByInternalName(%key, true);
if (isObject(%ctrl))
{
%name = %ctrl.getClassName();
if (%ctrl.getClassName() $= "GuiCheckBoxCtrl")
%ctrl.setStateOn(%data);
else
%ctrl.setText(%data);
}
}
%this.updateOverrideUpAxis(%this-->overrideUpAxis.getValue());
%this.updateOverrideScale(%this-->overrideScale.getValue());
%fileObj.close();
%fileObj.delete();
}
function AssimpImportDlg::saveSettingsTo(%this, %filename)
{
%fileObj = new FileObject();
if (!%fileObj.openForWrite(%fileName))
{
error("Error opening file to write settings (" @ %fileName @ ").");
%fileObj.delete();
return;
}
%fileObj.writeLine("SISV" @ %this.settingVersion);
foreach$ (%key in $Assimp::textFields)
{
%ctrl = %this.findObjectByInternalName(%key, true);
if (isObject(%ctrl))
{
%data = %ctrl.getText();
%fileObj.writeLine(%key TAB %data);
}
}
foreach$ (%key in $Assimp::checkboxFields)
{
%ctrl = %this.findObjectByInternalName(%key, true);
if (isObject(%ctrl))
{
%data = %ctrl.getValue();
%fileObj.writeLine(%key TAB %data);
}
}
%fileObj.close();
%fileObj.delete();
}

File diff suppressed because it is too large Load diff

View file

@ -489,14 +489,14 @@
Profile = "ToolsGuiCheckBoxProfile";
HorizSizing = "left";
VertSizing = "bottom";
Position = "135 27";
Position = "133 27";
Extent = "72 13";
Variable = "EWorldEditor.forceLoadDAE";
Command = "EWorldEditor.forceLoadDAE = $ThisControl.getValue(); EditorSettings.setValue(\"forceLoadDAE\", EWorldEditor.forceLoadDAE);";
tooltipprofile = "ToolsGuiToolTipProfile";
ToolTip = "Forces loading of DAE files (ignores cached.dts if present)";
hovertime = "1000";
text = " Force DAE";
text = " Source Art";
};
};

View file

@ -227,6 +227,9 @@ function ShapeEditor::saveChanges( %this )
function ShapeEditor::findConstructor( %this, %path )
{
if (!isObject(TSShapeConstructorGroup))
return -1;
%count = TSShapeConstructorGroup.getCount();
for ( %i = 0; %i < %count; %i++ )
{