Torque3D Documentation / _generateds / assetImporter.cpp

assetImporter.cpp

Engine/source/T3D/assets/assetImporter.cpp

More...

Classes:

Public Functions

ConsoleDocClass(AssetImportConfig , "@brief Defines properties <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> an AssetImprotConfig <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@<a href="/coding/class/classassetimportconfig/">AssetImportConfig</a> is <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classsimobject/">SimObject</a> derived object intended <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> act as <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> container <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> all the necessary configuration data when running the Asset <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Importer.\n</a>" "@It dictates <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> and how any given asset type will be processed when running an import action. This is because the Asset Importer utilizes <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> lot of informed <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">logic\n</a>" "@<a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> try and automate as much of the import process as possible. In theory, you would run the import on <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> given file, and based on your config the importer will <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">do\n</a>" " @everything from importing the designated file, as well as finding and importing any associated files such as images or materials, and prepping the objects at <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">time\n</a>" " @of import <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> avoid as much manual post-processing as <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">possible.\n\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Assets\n</a>" )
ConsoleDocClass(AssetImporter , "@brief Defines properties <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> an <a href="/coding/class/classassetimportobject/">AssetImportObject</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@<a href="/coding/class/classassetimportobject/">AssetImportObject</a> is <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classsimobject/">SimObject</a> derived object intended <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> act as <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> stand-in <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a>-be imported <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">objects.\n</a>" "@It contains important info such as dependencies, <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> it 's been processed, any error/status issues and the originating <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">file\n</a>" " @or <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> it 's been programmatically generated as part of the import <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">process.\n\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Assets\n</a>" )
ConsoleDocClass(AssetImportObject , "@brief Defines properties <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> an <a href="/coding/class/classassetimportobject/">AssetImportObject</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@<a href="/coding/class/classassetimportobject/">AssetImportObject</a> is <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classsimobject/">SimObject</a> derived object intended <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> act as <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> stand-in <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a>-be imported <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">objects.\n</a>" "@It contains important info such as dependencies, <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> it 's been processed, any error/status issues and the originating <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">file\n</a>" " @or <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> it 's been programmatically generated as part of the import <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">process.\n\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Assets\n</a>" )
bool
enumColladaForImport(const char * shapePath, GuiTreeViewCtrl * tree, bool loadCachedDts)
bool
enumDTSForImport(const char * shapePath, GuiTreeViewCtrl * tree)
processNode(GuiTreeViewCtrl * tree, domNode * node, S32 parentID, SceneStats & stats)

Detailed Description

Public Functions

ConsoleDocClass(AssetImportConfig , "@brief Defines properties <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> an AssetImprotConfig <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@<a href="/coding/class/classassetimportconfig/">AssetImportConfig</a> is <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classsimobject/">SimObject</a> derived object intended <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> act as <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> container <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> all the necessary configuration data when running the Asset <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Importer.\n</a>" "@It dictates <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> and how any given asset type will be processed when running an import action. This is because the Asset Importer utilizes <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> lot of informed <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">logic\n</a>" "@<a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> try and automate as much of the import process as possible. In theory, you would run the import on <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> given file, and based on your config the importer will <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">do\n</a>" " @everything from importing the designated file, as well as finding and importing any associated files such as images or materials, and prepping the objects at <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">time\n</a>" " @of import <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> avoid as much manual post-processing as <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">possible.\n\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Assets\n</a>" )

ConsoleDocClass(AssetImporter , "@brief Defines properties <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> an <a href="/coding/class/classassetimportobject/">AssetImportObject</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@<a href="/coding/class/classassetimportobject/">AssetImportObject</a> is <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classsimobject/">SimObject</a> derived object intended <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> act as <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> stand-in <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a>-be imported <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">objects.\n</a>" "@It contains important info such as dependencies, <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> it 's been processed, any error/status issues and the originating <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">file\n</a>" " @or <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> it 's been programmatically generated as part of the import <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">process.\n\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Assets\n</a>" )

ConsoleDocClass(AssetImportObject , "@brief Defines properties <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> an <a href="/coding/class/classassetimportobject/">AssetImportObject</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@<a href="/coding/class/classassetimportobject/">AssetImportObject</a> is <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classsimobject/">SimObject</a> derived object intended <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> act as <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> stand-in <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a>-be imported <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">objects.\n</a>" "@It contains important info such as dependencies, <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> it 's been processed, any error/status issues and the originating <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">file\n</a>" " @or <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> it 's been programmatically generated as part of the import <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">process.\n\n</a>" " @ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Assets\n</a>" )

enumColladaForImport(const char * shapePath, GuiTreeViewCtrl * tree, bool loadCachedDts)

enumDTSForImport(const char * shapePath, GuiTreeViewCtrl * tree)

IMPLEMENT_CONOBJECT(AssetImportConfig )

IMPLEMENT_CONOBJECT(AssetImporter )

IMPLEMENT_CONOBJECT(AssetImportObject )

processNode(GuiTreeViewCtrl * tree, domNode * node, S32 parentID, SceneStats & stats)

   1
   2#include "assetImporter.h"
   3#include "assetImporter_ScriptBinding.h"
   4#include "core/strings/findMatch.h"
   5#include "ImageAsset.h"
   6#include "ShapeAsset.h"
   7#include "SoundAsset.h"
   8#include "MaterialAsset.h"
   9#include "ShapeAnimationAsset.h"
  10
  11#include "ts/collada/colladaUtils.h"
  12#include "ts/collada/colladaAppNode.h"
  13#include "ts/collada/colladaShapeLoader.h"
  14
  15#include "ts/assimp/assimpShapeLoader.h"
  16#include "ts/tsShapeConstruct.h"
  17#include "core/resourceManager.h"
  18
  19#include "materials/materialManager.h"
  20
  21#include "console/persistenceManager.h"
  22
  23ConsoleDocClass(AssetImportConfig,
  24   "@brief Defines properties for an AssetImprotConfig object.\n"
  25   "@AssetImportConfig is a SimObject derived object intended to act as a container for all the necessary configuration data when running the Asset Importer.\n"
  26   "@It dictates if and how any given asset type will be processed when running an import action. This is because the Asset Importer utilizes a lot of informed logic\n"
  27   "@to try and automate as much of the import process as possible. In theory, you would run the import on a given file, and based on your config the importer will do\n"
  28   "@everything from importing the designated file, as well as finding and importing any associated files such as images or materials, and prepping the objects at time\n"
  29   "@of import to avoid as much manual post-processing as possible.\n\n"
  30   "@ingroup Assets\n"
  31);
  32
  33IMPLEMENT_CONOBJECT(AssetImportConfig);
  34
  35AssetImportConfig::AssetImportConfig() :
  36   DuplicatAutoResolution("AutoRename"),
  37   WarningsAsErrors(false),
  38   PreventImportWithErrors(true),
  39   AutomaticallyPromptMissingFiles(false),
  40   ImportMesh(true),
  41   AlwaysAddShapeSuffix(false),
  42   AddedShapeSuffix("_shape"),
  43   UseManualShapeConfigRules(false),
  44   DoUpAxisOverride(false),
  45   UpAxisOverride("Z_AXIS"),
  46   DoScaleOverride(false),
  47   ScaleOverride(false),
  48   IgnoreNodeScale(false),
  49   AdjustCenter(false),
  50   AdjustFloor(false),
  51   CollapseSubmeshes(false),
  52   LODType("TrailingNumber"),
  53   AlwaysImportedNodes(""),
  54   AlwaysIgnoreNodes(""),
  55   AlwaysImportMeshes(""),
  56   AlwaysIgnoreMeshes(""),
  57   convertLeftHanded(false),
  58   calcTangentSpace(false),
  59   removeRedundantMats(false),
  60   genUVCoords(false),
  61   TransformUVs(false),
  62   flipUVCoords(false),
  63   findInstances(false),
  64   limitBoneWeights(false),
  65   JoinIdenticalVerts(false),
  66   reverseWindingOrder(false),
  67   invertNormals(false),
  68   ImportMaterials(true),
  69   AlwaysAddMaterialSuffix(true),
  70   AddedMaterialSuffix("_mat"),
  71   CreateORMConfig(true),
  72   UseDiffuseSuffixOnOriginImage(false),
  73   UseExistingMaterials(false),
  74   IgnoreMaterials(""),
  75   PopulateMaterialMaps(true),
  76   ImportAnimations(true),
  77   SeparateAnimations(false),
  78   SeparateAnimationPrefix(""),
  79   animTiming("FrameCount"),
  80   animFPS(false),
  81   GenerateCollisions(false),
  82   GenCollisionType(""),
  83   CollisionMeshPrefix(""),
  84   GenerateLOSCollisions(false),
  85   GenLOSCollisionType(""),
  86   LOSCollisionMeshPrefix(""),
  87   importImages(true),
  88   AlwaysAddImageSuffix(true),
  89   AddedImageSuffix("_image"),
  90   ImageType("GUI"),
  91   DiffuseTypeSuffixes("_ALBEDO,_DIFFUSE,_ALB,_DIF,_COLOR,_COL,_A,_C,-ALBEDO,-DIFFUSE,-ALB,-DIF,-COLOR,-COL,-A,-C"),
  92   NormalTypeSuffixes("_NORMAL,_NORM,_N,-NORMAL,-NORM,-N"),
  93   MetalnessTypeSuffixes("_METAL,_MET,_METALNESS,_METALLIC,_M,-METAL, -MET, -METALNESS, -METALLIC, -M"),
  94   RoughnessTypeSuffixes("_ROUGH,_ROUGHNESS,_R,-ROUGH,-ROUGHNESS,-R"),
  95   SmoothnessTypeSuffixes("_SMOOTH,_SMOOTHNESS,_S,-SMOOTH,-SMOOTHNESS,-S"),
  96   AOTypeSuffixes("_AO,_AMBIENT,_AMBIENTOCCLUSION,-AO,-AMBIENT,-AMBIENTOCCLUSION"),
  97   PBRTypeSuffixes("_COMP,_COMPOSITE,_PBR,-COMP,-COMPOSITE,-PBR,_ORM,-ORM"),
  98   TextureFilteringMode("Bilinear"),
  99   UseMips(true),
 100   IsHDR(false),
 101   Scaling(false),
 102   ImagesCompressed(false),
 103   GenerateMaterialOnImport(true),
 104   importSounds(true),
 105   VolumeAdjust(false),
 106   PitchAdjust(false),
 107   SoundsCompressed(false)
 108{
 109}
 110
 111AssetImportConfig::~AssetImportConfig()
 112{
 113
 114}
 115
 116bool AssetImportConfig::onAdd()
 117{
 118   if (!Parent::onAdd())
 119      return false;
 120
 121   return true;
 122}
 123
 124void AssetImportConfig::onRemove()
 125{
 126   Parent::onRemove();
 127}
 128
 129/// Engine.
 130void AssetImportConfig::initPersistFields()
 131{
 132   Parent::initPersistFields();
 133
 134   addGroup("General");
 135      addField("DuplicatAutoResolution", TypeRealString, Offset(DuplicatAutoResolution, AssetImportConfig), "Duplicate Asset Auto-Resolution Action. Options are None, AutoPrune, AutoRename");
 136      addField("WarningsAsErrors", TypeBool, Offset(WarningsAsErrors, AssetImportConfig), "Indicates if warnings should be treated as errors");
 137      addField("PreventImportWithErrors", TypeBool, Offset(PreventImportWithErrors, AssetImportConfig), "Indicates if importing should be prevented from completing if any errors are detected at all");
 138      addField("AutomaticallyPromptMissingFiles", TypeBool, Offset(AutomaticallyPromptMissingFiles, AssetImportConfig), "Should the importer automatically prompt to find missing files if they are not detected automatically by the importer");
 139   endGroup("General");
 140
 141   addGroup("Meshes");
 142      addField("ImportMesh", TypeBool, Offset(ImportMesh, AssetImportConfig), "Indicates if this config supports importing meshes");
 143      addField("AlwaysAddShapeSuffix", TypeBool, Offset(AlwaysAddShapeSuffix, AssetImportConfig), "When importing a shape, this indicates if it should automatically add a standard suffix onto the name");
 144      addField("AddedShapeSuffix", TypeString, Offset(AddedShapeSuffix, AssetImportConfig), " If AlwaysAddShapeSuffix is on, this is the suffix to be added");
 145      addField("UseManualShapeConfigRules", TypeBool, Offset(UseManualShapeConfigRules, AssetImportConfig), "Indicates if this config should override the per-format sis files with the config's specific settings");
 146      addField("DoUpAxisOverride", TypeBool, Offset(DoUpAxisOverride, AssetImportConfig), "Indicates if the up axis in the model file should be overridden");
 147      addField("UpAxisOverride", TypeRealString, Offset(UpAxisOverride, AssetImportConfig), "If overriding, what axis should be used as up. Options are X_AXIS, Y_AXIS, Z_AXIS");
 148      addField("DoScaleOverride", TypeBool, Offset(DoScaleOverride, AssetImportConfig), "Indicates if the scale in the model file should be overridden");
 149      addField("ScaleOverride", TypeF32, Offset(ScaleOverride, AssetImportConfig), "If overriding, what scale should be used");
 150      addField("IgnoreNodeScale", TypeBool, Offset(IgnoreNodeScale, AssetImportConfig), "Indicates if scale of nodes should be ignored");
 151      addField("AdjustCenter", TypeBool, Offset(AdjustCenter, AssetImportConfig), "Indicates if the center of the model file should be automatically recentered");
 152      addField("AdjustFloor", TypeBool, Offset(AdjustFloor, AssetImportConfig), "Indicates if the floor height of the model file should be automatically zero'd");
 153      addField("CollapseSubmeshes", TypeBool, Offset(CollapseSubmeshes, AssetImportConfig), "Indicates if submeshes should be collapsed down into a single main mesh");
 154      addField("LODType", TypeRealString, Offset(LODType, AssetImportConfig), "Indicates what LOD mode the model file should utilize to process out LODs. Options are TrailingNumber, DetectDTS, SingleSize");
 155      addField("AlwaysImportedNodes", TypeRealString, Offset(AlwaysImportedNodes, AssetImportConfig), " A list of what nodes should be guaranteed to be imported if found in the model file. Separated by either , or ;");
 156      addField("AlwaysIgnoreNodes", TypeRealString, Offset(AlwaysIgnoreNodes, AssetImportConfig), "A list of what nodes should be guaranteed to not be imported if found in the model file. Separated by either , or ;");
 157      addField("AlwaysImportMeshes", TypeRealString, Offset(AlwaysImportMeshes, AssetImportConfig), "A list of what mesh objects should be guaranteed to be imported if found in the model file. Separated by either , or ;");
 158      addField("AlwaysIgnoreMeshes", TypeRealString, Offset(AlwaysIgnoreMeshes, AssetImportConfig), "A list of what mesh objects should be guaranteed to not be imported if found in the model file. Separated by either , or ;");
 159      addField("convertLeftHanded", TypeBool, Offset(convertLeftHanded, AssetImportConfig), "Flag to indicate the shape loader should convert to a left-handed coordinate system");
 160      addField("calcTangentSpace", TypeBool, Offset(calcTangentSpace, AssetImportConfig), "Should the shape loader calculate tangent space values");
 161      addField("removeRedundantMats", TypeBool, Offset(removeRedundantMats, AssetImportConfig), "Should the shape loader automatically prune redundant/duplicate materials");
 162      addField("genUVCoords", TypeBool, Offset(genUVCoords, AssetImportConfig), "Should the shape loader auto-generate UV Coordinates for the mesh.");
 163      addField("TransformUVs", TypeBool, Offset(TransformUVs, AssetImportConfig), "Should the UV coordinates be transformed");
 164      addField("flipUVCoords", TypeBool, Offset(flipUVCoords, AssetImportConfig), "Should the UV coordinates be flipped");
 165      addField("findInstances", TypeBool, Offset(findInstances, AssetImportConfig), "Should the shape loader automatically look for instanced submeshes in the model file");
 166      addField("limitBoneWeights", TypeBool, Offset(limitBoneWeights, AssetImportConfig), "Should the shape loader limit the bone weights");
 167      addField("JoinIdenticalVerts", TypeBool, Offset(JoinIdenticalVerts, AssetImportConfig), "Should the shape loader automatically merge identical/duplicate verts");
 168      addField("reverseWindingOrder", TypeBool, Offset(reverseWindingOrder, AssetImportConfig), "Should the shape loader reverse the winding order of the mesh's face indicies");
 169      addField("invertNormals", TypeBool, Offset(invertNormals, AssetImportConfig), "Should the normals on the model be inverted");
 170   endGroup("Meshes");
 171
 172   addGroup("Materials");
 173      addField("ImportMaterials", TypeBool, Offset(ImportMaterials, AssetImportConfig), "Does this config allow for importing of materials");
 174      addField("AlwaysAddMaterialSuffix", TypeBool, Offset(AlwaysAddMaterialSuffix, AssetImportConfig), "When importing a material, this indicates if it should automatically add a standard suffix onto the name");
 175      addField("AddedMaterialSuffix", TypeString, Offset(AddedMaterialSuffix, AssetImportConfig), " If AlwaysAddMaterialSuffix is on, this is the suffix to be added");
 176      addField("CreateORMConfig", TypeBool, Offset(PreventImportWithErrors, AssetImportConfig), "When importing a material, should it automatically attempt to merge Roughness, AO and Metalness maps into a single, composited PBR Configuration map");
 177      addField("UseDiffuseSuffixOnOriginImage", TypeBool, Offset(UseDiffuseSuffixOnOriginImage, AssetImportConfig), "When generating a material off of an importing image, should the importer force appending a diffusemap suffix onto the end to avoid potential naming confusion.\n e.g. MyCoolStuff.png is imported, generating MyCoolStuff material asset and MyCoolStuff_Diffuse image asset");
 178      addField("UseExistingMaterials", TypeBool, Offset(UseExistingMaterials, AssetImportConfig), "Should the importer try and use existing material assets in the game directory if at all possible. (Not currently utilized)");
 179      addField("IgnoreMaterials", TypeRealString, Offset(IgnoreMaterials, AssetImportConfig), "A list of material names that should not be imported. Separated by either , or ;");
 180      addField("PopulateMaterialMaps", TypeBool, Offset(PopulateMaterialMaps, AssetImportConfig), "When processing a material asset, should the importer attempt to populate the various material maps on it by looking up common naming conventions for potentially relevent image files.\n e.g. If MyCoolStuff_Diffuse.png is imported, generating MyCoolStuff material, it would also find MyCoolStuff_Normal and MyCoolStuff_PBR images and map them to the normal and ORMConfig maps respectively automatically");
 181   endGroup("Materials");
 182
 183   addGroup("Animation");
 184      addField("ImportAnimations", TypeBool, Offset(ImportAnimations, AssetImportConfig), "Does this config allow for importing Shape Animations");
 185      addField("SeparateAnimations", TypeBool, Offset(SeparateAnimations, AssetImportConfig), "When importing a shape file, should the animations within be separated out into unique files");
 186      addField("SeparateAnimationPrefix", TypeRealString, Offset(SeparateAnimationPrefix, AssetImportConfig), "If separating animations out from a source file, what prefix should be added to the names for grouping association");
 187      addField("animTiming", TypeRealString, Offset(animTiming, AssetImportConfig), "Defines the animation timing for the given animation sequence. Options are FrameTime, Seconds, Milliseconds");
 188      addField("animFPS", TypeBool, Offset(animFPS, AssetImportConfig), "The FPS of the animation sequence");
 189   endGroup("Animation");
 190
 191   addGroup("Collision");
 192      addField("GenerateCollisions", TypeBool, Offset(GenerateCollisions, AssetImportConfig), "Does this configuration generate collision geometry when importing. (Not currently enabled)");
 193      addField("GenCollisionType", TypeRealString, Offset(GenCollisionType, AssetImportConfig), "What sort of collision geometry is generated. (Not currently enabled)");
 194      addField("CollisionMeshPrefix", TypeRealString, Offset(CollisionMeshPrefix, AssetImportConfig), "What prefix is added to the collision geometry generated. (Not currently enabled)");
 195      addField("GenerateLOSCollisions", TypeBool, Offset(GenerateLOSCollisions, AssetImportConfig), "Does this configuration generate Line of Sight collision geometry. (Not currently enabled)");
 196      addField("GenLOSCollisionType", TypeRealString, Offset(GenLOSCollisionType, AssetImportConfig), "What sort of Line of Sight collision geometry is generated. (Not currently enabled)");
 197      addField("LOSCollisionMeshPrefix", TypeRealString, Offset(LOSCollisionMeshPrefix, AssetImportConfig), "What prefix is added to the Line of Sight collision geometry generated. (Not currently enabled)");
 198   endGroup("Collision");
 199
 200   addGroup("Images");
 201      addField("importImages", TypeBool, Offset(importImages, AssetImportConfig), "Does this configuration support importing images.");
 202      addField("AlwaysAddImageSuffix", TypeBool, Offset(AlwaysAddImageSuffix, AssetImportConfig), "When importing an image, this indicates if it should automatically add a standard suffix onto the name");
 203      addField("AddedImageSuffix", TypeString, Offset(AddedImageSuffix, AssetImportConfig), " If AlwaysAddImageSuffix is on, this is the suffix to be added");
 204      addField("ImageType", TypeRealString, Offset(ImageType, AssetImportConfig), "What is the default ImageType images are imported as. Options are: N/A, Diffuse, Normal, Metalness, Roughness, AO, ORMConfig, GUI, Cubemap");
 205      addField("DiffuseTypeSuffixes", TypeRealString, Offset(DiffuseTypeSuffixes, AssetImportConfig), "What type of suffixes are scanned to detect if an importing image is a diffuse map. \n e.g. _Albedo or _Color");
 206      addField("NormalTypeSuffixes", TypeRealString, Offset(NormalTypeSuffixes, AssetImportConfig), "What type of suffixes are scanned to detect if an importing image is a normal map. \n e.g. _Normal or _Norm");
 207      addField("MetalnessTypeSuffixes", TypeRealString, Offset(MetalnessTypeSuffixes, AssetImportConfig), "What type of suffixes are scanned to detect if an importing image is a metalness map. \n e.g. _Metalness or _Metal");
 208      addField("RoughnessTypeSuffixes", TypeRealString, Offset(RoughnessTypeSuffixes, AssetImportConfig), "What type of suffixes are scanned to detect if an importing image is a roughness map.\n e.g. _roughness or _rough");
 209      addField("SmoothnessTypeSuffixes", TypeRealString, Offset(SmoothnessTypeSuffixes, AssetImportConfig), "What type of suffixes are scanned to detect if an importing image is a smoothness map. \n e.g. _smoothness or _smooth");
 210      addField("AOTypeSuffixes", TypeRealString, Offset(AOTypeSuffixes, AssetImportConfig), "What type of suffixes are scanned to detect if an importing image is a ambient occlusion map. \n e.g. _ambient or _ao");
 211      addField("PBRTypeSuffixes", TypeRealString, Offset(PBRTypeSuffixes, AssetImportConfig), "What type of suffixes are scanned to detect if an importing image is a ORMConfig map.\n e.g. _Composite or _PBR");
 212      addField("TextureFilteringMode", TypeRealString, Offset(TextureFilteringMode, AssetImportConfig), "Indicates what filter mode images imported with this configuration utilizes. Options are Linear, Bilinear, Trilinear");
 213      addField("UseMips", TypeBool, Offset(UseMips, AssetImportConfig), "Indicates if images imported with this configuration utilize mipmaps");
 214
 215      addField("IsHDR", TypeBool, Offset(IsHDR, AssetImportConfig), "Indicates if images imported with this configuration are in an HDR format");
 216      addField("Scaling", TypeF32, Offset(Scaling, AssetImportConfig), "Indicates what amount of scaling images imported with this configuration use");
 217      addField("ImagesCompressed", TypeBool, Offset(ImagesCompressed, AssetImportConfig), "Indicates if images imported with this configuration are compressed");
 218      addField("GenerateMaterialOnImport", TypeBool, Offset(GenerateMaterialOnImport, AssetImportConfig), "Indicates if images imported with this configuration generate a parent material for it as well");
 219   endGroup("Images");
 220
 221   addGroup("Sounds");
 222      addField("importSounds", TypeBool, Offset(importSounds, AssetImportConfig), "Indicates if sounds are imported with this configuration");
 223      addField("VolumeAdjust", TypeF32, Offset(VolumeAdjust, AssetImportConfig), "Indicates what amount the volume is adjusted on sounds imported with this configuration");
 224      addField("PitchAdjust", TypeF32, Offset(PitchAdjust, AssetImportConfig), "Indicates what amount the pitch is adjusted on sounds imported with this configuration");
 225      addField("SoundsCompressed", TypeBool, Offset(SoundsCompressed, AssetImportConfig), "Indicates if sounds imported with this configuration are compressed");
 226   endGroup("Sounds");
 227}
 228
 229void AssetImportConfig::loadImportConfig(Settings* configSettings, String configName)
 230{
 231   //General
 232   DuplicatAutoResolution = configSettings->value(String(configName + "/General/DuplicatAutoResolution").c_str());
 233   WarningsAsErrors = dAtob(configSettings->value(String(configName + "/General/WarningsAsErrors").c_str()));
 234   PreventImportWithErrors = dAtob(configSettings->value(String(configName + "/General/PreventImportWithErrors").c_str()));
 235   AutomaticallyPromptMissingFiles = dAtob(configSettings->value(String(configName + "/General/AutomaticallyPromptMissingFiles").c_str()));
 236
 237   //Meshes
 238   ImportMesh = dAtob(configSettings->value(String(configName + "/Meshes/ImportMesh").c_str()));
 239   AlwaysAddShapeSuffix = dAtob(configSettings->value(String(configName + "/Meshes/AlwaysAddShapeSuffix").c_str()));
 240   AddedShapeSuffix = configSettings->value(String(configName + "/Meshes/AddedShapeSuffix").c_str());
 241   UseManualShapeConfigRules = dAtob(configSettings->value(String(configName + "/Meshes/UseManualShapeConfigRules").c_str()));
 242   DoUpAxisOverride = dAtob(configSettings->value(String(configName + "/Meshes/DoUpAxisOverride").c_str()));
 243   UpAxisOverride = configSettings->value(String(configName + "/Meshes/UpAxisOverride").c_str());
 244   DoScaleOverride = dAtob(configSettings->value(String(configName + "/Meshes/DoScaleOverride").c_str()));
 245   ScaleOverride = dAtof(configSettings->value(String(configName + "/Meshes/ScaleOverride").c_str()));
 246   IgnoreNodeScale = dAtob(configSettings->value(String(configName + "/Meshes/IgnoreNodeScale").c_str()));
 247   AdjustCenter = dAtob(configSettings->value(String(configName + "/Meshes/AdjustCenter").c_str()));
 248   AdjustFloor = dAtob(configSettings->value(String(configName + "/Meshes/AdjustFloor").c_str()));
 249   CollapseSubmeshes = dAtob(configSettings->value(String(configName + "/Meshes/CollapseSubmeshes").c_str()));
 250   LODType = configSettings->value(String(configName + "/Meshes/LODType").c_str());
 251   AlwaysImportedNodes = configSettings->value(String(configName + "/Meshes/AlwaysImportedNodes").c_str());
 252   AlwaysIgnoreNodes = configSettings->value(String(configName + "/Meshes/AlwaysIgnoreNodes").c_str());
 253   AlwaysImportMeshes = configSettings->value(String(configName + "/Meshes/AlwaysImportMeshes").c_str());
 254   AlwaysIgnoreMeshes = configSettings->value(String(configName + "/Meshes/AlwaysIgnoreMeshes").c_str());
 255
 256   //Assimp/Collada
 257   convertLeftHanded = dAtob(configSettings->value(String(configName + "/Meshes/convertLeftHanded").c_str()));
 258   calcTangentSpace = dAtob(configSettings->value(String(configName + "/Meshes/calcTangentSpace").c_str()));
 259   removeRedundantMats = dAtob(configSettings->value(String(configName + "/Meshes/removeRedundantMats").c_str()));
 260   genUVCoords = dAtob(configSettings->value(String(configName + "/Meshes/genUVCoords").c_str()));
 261   TransformUVs = dAtob(configSettings->value(String(configName + "/Meshes/TransformUVs").c_str()));
 262   flipUVCoords = dAtob(configSettings->value(String(configName + "/Meshes/flipUVCoords").c_str()));
 263   findInstances = dAtob(configSettings->value(String(configName + "/Meshes/findInstances").c_str()));
 264   limitBoneWeights = dAtob(configSettings->value(String(configName + "/Meshes/limitBoneWeights").c_str()));
 265   JoinIdenticalVerts = dAtob(configSettings->value(String(configName + "/Meshes/JoinIdenticalVerts").c_str()));
 266   reverseWindingOrder = dAtob(configSettings->value(String(configName + "/Meshes/reverseWindingOrder").c_str()));
 267   invertNormals = dAtob(configSettings->value(String(configName + "/Meshes/invertNormals").c_str()));
 268
 269   //Materials
 270   ImportMaterials = dAtob(configSettings->value(String(configName + "/Materials/ImportMaterials").c_str()));
 271   AlwaysAddMaterialSuffix = dAtob(configSettings->value(String(configName + "/Materials/AlwaysAddMaterialSuffix").c_str()));
 272   AddedMaterialSuffix = configSettings->value(String(configName + "/Materials/AddedMaterialSuffix").c_str());
 273   CreateORMConfig = dAtob(configSettings->value(String(configName + "/Materials/CreateORMConfig").c_str()));
 274   UseDiffuseSuffixOnOriginImage = dAtob(configSettings->value(String(configName + "/Materials/UseDiffuseSuffixOnOriginImage").c_str()));
 275   UseExistingMaterials = dAtob(configSettings->value(String(configName + "/Materials/UseExistingMaterials").c_str()));
 276   IgnoreMaterials = configSettings->value(String(configName + "/Materials/IgnoreMaterials").c_str());
 277   PopulateMaterialMaps = dAtob(configSettings->value(String(configName + "/Materials/PopulateMaterialMaps").c_str()));
 278
 279   //Animations
 280   ImportAnimations = dAtob(configSettings->value(String(configName + "/Animations/ImportAnimations").c_str()));
 281   SeparateAnimations = dAtob(configSettings->value(String(configName + "/Animations/SeparateAnimations").c_str()));
 282   SeparateAnimationPrefix = configSettings->value(String(configName + "/Animations/SeparateAnimationPrefix").c_str());
 283   animTiming = configSettings->value(String(configName + "/Animations/animTiming").c_str());
 284   animFPS = dAtof(configSettings->value(String(configName + "/Animations/animFPS").c_str()));
 285
 286   //Collisions
 287   GenerateCollisions = dAtob(configSettings->value(String(configName + "/Collision/GenerateCollisions").c_str()));
 288   GenCollisionType = configSettings->value(String(configName + "/Collision/GenCollisionType").c_str());
 289   CollisionMeshPrefix = configSettings->value(String(configName + "/Collision/CollisionMeshPrefix").c_str());
 290   GenerateLOSCollisions = dAtob(configSettings->value(String(configName + "/Collision/GenerateLOSCollisions").c_str()));
 291   GenLOSCollisionType = configSettings->value(String(configName + "/Collision/GenLOSCollisionType").c_str());
 292   LOSCollisionMeshPrefix = configSettings->value(String(configName + "/Collision/LOSCollisionMeshPrefix").c_str());
 293
 294   //Images
 295   importImages = dAtob(configSettings->value(String(configName + "/Images/importImages").c_str()));
 296   AlwaysAddImageSuffix = dAtob(configSettings->value(String(configName + "/Images/AlwaysAddImageSuffix").c_str()));
 297   AddedImageSuffix = configSettings->value(String(configName + "/Images/AddedImageSuffix").c_str());
 298   ImageType = configSettings->value(String(configName + "/Images/ImageType").c_str());
 299   DiffuseTypeSuffixes = configSettings->value(String(configName + "/Images/DiffuseTypeSuffixes").c_str());
 300   NormalTypeSuffixes = configSettings->value(String(configName + "/Images/NormalTypeSuffixes").c_str());
 301   MetalnessTypeSuffixes = configSettings->value(String(configName + "/Images/MetalnessTypeSuffixes").c_str());
 302   RoughnessTypeSuffixes = configSettings->value(String(configName + "/Images/RoughnessTypeSuffixes").c_str());
 303   SmoothnessTypeSuffixes = configSettings->value(String(configName + "/Images/SmoothnessTypeSuffixes").c_str());
 304   AOTypeSuffixes = configSettings->value(String(configName + "/Images/AOTypeSuffixes").c_str());
 305   PBRTypeSuffixes = configSettings->value(String(configName + "/Images/PBRTypeSuffixes").c_str());
 306   TextureFilteringMode = configSettings->value(String(configName + "/Images/TextureFilteringMode").c_str());
 307   UseMips = dAtob(configSettings->value(String(configName + "/Images/UseMips").c_str()));
 308   IsHDR = dAtob(configSettings->value(String(configName + "/Images/IsHDR").c_str()));
 309   Scaling = dAtof(configSettings->value(String(configName + "/Images/Scaling").c_str()));
 310   ImagesCompressed = dAtob(configSettings->value(String(configName + "/Images/Compressed").c_str()));
 311   GenerateMaterialOnImport = dAtob(configSettings->value(String(configName + "/Images/GenerateMaterialOnImport").c_str()));
 312
 313   //Sounds
 314   VolumeAdjust = dAtof(configSettings->value(String(configName + "/Sounds/VolumeAdjust").c_str()));
 315   PitchAdjust = dAtof(configSettings->value(String(configName + "/Sounds/PitchAdjust").c_str()));
 316   SoundsCompressed = dAtob(configSettings->value(String(configName + "/Sounds/Compressed").c_str()));
 317}
 318
 319void AssetImportConfig::CopyTo(AssetImportConfig* target) const
 320{
 321   target->DuplicatAutoResolution = DuplicatAutoResolution;
 322   target->WarningsAsErrors = WarningsAsErrors;
 323   target->PreventImportWithErrors = PreventImportWithErrors;
 324   target->AutomaticallyPromptMissingFiles = AutomaticallyPromptMissingFiles;
 325
 326   //Meshes
 327   target->ImportMesh = ImportMesh;
 328   target->AlwaysAddShapeSuffix = AlwaysAddShapeSuffix;
 329   target->AddedShapeSuffix = AddedShapeSuffix;
 330   target->UseManualShapeConfigRules = UseManualShapeConfigRules;
 331   target->DoUpAxisOverride = DoUpAxisOverride;
 332   target->UpAxisOverride = UpAxisOverride;
 333   target->DoScaleOverride = DoScaleOverride;
 334   target->ScaleOverride = ScaleOverride;
 335   target->IgnoreNodeScale = IgnoreNodeScale;
 336   target->AdjustCenter = AdjustCenter;
 337   target->AdjustFloor = AdjustFloor;
 338   target->CollapseSubmeshes = CollapseSubmeshes;
 339   target->LODType = LODType;
 340   target->AlwaysImportedNodes = AlwaysImportedNodes;
 341   target->AlwaysIgnoreNodes = AlwaysIgnoreNodes;
 342   target->AlwaysImportMeshes = AlwaysImportMeshes;
 343   target->AlwaysIgnoreMeshes = AlwaysIgnoreMeshes;
 344
 345   //Assimp/Collada
 346   target->convertLeftHanded = convertLeftHanded;
 347   target->calcTangentSpace = calcTangentSpace;
 348   target->removeRedundantMats = removeRedundantMats;
 349   target->genUVCoords = genUVCoords;
 350   target->TransformUVs = TransformUVs;
 351   target->flipUVCoords = flipUVCoords;
 352   target->findInstances = findInstances;
 353   target->limitBoneWeights = limitBoneWeights;
 354   target->JoinIdenticalVerts = JoinIdenticalVerts;
 355   target->reverseWindingOrder = reverseWindingOrder;
 356   target->invertNormals = invertNormals;
 357
 358   //Materials
 359   target->ImportMaterials = ImportMaterials;
 360   target->AlwaysAddMaterialSuffix = AlwaysAddMaterialSuffix;
 361   target->AddedMaterialSuffix = AddedMaterialSuffix;
 362   target->CreateORMConfig = CreateORMConfig;
 363   target->UseDiffuseSuffixOnOriginImage = UseDiffuseSuffixOnOriginImage;
 364   target->UseExistingMaterials = UseExistingMaterials;
 365   target->IgnoreMaterials = IgnoreMaterials;
 366   target->PopulateMaterialMaps = PopulateMaterialMaps;
 367
 368   //Animations
 369   target->ImportAnimations = ImportAnimations;
 370   target->SeparateAnimations = SeparateAnimations;
 371   target->SeparateAnimationPrefix = SeparateAnimationPrefix;
 372   target->animTiming = animTiming;
 373   target->animFPS = animFPS;
 374
 375   //Collisions
 376   target->GenerateCollisions = GenerateCollisions;
 377   target->GenCollisionType = GenCollisionType;
 378   target->CollisionMeshPrefix = CollisionMeshPrefix;
 379   target->GenerateLOSCollisions = GenerateLOSCollisions;
 380   target->GenLOSCollisionType = GenLOSCollisionType;
 381   target->LOSCollisionMeshPrefix = LOSCollisionMeshPrefix;
 382
 383   //Images
 384   target->importImages = importImages;
 385   target->AlwaysAddImageSuffix = AlwaysAddImageSuffix;
 386   target->AddedImageSuffix = AddedImageSuffix;
 387   target->ImageType = ImageType;
 388   target->DiffuseTypeSuffixes = DiffuseTypeSuffixes;
 389   target->NormalTypeSuffixes = NormalTypeSuffixes;
 390   target->MetalnessTypeSuffixes = MetalnessTypeSuffixes;
 391   target->RoughnessTypeSuffixes = RoughnessTypeSuffixes;
 392   target->SmoothnessTypeSuffixes = SmoothnessTypeSuffixes;
 393   target->AOTypeSuffixes = AOTypeSuffixes;
 394   target->PBRTypeSuffixes = PBRTypeSuffixes;
 395   target->TextureFilteringMode = TextureFilteringMode;
 396   target->UseMips = UseMips;
 397   target->IsHDR = IsHDR;
 398   target->Scaling = Scaling;
 399   target->ImagesCompressed = ImagesCompressed;
 400   target->GenerateMaterialOnImport = GenerateMaterialOnImport;
 401
 402   //Sounds
 403   target->VolumeAdjust = VolumeAdjust;
 404   target->PitchAdjust = PitchAdjust;
 405   target->SoundsCompressed = SoundsCompressed;
 406}
 407
 408ConsoleDocClass(AssetImportObject,
 409   "@brief Defines properties for an AssetImportObject object.\n"
 410   "@AssetImportObject is a SimObject derived object intended to act as a stand-in for the to-be imported objects.\n"
 411   "@It contains important info such as dependencies, if it's been processed, any error/status issues and the originating file\n"
 412   "@or if it's been programmatically generated as part of the import process.\n\n"
 413   "@ingroup Assets\n"
 414);
 415
 416IMPLEMENT_CONOBJECT(AssetImportObject);
 417
 418AssetImportObject::AssetImportObject() :
 419   dirty(false),
 420   skip(false),
 421   processed(false),
 422   generatedAsset(false),
 423   parentAssetItem(nullptr),
 424   tamlFilePath(""),
 425   imageSuffixType(""),
 426   shapeInfo(nullptr),
 427   filePathString(StringTable->EmptyString())
 428{
 429
 430}
 431
 432AssetImportObject::~AssetImportObject()
 433{
 434
 435}
 436
 437bool AssetImportObject::onAdd()
 438{
 439   if (!Parent::onAdd())
 440      return false;
 441
 442   return true;
 443}
 444
 445void AssetImportObject::onRemove()
 446{
 447   Parent::onRemove();
 448}
 449
 450void AssetImportObject::initPersistFields()
 451{
 452   Parent::initPersistFields();
 453
 454   addField("assetType", TypeRealString, Offset(assetType, AssetImportObject), "What type is the importing asset");
 455   addProtectedField("filePath", TypeFilename, Offset(filePathString, AssetImportObject), &_setFilePath, &defaultProtectedGetFn, "What is the source file path of the importing asset");
 456   addField("assetName", TypeRealString, Offset(assetName, AssetImportObject), "What is the asset's name");
 457   addField("cleanAssetName", TypeRealString, Offset(cleanAssetName, AssetImportObject), "What is the original, unmodified by processing, asset name");
 458   addField("status", TypeRealString, Offset(status, AssetImportObject), "What is the current status of this asset item in it's import process");
 459   addField("statusType", TypeRealString, Offset(statusType, AssetImportObject), "If there is a warning or error status, what type is the condition for this asset item");
 460   addField("statusInfo", TypeRealString, Offset(statusInfo, AssetImportObject), "What is the articulated information of the status of the asset. Contains the error or warning log data");
 461
 462   addField("dirty", TypeBool, Offset(dirty, AssetImportObject), "Is the asset item currently flagged as dirty");
 463   addField("skip", TypeBool, Offset(skip, AssetImportObject), "Is this asset item marked to be skipped. If it is, it's usually due to being marked as deleted");
 464   addField("processed", TypeBool, Offset(processed, AssetImportObject), "Has the asset item been processed");
 465   addField("generatedAsset", TypeBool, Offset(generatedAsset, AssetImportObject), "Is this specific asset item generated as part of the import process of another item");
 466
 467   addField("tamlFilePath", TypeRealString, Offset(tamlFilePath, AssetImportObject), "What is the ultimate asset taml file path for this import item");
 468
 469   addField("imageType", TypeRealString, Offset(imageSuffixType, AssetImportObject), "Specific to ImageAsset type. What is the image asset's suffix type. Options are: Albedo, Normal, Roughness, AO, Metalness, ORMConfig");
 470
 471   addField("shapeInfo", TYPEID< GuiTreeViewCtrl >(), Offset(shapeInfo, AssetImportObject), "Specific to ShapeAsset type. Processed information about the shape file. Contains numbers and lists of meshes, materials and animations");
 472}
 473
 474bool AssetImportObject::_setFilePath(void* obj, const char* index, const char* data)
 475{
 476   AssetImportObject* importObj = static_cast<AssetImportObject*>(obj);
 477   importObj->setFilePath(StringTable->insert(data));
 478
 479   return false;
 480}
 481
 482void AssetImportObject::setFilePath(StringTableEntry pFilePath)
 483{
 484   filePathString = pFilePath;
 485   filePath = Torque::Path(pFilePath);
 486}
 487
 488ConsoleDocClass(AssetImporter,
 489   "@brief Defines properties for an AssetImportObject object.\n"
 490   "@AssetImportObject is a SimObject derived object intended to act as a stand-in for the to-be imported objects.\n"
 491   "@It contains important info such as dependencies, if it's been processed, any error/status issues and the originating file\n"
 492   "@or if it's been programmatically generated as part of the import process.\n\n"
 493   "@ingroup Assets\n"
 494);
 495
 496IMPLEMENT_CONOBJECT(AssetImporter);
 497
 498AssetImporter::AssetImporter() :
 499   importIssues(false),
 500   isReimport(false),
 501   assetHeirarchyChanged(false),
 502   importLogBuffer(""),
 503   activeImportConfig(nullptr)
 504{
 505}
 506
 507AssetImporter::~AssetImporter()
 508{
 509}
 510
 511bool AssetImporter::onAdd()
 512{
 513   if (!Parent::onAdd())
 514      return false;
 515
 516   return true;
 517}
 518
 519void AssetImporter::onRemove()
 520{
 521   Parent::onRemove();
 522}
 523
 524void AssetImporter::initPersistFields()
 525{
 526   Parent::initPersistFields();
 527
 528   addField("targetModuleId", TypeRealString, Offset(targetModuleId, AssetImporter), "The Id of the module the assets are to be imported into");
 529   addField("finalImportedAssetPath", TypeRealString, Offset(finalImportedAssetPath, AssetImporter), "The Id of the module the assets are to be imported into");
 530   addField("targetPath", TypeRealString, Offset(targetPath, AssetImporter), "The path any imported assets are placed in as their destination");
 531}
 532
 533//
 534// Utility Functions
 535//
 536
 537AssetImportObject* AssetImporter::addImportingFile(Torque::Path filePath)
 538{
 539   String assetType = getAssetTypeByFile(filePath);
 540
 541   if (assetType.isEmpty())
 542   {
 543      dSprintf(importLogBuffer, sizeof(importLogBuffer), "Unable to import file %s because it is of an unrecognized/unsupported type.", filePath.getFullPath().c_str());
 544      activityLog.push_back(importLogBuffer);
 545      return nullptr;
 546   }
 547
 548   AssetImportObject* newAssetItem = addImportingAsset(assetType, filePath, nullptr, "");
 549
 550   originalImportingFiles.push_back(filePath);
 551
 552   return newAssetItem;
 553}
 554
 555void AssetImporter::addImportingAssetItem(AssetImportObject* assetItem, AssetImportObject* parentItem)
 556{
 557   if (assetItem == nullptr)
 558   {
 559      dSprintf(importLogBuffer, sizeof(importLogBuffer), "Cannot add a null AssetImportObject to import session!");
 560      activityLog.push_back(importLogBuffer);
 561      return;
 562   }
 563
 564   if (parentItem != nullptr)
 565   {
 566      dSprintf(importLogBuffer, sizeof(importLogBuffer), "Added Child Importing Asset to %s", parentItem->assetName.c_str());
 567      activityLog.push_back(importLogBuffer);
 568
 569      parentItem->childAssetItems.push_back(assetItem);
 570      assetItem->parentAssetItem = parentItem;
 571   }
 572   else
 573   {
 574      dSprintf(importLogBuffer, sizeof(importLogBuffer), "Added Importing Asset");
 575      activityLog.push_back(importLogBuffer);
 576      importingAssets.push_back(assetItem);
 577   }
 578
 579   dSprintf(importLogBuffer, sizeof(importLogBuffer), "   Asset Info: Name: %s | Type: %s", assetItem->assetName.c_str(), assetItem->assetType.c_str());
 580   activityLog.push_back(importLogBuffer);
 581
 582   if (!assetItem->filePath.isEmpty())
 583   {
 584      dSprintf(importLogBuffer, sizeof(importLogBuffer), "   File: %s", assetItem->filePath.getFullPath().c_str());
 585      activityLog.push_back(importLogBuffer);
 586   }
 587}
 588
 589AssetImportObject* AssetImporter::addImportingAsset(String assetType, Torque::Path filePath, AssetImportObject* parentItem, String assetNameOverride)
 590{
 591   String assetName;
 592
 593   //In some cases(usually generated assets on import, like materials) we'll want to specifically define the asset name instead of peeled from the filePath
 594   if (assetNameOverride.isNotEmpty())
 595      assetName = assetNameOverride;
 596   else
 597      assetName = filePath.getFileName();
 598
 599   AssetImportObject* assetImportObj = new AssetImportObject();
 600   assetImportObj->registerObject();
 601
 602   //sanitize
 603   assetName.replace(" ", "_");
 604
 605   assetImportObj->assetType = assetType;
 606   assetImportObj->filePath = filePath;
 607   assetImportObj->filePathString = StringTable->insert(filePath.getFullPath().c_str());
 608   assetImportObj->assetName = assetName;
 609   assetImportObj->cleanAssetName = assetName;
 610   assetImportObj->moduleName = targetModuleId;
 611   assetImportObj->status = "";
 612   assetImportObj->statusType = "";
 613   assetImportObj->statusInfo = "";
 614
 615   assetImportObj->dirty = false;
 616   assetImportObj->skip = false;
 617   assetImportObj->processed = false;
 618   assetImportObj->generatedAsset = false;
 619
 620   if (parentItem != nullptr)
 621   {
 622      dSprintf(importLogBuffer, sizeof(importLogBuffer), "Added Child Importing Asset to %s", parentItem->assetName.c_str());
 623      activityLog.push_back(importLogBuffer);
 624
 625      parentItem->childAssetItems.push_back(assetImportObj);
 626      assetImportObj->parentAssetItem = parentItem;
 627   }
 628   else
 629   {
 630      dSprintf(importLogBuffer, sizeof(importLogBuffer), "Added Importing Asset");
 631      activityLog.push_back(importLogBuffer);
 632
 633      importingAssets.push_back(assetImportObj);
 634   }
 635
 636   dSprintf(importLogBuffer, sizeof(importLogBuffer), "   Asset Info: Name: %s | Type: %s", assetImportObj->assetName.c_str(), assetImportObj->assetType.c_str());
 637   activityLog.push_back(importLogBuffer);
 638
 639   if (!filePath.isEmpty())
 640   {
 641      dSprintf(importLogBuffer, sizeof(importLogBuffer), "   File: %s", filePath.getFullPath().c_str());
 642      activityLog.push_back(importLogBuffer);
 643   }
 644
 645   return assetImportObj;
 646}
 647
 648void AssetImporter::deleteImportingAsset(AssetImportObject* assetItem)
 649{
 650   assetItem->skip = true;
 651
 652   //log it
 653   dSprintf(importLogBuffer, sizeof(importLogBuffer), "Deleting Importing Asset %s and all it's child items", assetItem->assetName.c_str());
 654   activityLog.push_back(importLogBuffer);
 655}
 656
 657AssetImportObject* AssetImporter::findImportingAssetByName(String assetName, AssetImportObject* assetItem)
 658{
 659   if (assetItem == nullptr)
 660   {
 661      for (U32 i = 0; i < importingAssets.size(); i++)
 662      {
 663         if (importingAssets[i]->cleanAssetName == assetName)
 664         {
 665            return importingAssets[i];
 666         }
 667
 668         //If it wasn't a match, try recusing on the children(if any)
 669         AssetImportObject* retItem = findImportingAssetByName(assetName, importingAssets[i]);
 670         if (retItem != nullptr)
 671            return retItem;
 672      }
 673   }
 674   else
 675   {
 676      //this is the child recursing section
 677      for (U32 i = 0; i < assetItem->childAssetItems.size(); i++)
 678      {
 679         if (assetItem->childAssetItems[i]->cleanAssetName == assetName)
 680         {
 681            return assetItem->childAssetItems[i];
 682         }
 683
 684         //If it wasn't a match, try recusing on the children(if any)
 685         AssetImportObject* retItem = findImportingAssetByName(assetName, assetItem->childAssetItems[i]);
 686         if (retItem != nullptr)
 687            return retItem;
 688      }
 689   }
 690
 691   return nullptr;
 692}
 693
 694ModuleDefinition* AssetImporter::getModuleFromPath(Torque::Path filePath)
 695{
 696   //We want to ensure it's a full filepath, because the module system internally uses full paths for the module dirs
 697   char fullPath[2048];
 698   Platform::makeFullPathName(filePath.getFullPath().c_str(), fullPath, sizeof(fullPath));
 699
 700   ModuleDefinition* moduleDef = ModuleDatabase.findModuleByFilePath(StringTable->insert(fullPath));
 701
 702   return moduleDef;
 703}
 704
 705String AssetImporter::parseImageSuffixes(String assetName, String* suffixType)
 706{
 707   //Here, we loop over our different suffix lists progressively.
 708   //This lets us walk through a list of suffixes in the Import Config, such as DiffuseTypeSuffixes
 709   //And then iterate over the delinated list of items within it to look for a match.
 710   //If we don't find a match, we then increment our list switch index and scan through the next list.
 711   U32 suffixTypeIdx = 0;
 712   while (suffixTypeIdx < 6)
 713   {
 714      String suffixList;
 715      switch (suffixTypeIdx)
 716      {
 717         case 0:
 718            suffixList = activeImportConfig->DiffuseTypeSuffixes;
 719            suffixType->insert(0, "Albedo", 10);
 720            break;
 721         case 1:
 722            suffixList = activeImportConfig->NormalTypeSuffixes;
 723            suffixType->insert(0, "Normal", 10);
 724            break;
 725         case 2:
 726            suffixList = activeImportConfig->RoughnessTypeSuffixes;
 727            suffixType->insert(0, "Roughness", 10);
 728            break;
 729         case 3:
 730            suffixList = activeImportConfig->AOTypeSuffixes;
 731            suffixType->insert(0, "AO", 10);
 732            break;
 733         case 4:
 734            suffixList = activeImportConfig->MetalnessTypeSuffixes;
 735            suffixType->insert(0, "Metalness", 10);
 736            break;
 737         case 5:
 738            suffixList = activeImportConfig->PBRTypeSuffixes;
 739            suffixType->insert(0, "ORMConfig", 10);
 740            break;
 741         default:
 742            suffixList = "";
 743      }
 744
 745      suffixTypeIdx++;
 746
 747      U32 suffixCount = StringUnit::getUnitCount(suffixList, ",;\t");
 748      for (U32 i = 0; i < suffixCount; i++)
 749      {
 750         String suffix = StringUnit::getUnit(suffixList, i, ",;\t");
 751         String searchSuffix = String("*") + suffix;
 752
 753         if (FindMatch::isMatch(searchSuffix.c_str(), assetName.c_str(), false))
 754         {
 755            //We have a match, so indicate as such
 756            S32 pos = assetName.length();
 757            pos -= searchSuffix.length();
 758            suffix = assetName.substr(pos+1);
 759            return suffix;
 760         }
 761      }
 762   }
 763
 764   suffixType->clear();
 765   return "";
 766}
 767
 768String AssetImporter::getAssetTypeByFile(Torque::Path filePath)
 769{
 770   String fileExt = String::ToLower(filePath.getExtension());
 771   String fileName = String::ToLower(filePath.getFileName());
 772
 773   if (fileExt == String("dts") && fileName.endsWith("cached"))
 774      return "";
 775
 776   if (fileExt == String("png") || fileExt == String("jpg") || fileExt == String("jpeg") || fileExt == String("dds"))
 777      return "ImageAsset";
 778   else if (fileExt == String("dae") || fileExt == String("fbx") || fileExt == String("blend") || fileExt == String("obj") || fileExt == String("dts") || fileExt == String("gltf") || fileExt == String("gltb"))
 779      return "ShapeAsset";
 780   else if (fileExt == String("dsq"))
 781      return "ShapeAnimationAsset";
 782   else if (fileExt == String("ogg") || fileExt == String("wav") || fileExt == String("mp3"))
 783      return "SoundAsset";
 784   else if (fileExt == String("zip"))
 785      return "Zip";
 786   else if (fileExt.isEmpty())
 787      return "Folder";
 788
 789   return "";
 790}
 791
 792String AssetImporter::getTrueFilename(const String& fileName)
 793{
 794   Torque::Path pth(fileName);
 795   String pattern = pth.getFullPath() + "*";
 796
 797   static const String sSlash("/");
 798
 799   Vector<String> findFilesResults;
 800
 801   String sPattern(Torque::Path::CleanSeparators(pattern));
 802   if (sPattern.isEmpty())
 803   {
 804      Con::errorf("findFirstFile() requires a search pattern");
 805      return "";
 806   }
 807
 808   char scriptFilenameBuffer[1024];
 809
 810   if (!Con::expandScriptFilename(scriptFilenameBuffer, sizeof(scriptFilenameBuffer), sPattern.c_str()))
 811   {
 812      Con::errorf("findFirstFile() given initial directory cannot be expanded: '%s'", pattern.c_str());
 813      return "";
 814   }
 815   sPattern = String::ToString(scriptFilenameBuffer);
 816
 817   String::SizeType slashPos = sPattern.find('/', 0, String::Right);
 818   //    if(slashPos == String::NPos)
 819   //    {
 820   //       Con::errorf("findFirstFile() missing search directory or expression: '%s'", sPattern.c_str());
 821   //       return -1;
 822   //    }
 823
 824      // Build the initial search path
 825   Torque::Path givenPath(Torque::Path::CompressPath(sPattern));
 826   givenPath.setFileName("*");
 827   givenPath.setExtension("*");
 828
 829   if (givenPath.getPath().length() > 0 && givenPath.getPath().find('*', 0, String::Right) == givenPath.getPath().length() - 1)
 830   {
 831      // Deal with legacy searches of the form '*/*.*'
 832      String suspectPath = givenPath.getPath();
 833      String::SizeType newLen = suspectPath.length() - 1;
 834      if (newLen > 0 && suspectPath.find('/', 0, String::Right) == suspectPath.length() - 2)
 835      {
 836         --newLen;
 837      }
 838      givenPath.setPath(suspectPath.substr(0, newLen));
 839   }
 840
 841   Torque::FS::FileSystemRef fs = Torque::FS::GetFileSystem(givenPath);
 842   //Torque::Path path = fs->mapTo(givenPath);
 843   Torque::Path path = givenPath;
 844
 845   // Make sure that we have a root so the correct file system can be determined when using zips
 846   if (givenPath.isRelative())
 847      path = Torque::Path::Join(Torque::FS::GetCwd(), '/', givenPath);
 848
 849   path.setFileName(String::EmptyString);
 850   path.setExtension(String::EmptyString);
 851   if (!Torque::FS::IsDirectory(path))
 852   {
 853      Con::errorf("findFirstFile() invalid initial search directory: '%s'", path.getFullPath().c_str());
 854      return "";
 855   }
 856
 857   // Build the search expression
 858   const String expression(slashPos != String::NPos ? sPattern.substr(slashPos + 1) : sPattern);
 859   if (expression.isEmpty())
 860   {
 861      Con::errorf("findFirstFile() requires a search expression: '%s'", sPattern.c_str());
 862      return "";
 863   }
 864
 865   S32 results = Torque::FS::FindByPattern(path, expression, false, findFilesResults, false);
 866   if (givenPath.isRelative() && results > 0)
 867   {
 868      // Strip the CWD out of the returned paths
 869      // MakeRelativePath() returns incorrect results (it adds a leading ..) so doing this the dirty way
 870      const String cwd = Torque::FS::GetCwd().getFullPath();
 871      for (S32 i = 0; i < findFilesResults.size(); ++i)
 872      {
 873         String str = findFilesResults[i];
 874         if (str.compare(cwd, cwd.length(), String::NoCase) == 0)
 875            str = str.substr(cwd.length());
 876         findFilesResults[i] = str;
 877      }
 878   }
 879
 880   for (U32 i = 0; i < findFilesResults.size(); i++)
 881   {
 882      if (!findFilesResults[i].compare(fileName, 0, String::NoCase</a>|<a href="/coding/class/classstring/#classstring_1ad23530ba3c445d964722346a3c80771da84aa4530ee3fa8bfa8e0c2305744bff8">String::Left))
 883         return findFilesResults[i];
 884   }
 885
 886   return "";
 887}
 888
 889void AssetImporter::resetImportSession(bool hardClearSession)
 890{
 891   importingAssets.clear();
 892   activityLog.clear();
 893
 894   if (hardClearSession)
 895   {
 896      originalImportingFiles.clear();
 897   }
 898   else
 899   {
 900      Vector<Torque::Path> tempImportingFiles = originalImportingFiles;
 901      originalImportingFiles.clear();
 902
 903      for (U32 i = 0; i < tempImportingFiles.size(); i++)
 904      {
 905         addImportingFile(tempImportingFiles[i]);
 906      }
 907   }
 908}
 909
 910S32 AssetImporter::getActivityLogLineCount()
 911{
 912   return activityLog.size();
 913}
 914
 915String AssetImporter::getActivityLogLine(U32 line)
 916{
 917   if (line >= activityLog.size())
 918      return "";
 919
 920   return activityLog[line];
 921}
 922
 923void AssetImporter::dumpActivityLog()
 924{
 925   for (U32 i = 0; i < activityLog.size(); i++)
 926   {
 927      Con::printf(activityLog[i].c_str());
 928   }
 929}
 930
 931S32 AssetImporter::getAssetItemCount()
 932{
 933   return importingAssets.size();
 934}
 935
 936AssetImportObject* AssetImporter::getAssetItem(U32 index)
 937{
 938   if (index >= importingAssets.size())
 939      return nullptr;
 940
 941   return importingAssets[index];
 942}
 943
 944S32 AssetImporter::getAssetItemChildCount(AssetImportObject* assetItem)
 945{
 946   return assetItem->childAssetItems.size();
 947}
 948
 949AssetImportObject* AssetImporter::getAssetItemChild(AssetImportObject* assetItem, U32 index)
 950{
 951   if (index >= assetItem->childAssetItems.size())
 952      return nullptr;
 953
 954   return assetItem->childAssetItems[index];
 955}
 956//
 957// Processing
 958//
 959// Helper struct for counting nodes, meshes and polygons down through the scene
 960// hierarchy
 961struct SceneStats
 962{
 963   S32 numNodes;
 964   S32 numMeshes;
 965   S32 numPolygons;
 966   S32 numMaterials;
 967   S32 numLights;
 968   S32 numClips;
 969
 970   SceneStats() : numNodes(0), numMeshes(0), numPolygons(0), numMaterials(0), numLights(0), numClips(0) { }
 971};
 972
 973// Recurse through the <visual_scene> adding nodes and geometry to the GuiTreeView control
 974static void processNode(GuiTreeViewCtrl* tree, domNode* node, S32 parentID, SceneStats& stats)
 975{
 976   stats.numNodes++;
 977   S32 nodeID = tree->insertItem(parentID, _GetNameOrId(node), "node", "", 0, 0);
 978
 979   // Update mesh and poly counts
 980   for (S32 i = 0; i < node->getContents().getCount(); i++)
 981   {
 982      domGeometry* geom = 0;
 983      const char* elemName = "";
 984
 985      daeElement* child = node->getContents()[i];
 986      switch (child->getElementType())
 987      {
 988      case COLLADA_TYPE::INSTANCE_GEOMETRY:
 989      {
 990         domInstance_geometry* instgeom = daeSafeCast<domInstance_geometry>(child);
 991         if (instgeom)
 992         {
 993            geom = daeSafeCast<domGeometry>(instgeom->getUrl().getElement());
 994            elemName = _GetNameOrId(geom);
 995         }
 996         break;
 997      }
 998
 999      case COLLADA_TYPE::INSTANCE_CONTROLLER:
1000      {
1001         domInstance_controller* instctrl = daeSafeCast<domInstance_controller>(child);
1002         if (instctrl)
1003         {
1004            domController* ctrl = daeSafeCast<domController>(instctrl->getUrl().getElement());
1005            elemName = _GetNameOrId(ctrl);
1006            if (ctrl && ctrl->getSkin())
1007               geom = daeSafeCast<domGeometry>(ctrl->getSkin()->getSource().getElement());
1008            else if (ctrl && ctrl->getMorph())
1009               geom = daeSafeCast<domGeometry>(ctrl->getMorph()->getSource().getElement());
1010         }
1011         break;
1012      }
1013
1014      case COLLADA_TYPE::INSTANCE_LIGHT:
1015         stats.numLights++;
1016         tree->insertItem(nodeID, _GetNameOrId(node), "light", "", 0, 0);
1017         break;
1018      }
1019
1020      if (geom && geom->getMesh())
1021      {
1022         const char* name = _GetNameOrId(node);
1023         if (dStrEqual(name, "null") || dStrEndsWith(name, "PIVOT"))
1024            name = _GetNameOrId(daeSafeCast<domNode>(node->getParent()));
1025
1026         stats.numMeshes++;
1027         tree->insertItem(nodeID, name, "mesh", "", 0, 0);
1028
1029         for (S32 j = 0; j < geom->getMesh()->getTriangles_array().getCount(); j++)
1030            stats.numPolygons += geom->getMesh()->getTriangles_array()[j]->getCount();
1031         for (S32 j = 0; j < geom->getMesh()->getTristrips_array().getCount(); j++)
1032            stats.numPolygons += geom->getMesh()->getTristrips_array()[j]->getCount();
1033         for (S32 j = 0; j < geom->getMesh()->getTrifans_array().getCount(); j++)
1034            stats.numPolygons += geom->getMesh()->getTrifans_array()[j]->getCount();
1035         for (S32 j = 0; j < geom->getMesh()->getPolygons_array().getCount(); j++)
1036            stats.numPolygons += geom->getMesh()->getPolygons_array()[j]->getCount();
1037         for (S32 j = 0; j < geom->getMesh()->getPolylist_array().getCount(); j++)
1038            stats.numPolygons += geom->getMesh()->getPolylist_array()[j]->getCount();
1039      }
1040   }
1041
1042   // Recurse into child nodes
1043   for (S32 i = 0; i < node->getNode_array().getCount(); i++)
1044      processNode(tree, node->getNode_array()[i], nodeID, stats);
1045
1046   for (S32 i = 0; i < node->getInstance_node_array().getCount(); i++)
1047   {
1048      domInstance_node* instnode = node->getInstance_node_array()[i];
1049      domNode* dNode = daeSafeCast<domNode>(instnode->getUrl().getElement());
1050      if (dNode)
1051         processNode(tree, dNode, nodeID, stats);
1052   }
1053}
1054
1055static bool enumColladaForImport(const char* shapePath, GuiTreeViewCtrl* tree, bool loadCachedDts)
1056{
1057   // Check if a cached DTS is available => no need to import the collada file
1058   // if we can load the DTS instead
1059   Torque::Path path(shapePath);
1060   if (loadCachedDts && ColladaShapeLoader::canLoadCachedDTS(path))
1061      return false;
1062
1063   // Check if this is a Sketchup file (.kmz) and if so, mount the zip filesystem
1064   // and get the path to the DAE file.
1065   String mountPoint;
1066   Torque::Path daePath;
1067   bool isSketchup = ColladaShapeLoader::checkAndMountSketchup(path, mountPoint, daePath);
1068
1069   // Load the Collada file into memory
1070   domCOLLADA* root = ColladaShapeLoader::getDomCOLLADA(daePath);
1071   if (!root)
1072   {
1073      TSShapeLoader::updateProgress(TSShapeLoader::Load_Complete, "Load complete");
1074      return false;
1075   }
1076
1077   if (isSketchup)
1078   {
1079      // Unmount the zip if we mounted it
1080      Torque::FS::Unmount(mountPoint);
1081   }
1082
1083   // Initialize tree
1084   tree->removeItem(0);
1085   S32 nodesID = tree->insertItem(0, "Shape", "", "", 0, 0);
1086   S32 matsID = tree->insertItem(0, "Materials", "", "", 0, 0);
1087   S32 animsID = tree->insertItem(0, "Animations", "", "", 0, 0);
1088
1089   SceneStats stats;
1090
1091   // Query DOM for shape summary details
1092   for (S32 i = 0; i < root->getLibrary_visual_scenes_array().getCount(); i++)
1093   {
1094      const domLibrary_visual_scenes* libScenes = root->getLibrary_visual_scenes_array()[i];
1095      for (S32 j = 0; j < libScenes->getVisual_scene_array().getCount(); j++)
1096      {
1097         const domVisual_scene* visualScene = libScenes->getVisual_scene_array()[j];
1098         for (S32 k = 0; k < visualScene->getNode_array().getCount(); k++)
1099            processNode(tree, visualScene->getNode_array()[k], nodesID, stats);
1100      }
1101   }
1102
1103   // Get material count
1104   for (S32 i = 0; i < root->getLibrary_materials_array().getCount(); i++)
1105   {
1106      const domLibrary_materials* libraryMats = root->getLibrary_materials_array()[i];
1107      stats.numMaterials += libraryMats->getMaterial_array().getCount();
1108      for (S32 j = 0; j < libraryMats->getMaterial_array().getCount(); j++)
1109      {
1110         domMaterial* mat = libraryMats->getMaterial_array()[j];
1111         tree->insertItem(matsID, _GetNameOrId(mat), "", "", 0, 0);
1112      }
1113   }
1114
1115   // Get images count
1116   for (S32 i = 0; i < root->getLibrary_images_array().getCount(); i++)
1117   {
1118      const domLibrary_images* libraryImages = root->getLibrary_images_array()[i];
1119
1120      for (S32 j = 0; j < libraryImages->getImage_array().getCount(); j++)
1121      {
1122         domImage* img = libraryImages->getImage_array()[j];
1123
1124         S32 materialID = tree->findItemByName(_GetNameOrId(img));
1125
1126         if (materialID == 0)
1127            continue;
1128
1129         tree->setItemValue(materialID, img->getInit_from()->getValue().str().c_str());
1130      }
1131   }
1132
1133   // Get animation count
1134   for (S32 i = 0; i < root->getLibrary_animation_clips_array().getCount(); i++)
1135   {
1136      const domLibrary_animation_clips* libraryClips = root->getLibrary_animation_clips_array()[i];
1137      stats.numClips += libraryClips->getAnimation_clip_array().getCount();
1138      for (S32 j = 0; j < libraryClips->getAnimation_clip_array().getCount(); j++)
1139      {
1140         domAnimation_clip* clip = libraryClips->getAnimation_clip_array()[j];
1141         tree->insertItem(animsID, _GetNameOrId(clip), "animation", "", 0, 0);
1142      }
1143   }
1144   if (stats.numClips == 0)
1145   {
1146      // No clips => check if there are any animations (these will be added to a default clip)
1147      for (S32 i = 0; i < root->getLibrary_animations_array().getCount(); i++)
1148      {
1149         const domLibrary_animations* libraryAnims = root->getLibrary_animations_array()[i];
1150         if (libraryAnims->getAnimation_array().getCount())
1151         {
1152            stats.numClips = 1;
1153            tree->insertItem(animsID, "ambient", "animation", "", 0, 0);
1154            break;
1155         }
1156      }
1157   }
1158
1159   // Extract the global scale and up_axis from the top level <asset> element,
1160   F32 unit = 1.0f;
1161   domUpAxisType upAxis = UPAXISTYPE_Z_UP;
1162   if (root->getAsset()) {
1163      if (root->getAsset()->getUnit())
1164         unit = root->getAsset()->getUnit()->getMeter();
1165      if (root->getAsset()->getUp_axis())
1166         upAxis = root->getAsset()->getUp_axis()->getValue();
1167   }
1168
1169   TSShapeLoader::updateProgress(TSShapeLoader::Load_Complete, "Load complete");
1170
1171   // Store shape information in the tree control
1172   tree->setDataField(StringTable->insert("_nodeCount"), 0, avar("%d", stats.numNodes));
1173   tree->setDataField(StringTable->insert("_meshCount"), 0, avar("%d", stats.numMeshes));
1174   tree->setDataField(StringTable->insert("_polygonCount"), 0, avar("%d", stats.numPolygons));
1175   tree->setDataField(StringTable->insert("_materialCount"), 0, avar("%d", stats.numMaterials));
1176   tree->setDataField(StringTable->insert("_lightCount"), 0, avar("%d", stats.numLights));
1177   tree->setDataField(StringTable->insert("_animCount"), 0, avar("%d", stats.numClips));
1178   tree->setDataField(StringTable->insert("_unit"), 0, avar("%g", unit));
1179
1180   if (upAxis == UPAXISTYPE_X_UP)
1181      tree->setDataField(StringTable->insert("_upAxis"), 0, "X_AXIS");
1182   else if (upAxis == UPAXISTYPE_Y_UP)
1183      tree->setDataField(StringTable->insert("_upAxis"), 0, "Y_AXIS");
1184   else
1185      tree->setDataField(StringTable->insert("_upAxis"), 0, "Z_AXIS");
1186
1187   char shapesStr[16];
1188   dSprintf(shapesStr, 16, "%i", stats.numMeshes);
1189   char materialsStr[16];
1190   dSprintf(materialsStr, 16, "%i", stats.numMaterials);
1191   char animationsStr[16];
1192   dSprintf(animationsStr, 16, "%i", stats.numClips);
1193
1194   tree->setItemValue(nodesID, StringTable->insert(shapesStr));
1195   tree->setItemValue(matsID, StringTable->insert(materialsStr));
1196   tree->setItemValue(animsID, StringTable->insert(animationsStr));
1197
1198   return true;
1199}
1200
1201static bool enumDTSForImport(const char* shapePath, GuiTreeViewCtrl* tree)
1202{
1203   // Check if a cached DTS is available => no need to import the collada file
1204   // if we can load the DTS instead
1205   Torque::Path path(shapePath);
1206   Resource<TSShape> dtsShape = ResourceManager::get().load(shapePath);
1207
1208   if (!dtsShape)
1209      return false;
1210
1211   // Initialize tree
1212   tree->removeItem(0);
1213   S32 nodesID = tree->insertItem(0, "Shape", "", "", 0, 0);
1214   S32 matsID = tree->insertItem(0, "Materials", "", "", 0, 0);
1215   S32 animsID = tree->insertItem(0, "Animations", "", "", 0, 0);
1216
1217   SceneStats stats;
1218
1219   // Query DOM for shape summary details
1220   for (S32 i = 0; i < dtsShape->objects.size(); i++)
1221   {
1222      tree->insertItem(nodesID, dtsShape->names[dtsShape->objects[i].nameIndex], "", "", 0, 0);
1223      stats.numMeshes++;
1224   }
1225
1226   // Get material count
1227   for (S32 i = 0; i < dtsShape->materialList->size(); i++)
1228   {
1229      S32 matId = tree->insertItem(matsID, dtsShape->materialList->getMaterialName(i).c_str(), "", "", 0, 0);
1230      stats.numMaterials++;
1231
1232      GFXTextureObject* difTex = dtsShape->materialList->getDiffuseTexture(i);
1233      if (difTex)
1234      {
1235         tree->insertItem(matId, difTex->getPath().c_str(), "", "", 0, 0);
1236      }
1237   }
1238
1239   // Get animation count
1240   for (S32 i = 0; i < dtsShape->sequences.size(); i++)
1241   {
1242      tree->insertItem(animsID, dtsShape->names[dtsShape->sequences[i].nameIndex], "animation", "", 0, 0);
1243      stats.numClips++;
1244   }
1245
1246   /*if (stats.numClips == 0)
1247   {
1248      // No clips => check if there are any animations (these will be added to a default clip)
1249      for (S32 i = 0; i < root->getLibrary_animations_array().getCount(); i++)
1250      {
1251         const domLibrary_animations* libraryAnims = root->getLibrary_animations_array()[i];
1252         if (libraryAnims->getAnimation_array().getCount())
1253         {
1254            stats.numClips = 1;
1255            tree->insertItem(animsID, "ambient", "animation", "", 0, 0);
1256            break;
1257         }
1258      }
1259   }*/
1260
1261   F32 unit = 1.0f;
1262
1263   // Store shape information in the tree control
1264   tree->setDataField(StringTable->insert("_nodeCount"), 0, avar("%d", stats.numNodes));
1265   tree->setDataField(StringTable->insert("_meshCount"), 0, avar("%d", stats.numMeshes));
1266   tree->setDataField(StringTable->insert("_polygonCount"), 0, avar("%d", stats.numPolygons));
1267   tree->setDataField(StringTable->insert("_materialCount"), 0, avar("%d", stats.numMaterials));
1268   tree->setDataField(StringTable->insert("_lightCount"), 0, avar("%d", stats.numLights));
1269   tree->setDataField(StringTable->insert("_animCount"), 0, avar("%d", stats.numClips));
1270   tree->setDataField(StringTable->insert("_unit"), 0, avar("%g", unit));
1271
1272   tree->setDataField(StringTable->insert("_upAxis"), 0, "Z_AXIS");
1273
1274   char shapesStr[16];
1275   dSprintf(shapesStr, 16, "%i", stats.numMeshes);
1276   char materialsStr[16];
1277   dSprintf(materialsStr, 16, "%i", stats.numMaterials);
1278   char animationsStr[16];
1279   dSprintf(animationsStr, 16, "%i", stats.numClips);
1280
1281   tree->setItemValue(nodesID, StringTable->insert(shapesStr));
1282   tree->setItemValue(matsID, StringTable->insert(materialsStr));
1283   tree->setItemValue(animsID, StringTable->insert(animationsStr));
1284
1285   return true;
1286}
1287
1288void AssetImportConfig::loadSISFile(Torque::Path filePath)
1289{
1290   String settingsFilePath = "Tools";
1291   Settings* editorSettings;
1292   //See if we can get our editor settings
1293   if (Sim::findObject("EditorSettings", editorSettings))
1294   {
1295      settingsFilePath = editorSettings->value("defaultSettingsPath", "Tools");
1296   }
1297
1298   String fileExtension = filePath.getExtension();
1299   String settingsFile = settingsFilePath + "/" + fileExtension + ".sis";
1300
1301   FileObject* fileObj = new FileObject();
1302   if (Platform::isFile(settingsFile))
1303   {
1304      if (!fileObj->readMemory(settingsFile.c_str()))
1305      {
1306         Con::errorf("AssetImporter::loadSISFile() - Error opening file to load settings: %s", settingsFile.c_str());
1307         fileObj->deleteObject();
1308         return;
1309      }
1310   }
1311   else
1312   {
1313      return;
1314   }
1315
1316   String headerLine = (const char*)fileObj->readLine();
1317   if (headerLine.substr(0, 4).compare("SISV", 0U, String::NoCase) != 0)
1318      return; //not a sis file?
1319
1320   while (!fileObj->isEOF())
1321   {
1322      const char* line = (const char*)fileObj->readLine();
1323      String key = StringUnit::getUnit(line, 0, "\t");
1324      String value = StringUnit::getUnit(line, 1, "\t");
1325
1326      if (key.compare("DoUpAxisOverride", 0U, String::NoCase) == 0)
1327         DoUpAxisOverride = dAtob(value.c_str());
1328      else if (key.compare("UpAxisOverride", 0U, String::NoCase) == 0)
1329         UpAxisOverride = value.c_str();
1330      else if (key.compare("DoScaleOverride", 0U, String::NoCase) == 0)
1331         DoScaleOverride = dAtob(value.c_str());
1332      else if (key.compare("ScaleOverride", 0U, String::NoCase) == 0)
1333         ScaleOverride = dAtof(value.c_str());
1334      else if (key.compare("IgnoreNodeScale", 0U, String::NoCase) == 0)
1335         IgnoreNodeScale = dAtob(value.c_str());
1336      else if (key.compare("AdjustCenter", 0U, String::NoCase) == 0)
1337         AdjustCenter = dAtob(value.c_str());
1338      else if (key.compare("AdjustFloor", 0U, String::NoCase) == 0)
1339         AdjustFloor = dAtob(value.c_str());
1340      else if (key.compare("CollapseSubmeshes", 0U, String::NoCase) == 0)
1341         CollapseSubmeshes = dAtob(value.c_str());
1342      else if (key.compare("LODType", 0U, String::NoCase) == 0)
1343         LODType = value.c_str();
1344      else if (key.compare("AlwaysImportedNodes", 0U, String::NoCase) == 0)
1345         AlwaysImportedNodes = value.c_str();
1346      else if (key.compare("AlwaysIgnoreNodes", 0U, String::NoCase) == 0)
1347         AlwaysIgnoreNodes = value.c_str();
1348      else if (key.compare("AlwaysImportMeshes", 0U, String::NoCase) == 0)
1349         AlwaysImportMeshes = value.c_str();
1350      else if (key.compare("AlwaysIgnoreMeshes", 0U, String::NoCase) == 0)
1351         AlwaysIgnoreMeshes = value.c_str();
1352      else if (key.compare("convertLeftHanded", 0U, String::NoCase) == 0)
1353         convertLeftHanded = dAtob(value.c_str());
1354      else if (key.compare("calcTangentSpace", 0U, String::NoCase) == 0)
1355         calcTangentSpace = dAtob(value.c_str());
1356      else if (key.compare("removeRedundantMats", 0U, String::NoCase) == 0)
1357         removeRedundantMats = dAtob(value.c_str());
1358      else if (key.compare("genUVCoords", 0U, String::NoCase) == 0)
1359         genUVCoords = dAtob(value.c_str());
1360      else if (key.compare("TransformUVs", 0U, String::NoCase) == 0)
1361         TransformUVs = dAtob(value.c_str());
1362      else if (key.compare("flipUVCoords", 0U, String::NoCase) == 0)
1363         flipUVCoords = dAtob(value.c_str());
1364      else if (key.compare("findInstances", 0U, String::NoCase) == 0)
1365         findInstances = dAtob(value.c_str());
1366      else if (key.compare("limitBoneWeights", 0U, String::NoCase) == 0)
1367         limitBoneWeights = dAtob(value.c_str());
1368      else if (key.compare("JoinIdenticalVerts", 0U, String::NoCase) == 0)
1369         JoinIdenticalVerts = dAtob(value.c_str());
1370      else if (key.compare("reverseWindingOrder", 0U, String::NoCase) == 0)
1371         reverseWindingOrder = dAtob(value.c_str());
1372      else if (key.compare("invertNormals", 0U, String::NoCase) == 0)
1373         invertNormals = dAtob(value.c_str());
1374   }
1375
1376   fileObj->close();
1377   fileObj->deleteObject();
1378}
1379
1380void AssetImporter::processImportAssets(AssetImportObject* assetItem)
1381{
1382   if (assetItem == nullptr)
1383   {
1384      assetHeirarchyChanged = false;
1385
1386      for (U32 i = 0; i < importingAssets.size(); i++)
1387      {
1388         AssetImportObject* item = importingAssets[i];
1389         if (item->skip)
1390            continue;
1391
1392         if (!item->processed)
1393         {
1394            //Sanitize before modifying our asset name(suffix additions, etc)
1395            if (item->assetName != item->cleanAssetName)
1396               item->assetName = item->cleanAssetName;
1397
1398            //handle special pre-processing here for any types that need it
1399
1400            //process the asset items
1401            if (item->assetType == String("ImageAsset"))
1402            {
1403               processImageAsset(item);
1404            }
1405            else if (item->assetType == String("ShapeAsset"))
1406            {
1407               processShapeAsset(item);
1408            }
1409            /*else if (item->assetType == String("SoundAsset"))
1410               SoundAsset::prepareAssetForImport(this, item);*/
1411            else if (item->assetType == String("MaterialAsset"))
1412            {
1413               processMaterialAsset(item);
1414            }
1415            /*else if (item->assetType == String("ShapeAnimationAsset"))
1416               ShapeAnimationAsset::prepareAssetForImport(this, item);*/
1417            else
1418            {
1419               String processCommand = "process";
1420               processCommand += item->assetType;
1421               if(isMethod(processCommand.c_str()))
1422                  Con::executef(this, processCommand.c_str(), item);
1423            }
1424
1425            item->processed = true;
1426         }
1427
1428         //try recusing on the children(if any)
1429         processImportAssets(item);
1430      }
1431   }
1432   else
1433   {
1434      //this is the child recursing section
1435      for (U32 i = 0; i < assetItem->childAssetItems.size(); i++)
1436      {
1437         AssetImportObject* childItem = assetItem->childAssetItems[i];
1438
1439         if (childItem->skip)
1440            continue;
1441
1442         if (!childItem->processed)
1443         {
1444            //Sanitize before modifying our asset name(suffix additions, etc)
1445            if (childItem->assetName != childItem->cleanAssetName)
1446               childItem->assetName = childItem->cleanAssetName;
1447
1448            //handle special pre-processing here for any types that need it
1449
1450            //process the asset items
1451            if (childItem->assetType == String("ImageAsset"))
1452            {
1453               processImageAsset(childItem);
1454            }
1455            else if (childItem->assetType == String("ShapeAsset"))
1456            {
1457               processShapeAsset(childItem);
1458            }
1459            /*else if (item->assetType == String("SoundAsset"))
1460               SoundAsset::prepareAssetForImport(this, item);*/
1461            else if (childItem->assetType == String("MaterialAsset"))
1462            {
1463               processMaterialAsset(childItem);
1464            }
1465            /*else if (item->assetType == String("ShapeAnimationAsset"))
1466               ShapeAnimationAsset::prepareAssetForImport(this, item);*/
1467            else
1468            {
1469               String processCommand = "process";
1470               processCommand += childItem->assetType;
1471               if (isMethod(processCommand.c_str()))
1472                  Con::executef(this, processCommand.c_str(), childItem);
1473            }
1474
1475            childItem->processed = true;
1476         }
1477
1478         //try recusing on the children(if any)
1479         processImportAssets(childItem);
1480      }
1481   }
1482
1483   //If our hierarchy changed, it's because we did so during processing
1484   //so we'll loop back through again until everything has been processed
1485   if (assetHeirarchyChanged)
1486      processImportAssets();
1487}
1488
1489void AssetImporter::processImageAsset(AssetImportObject* assetItem)
1490{
1491   dSprintf(importLogBuffer, sizeof(importLogBuffer), "Preparing Image for Import: %s", assetItem->assetName.c_str());
1492   activityLog.push_back(importLogBuffer);
1493
1494   if ((activeImportConfig->GenerateMaterialOnImport && assetItem->parentAssetItem == nullptr)/* || assetItem->parentAssetItem != nullptr*/)
1495   {
1496      //find our suffix match, if any
1497      String noSuffixName = assetItem->assetName;
1498      String suffixType;
1499      String suffix = parseImageSuffixes(assetItem->assetName, &suffixType);
1500
1501      if (suffix.isNotEmpty())
1502      {
1503         assetItem->imageSuffixType = suffixType;
1504         S32 suffixPos =assetItem->assetName.find(suffix, 0, String::NoCase</a>|<a href="/coding/class/classstring/#classstring_1ad23530ba3c445d964722346a3c80771da84aa4530ee3fa8bfa8e0c2305744bff8">String::Left);
1505         noSuffixName = assetItem->assetName.substr(0, suffixPos);
1506      }
1507
1508      //We try to automatically populate materials under the naming convention: materialName: Rock, image maps: Rock_Albedo, Rock_Normal, etc
1509
1510      AssetImportObject* materialAsset = findImportingAssetByName(noSuffixName);
1511      if (materialAsset != nullptr && materialAsset->assetType != String("MaterialAsset"))
1512      {
1513         //We may have a situation where an asset matches the no-suffix name, but it's not a material asset. Ignore this
1514         //asset item for now
1515
1516         materialAsset = nullptr;
1517      }
1518
1519      //If we didn't find a matching material asset in our current items, we'll make one now
1520      if (materialAsset == nullptr)
1521      {
1522         if (!assetItem->filePath.isEmpty())
1523         {
1524            materialAsset = addImportingAsset("MaterialAsset", assetItem->filePath, nullptr, noSuffixName);
1525         }
1526      }
1527
1528      //Not that, one way or another, we have the generated material asset, lets move on to associating our image with it
1529      if (materialAsset != nullptr && materialAsset != assetItem->parentAssetItem)
1530      {
1531         if (assetItem->parentAssetItem != nullptr)
1532         {
1533            //If the image had an existing parent, it gets removed from that parent's child item list
1534            assetItem->parentAssetItem->childAssetItems.remove(assetItem);
1535         }
1536         else
1537         {
1538            //If it didn't have one, we're going to pull it from the importingAssets list
1539            importingAssets.remove(assetItem);
1540         }
1541
1542         //Now we can add it to the correct material asset
1543         materialAsset->childAssetItems.push_back(assetItem);
1544         assetItem->parentAssetItem = materialAsset;
1545
1546         assetHeirarchyChanged = true;
1547      }
1548
1549      //Now to do some cleverness. If we're generating a material, we can parse like assets being imported(similar filenames) but different suffixes
1550      //If we find these, we'll just populate into the original's material
1551
1552      //if we need to append the diffuse suffix and indeed didn't find a suffix on the name, do that here
1553      if (suffixType.isEmpty())
1554      {
1555         if (activeImportConfig->UseDiffuseSuffixOnOriginImage)
1556         {
1557            String diffuseToken = StringUnit::getUnit(activeImportConfig->DiffuseTypeSuffixes, 0, ",;\t");
1558            assetItem->assetName = assetItem->assetName + diffuseToken;
1559            assetItem->cleanAssetName = assetItem->assetName;
1560         }
1561         else
1562         {
1563            //We need to ensure that our image asset doesn't match the same name as the material asset, so if we're not trying to force the diffuse suffix
1564            //we'll give it a generic one
1565            if ((materialAsset && materialAsset->assetName.compare(assetItem->assetName) == 0) || activeImportConfig->AlwaysAddImageSuffix)
1566            {
1567               assetItem->assetName = assetItem->assetName + activeImportConfig->AddedImageSuffix;
1568               assetItem->cleanAssetName = assetItem->assetName;
1569            }
1570         }
1571
1572         //Assume for abledo if it has no suffix matches
1573         assetItem->imageSuffixType = "Albedo";
1574      }
1575      else
1576      {
1577
1578      }
1579   }
1580
1581   assetItem->processed = true;
1582}
1583
1584void AssetImporter::processMaterialAsset(AssetImportObject* assetItem)
1585{
1586   dSprintf(importLogBuffer, sizeof(importLogBuffer), "Preparing Material for Import: %s", assetItem->assetName.c_str());
1587   activityLog.push_back(importLogBuffer);
1588
1589   String filePath = assetItem->filePath.getFullPath();
1590   String fileName = assetItem->filePath.getFileName();
1591   String fileExt = assetItem->filePath.getExtension();
1592   const char* assetName = assetItem->assetName.c_str();
1593
1594   assetItem->generatedAsset = true;
1595
1596   if (activeImportConfig->IgnoreMaterials.isNotEmpty())
1597   {
1598      U32 ignoredMatNameCount = StringUnit::getUnitCount(activeImportConfig->IgnoreMaterials, ",;\t");
1599      for (U32 i = 0; i < ignoredMatNameCount; i++)
1600      {
1601         String ignoredName = StringUnit::getUnit(activeImportConfig->IgnoreMaterials, i, ",;\t");
1602         if (FindMatch::isMatch(ignoredName.c_str(), assetName, false))
1603         {
1604            assetItem->skip = true;
1605
1606            dSprintf(importLogBuffer, sizeof(importLogBuffer), "Material %s has been ignored due to it's name being listed in the IgnoreMaterials list in the Import Config.", assetItem->assetName.c_str());
1607            activityLog.push_back(importLogBuffer);
1608            return;
1609         }
1610      }
1611   }
1612
1613   if (activeImportConfig->AlwaysAddMaterialSuffix)
1614   {
1615      assetItem->assetName += activeImportConfig->AddedMaterialSuffix;
1616   }
1617
1618   if (activeImportConfig->PopulateMaterialMaps)
1619   {
1620      //If we're trying to populate the rest of our material maps, we need to go looking
1621      dSprintf(importLogBuffer, sizeof(importLogBuffer), "Attempting to Auto-Populate Material Maps");
1622      activityLog.push_back(importLogBuffer);
1623
1624      AssetImportObject* matchedImageTypes[ImageAsset::ImageTypeCount] = { nullptr };
1625
1626      String materialImageNoSuffix;
1627
1628      for (U32 i = 0; i < assetItem->childAssetItems.size(); i++)
1629      {
1630         AssetImportObject* childAssetItem = assetItem->childAssetItems[i];
1631
1632         if (childAssetItem->skip || childAssetItem->assetType != String("ImageAsset"))
1633            continue;
1634
1635         for (S32 t = 0; t < ImageAsset::ImageTypeCount; t++)
1636         {
1637            //If the imageType name and child asset image type match, check it off our list
1638            if (!dStricmp(ImageAsset::getImageTypeNameFromType((ImageAsset::ImageTypes)t), childAssetItem->imageSuffixType.c_str()))
1639            {
1640               matchedImageTypes[t] = childAssetItem;
1641
1642               if (t == ImageAsset::ImageTypes::Albedo)
1643               {
1644                  String sufType;
1645                  String suffix = parseImageSuffixes(childAssetItem->assetName, &sufType);
1646
1647                  String imageAssetName = childAssetItem->assetName;
1648
1649                  if (suffix.isEmpty())
1650                     materialImageNoSuffix = imageAssetName;
1651                  else
1652                     materialImageNoSuffix = imageAssetName.erase(imageAssetName.length() - suffix.length(), suffix.length());//cache this for later as we may need it for file association lookups
1653               }
1654            }
1655         }
1656      }
1657
1658      //Now that we've checked off any existingly matched image types, process through the unmatched to look for files that associate
1659      for (S32 t = 0; t < ImageAsset::ImageTypeCount; t++)
1660      {
1661         //This type wasn't found, so try and find a match based on suffix
1662         String suffixList;
1663
1664         switch (t)
1665         {
1666         case ImageAsset::Albedo:
1667            suffixList = activeImportConfig->DiffuseTypeSuffixes;
1668            break;
1669         case ImageAsset::Normal:
1670            suffixList = activeImportConfig->NormalTypeSuffixes;
1671            break;
1672         case ImageAsset::ORMConfig:
1673            suffixList = activeImportConfig->PBRTypeSuffixes;
1674            break;
1675         case ImageAsset::Metalness:
1676            suffixList = activeImportConfig->MetalnessTypeSuffixes;
1677            break;
1678         case ImageAsset::AO:
1679            suffixList = activeImportConfig->AOTypeSuffixes;
1680            break;
1681         case ImageAsset::Roughness:
1682            suffixList = activeImportConfig->RoughnessTypeSuffixes;
1683            break;
1684            //TODO: Glow map lookup too
1685         }
1686
1687         if (!matchedImageTypes[t])
1688         {
1689            U32 suffixCount = StringUnit::getUnitCount(suffixList.c_str(), ",;\t");
1690            for (U32 i = 0; i < suffixCount; i++)
1691            {
1692               //First, try checking based on the material's assetName for our patternbase
1693               String testPath = assetItem->filePath.getRootAndPath();
1694               testPath += "/" + assetItem->cleanAssetName + StringUnit::getUnit(suffixList.c_str(), i, ",;\t");
1695
1696               String imagePath = AssetImporter::findImagePath(testPath);
1697
1698               if (imagePath.isNotEmpty())
1699               {
1700                  //got a match!
1701                  AssetImportObject* newImageAssetObj = addImportingAsset("ImageAsset", imagePath, assetItem, "");
1702
1703                  newImageAssetObj->imageSuffixType = ImageAsset::getImageTypeNameFromType((ImageAsset::ImageTypes)t);
1704
1705                  matchedImageTypes[t] = newImageAssetObj;
1706                  break;
1707               }
1708               else
1709               {
1710                  if(materialImageNoSuffix.isNotEmpty())
1711                  {
1712                     testPath = assetItem->filePath.getRootAndPath();
1713                     testPath += "/" + materialImageNoSuffix + StringUnit::getUnit(suffixList.c_str(), i, ",;\t");
1714
1715                     imagePath = AssetImporter::findImagePath(testPath);
1716
1717                     if (imagePath.isNotEmpty())
1718                     {
1719                        //got a match!
1720                        AssetImportObject* newImageAssetObj = addImportingAsset("ImageAsset", imagePath, assetItem, "");
1721
1722                        newImageAssetObj->imageSuffixType = ImageAsset::getImageTypeNameFromType((ImageAsset::ImageTypes)t);
1723
1724                        matchedImageTypes[t] = newImageAssetObj;
1725                        break;
1726                     }
1727                  }
1728               }
1729            }
1730
1731            //If we're the abledo slot and after all that we didn't find anything, it probably is a suffixless image
1732            if (t == ImageAsset::Albedo && matchedImageTypes[t] == nullptr)
1733            {
1734               String testPath = assetItem->filePath.getRootAndPath() + "/" + assetItem->cleanAssetName;
1735               String imagePath = AssetImporter::findImagePath(testPath);
1736
1737               if (imagePath.isNotEmpty())
1738               {
1739                  //got a match!
1740                  AssetImportObject* newImageAssetObj = addImportingAsset("ImageAsset", imagePath, assetItem, "");
1741
1742                  //In the event that the names match, we want to avoid duplications, so we'll go ahead and append a suffix onto our new image asset
1743                  if (newImageAssetObj->assetName == assetItem->assetName)
1744                  {
1745                     newImageAssetObj->assetName += StringUnit::getUnit(suffixList.c_str(), 0, ",;\t");
1746                     newImageAssetObj->cleanAssetName = newImageAssetObj->assetName;
1747                  }
1748
1749                  newImageAssetObj->imageSuffixType = ImageAsset::getImageTypeNameFromType(ImageAsset::ImageTypes::Albedo);
1750
1751                  matchedImageTypes[t] = newImageAssetObj;
1752               }
1753            }
1754         }
1755         else
1756         {
1757            //just a bit of cleanup and logical testing for matches
1758            //in the event we KNOW what the type is, but we don't have a suffix, such as a found image on a material lookup
1759            //that doesn't have a suffix, we assume it to be the albedo, so we'll just append the suffix to avoid collisions if
1760            //the name already matches our material name, similar to above logic
1761            if (matchedImageTypes[t]->assetName == assetItem->assetName)
1762            {
1763               matchedImageTypes[t]->assetName += StringUnit::getUnit(suffixList.c_str(), 0, ",;\t");
1764               matchedImageTypes[t]->cleanAssetName = matchedImageTypes[t]->assetName;
1765            }
1766         }
1767      }
1768
1769      /*for (U32 i = 0; i < assetItem->childAssetItems.size(); i++)
1770      {
1771         AssetImportObject* childAssetItem = assetItem->childAssetItems[i];
1772
1773         if (childAssetItem->skip || childAssetItem->processed || childAssetItem->assetType != String("ImageAsset"))
1774            continue;
1775
1776         if (childAssetItem->imageSuffixType == String("Albedo"))
1777         {
1778            assetItem->diffuseImageAsset = % childAssetItem;
1779         }
1780      }*/
1781   }
1782   
1783   assetItem->processed = true;
1784}
1785
1786void AssetImporter::processShapeAsset(AssetImportObject* assetItem)
1787{
1788   dSprintf(importLogBuffer, sizeof(importLogBuffer), "Preparing Shape for Import: %s", assetItem->assetName.c_str());
1789   activityLog.push_back(importLogBuffer);
1790
1791   String filePath = assetItem->filePath.getFullPath();
1792   String fileName = assetItem->filePath.getFileName();
1793   String fileExt = assetItem->filePath.getExtension();
1794
1795   if (assetItem->shapeInfo == nullptr)
1796   {
1797      GuiTreeViewCtrl* shapeInfo = new GuiTreeViewCtrl();
1798      shapeInfo->registerObject();
1799
1800      if (fileExt.compare("dae") == 0)
1801      {
1802         enumColladaForImport(filePath, shapeInfo, false);
1803      }
1804      else if (fileExt.compare("dts") == 0)
1805      {
1806         enumDTSForImport(filePath, shapeInfo);
1807      }
1808      else
1809      {
1810         // Check if a cached DTS is available => no need to import the source file
1811         // if we can load the DTS instead
1812
1813         AssimpShapeLoader loader;
1814         loader.fillGuiTreeView(filePath.c_str(), shapeInfo);
1815      }
1816
1817      assetItem->shapeInfo = shapeInfo;
1818   }
1819
1820   if (activeImportConfig->AlwaysAddShapeSuffix)
1821   {
1822      assetItem->assetName += activeImportConfig->AddedShapeSuffix;
1823   }
1824
1825   S32 meshCount = dAtoi(assetItem->shapeInfo->getDataField(StringTable->insert("_meshCount"), nullptr));
1826   S32 shapeItem = assetItem->shapeInfo->findItemByName("Meshes");
1827
1828   S32 animCount = dAtoi(assetItem->shapeInfo->getDataField(StringTable->insert("_animCount"), nullptr));
1829   S32 animItem = assetItem->shapeInfo->findItemByName("Animations");
1830
1831   S32 materialCount = dAtoi(assetItem->shapeInfo->getDataField(StringTable->insert("_materialCount"), nullptr));
1832   S32 matItem = assetItem->shapeInfo->findItemByName("Materials");
1833
1834   dSprintf(importLogBuffer, sizeof(importLogBuffer), "   Shape Info: Mesh Count: %i | Material Count: %i | Anim Count: %i", meshCount, animCount, materialCount);
1835   activityLog.push_back(importLogBuffer);
1836
1837   AssetImportConfig* cachedConfig = new AssetImportConfig();;
1838   cachedConfig->registerObject();
1839   activeImportConfig->CopyTo(cachedConfig);
1840
1841   if (!activeImportConfig->UseManualShapeConfigRules)
1842   {
1843      //Try and load a sis file if it exists for this format
1844      activeImportConfig->loadSISFile(assetItem->filePath);
1845   }
1846
1847   if (activeImportConfig->ImportMesh && meshCount > 0)
1848   {
1849
1850   }
1851
1852   if (activeImportConfig->ImportAnimations && animCount > 0)
1853   {
1854      //If we have animations but no meshes, then this is a pure animation file so we can swap the asset type here
1855      if (meshCount == 0)
1856      {
1857         assetItem->assetType = "ShapeAnimationAsset";
1858      }
1859   }
1860
1861   if (activeImportConfig->ImportMaterials && materialCount > 0)
1862   {
1863      S32 materialId = assetItem->shapeInfo->getChildItem(matItem);
1864      processShapeMaterialInfo(assetItem, materialId);
1865
1866      materialId = assetItem->shapeInfo->getNextSiblingItem(materialId);
1867      while (materialId != 0)
1868      {
1869         processShapeMaterialInfo(assetItem, materialId);
1870         materialId = assetItem->shapeInfo->getNextSiblingItem(materialId);
1871      }
1872   }
1873
1874   //restore the cached version just in case we loaded a sis file
1875   cachedConfig->CopyTo(activeImportConfig);
1876   cachedConfig->deleteObject();
1877
1878   assetItem->processed = true;
1879}
1880
1881void AssetImporter::processShapeMaterialInfo(AssetImportObject* assetItem, S32 materialItemId)
1882{
1883   String matName = assetItem->shapeInfo->getItemText(materialItemId);
1884   String matAssetName = matName;
1885
1886   if (matName == assetItem->assetName)
1887   {
1888      //So apparently we managed to name the material the same as the shape. So we'll tweak the name
1889      matAssetName += activeImportConfig->AlwaysAddMaterialSuffix;
1890   }
1891
1892   //Do a check so we don't import materials that are on our ignore list
1893   if (activeImportConfig->IgnoreMaterials.isNotEmpty())
1894   {
1895      U32 ignoredMatNamesCount = StringUnit::getUnitCount(activeImportConfig->IgnoreMaterials, ",;\t");
1896      for (U32 i = 0; i < ignoredMatNamesCount; i++)
1897      {
1898         const char* ignoreMatName = StringUnit::getUnit(activeImportConfig->IgnoreMaterials, i, ",;\t");
1899         if (FindMatch::isMatch(ignoreMatName, matName.c_str(), false))
1900         {
1901            //If we have a match to one of our ignore names, just bail out here and skip the material wholesale
1902            return;
1903         }
1904      }
1905   }
1906
1907   String materialItemValue = assetItem->shapeInfo->getItemValue(materialItemId);
1908
1909   AssetImportObject* matAssetItem = nullptr;
1910
1911   //If it happens to just be a color value instead of an image, we'll go ahead and skip doing any lookups
1912   //TODO: properly map the 'texture' color to the material that gets created
1913   if (materialItemValue.startsWith("Color:"))
1914   {
1915      matAssetItem = addImportingAsset("MaterialAsset", "", assetItem, matName);
1916   }
1917   else
1918   {
1919      Torque::Path filePath = materialItemValue;
1920      String fullFilePath = filePath.getFullFileName().c_str();
1921      String shapePathBase = assetItem->filePath.getRootAndPath();
1922
1923      if (fullFilePath.isNotEmpty())
1924      {
1925         if (!Platform::isFile(fullFilePath.c_str()))
1926         {
1927            //could be a stale path reference, such as if it was downloaded elsewhere. Trim to just the filename and see
1928            //if we can find it there
1929            
1930            //trim (not found) if needbe
1931            fullFilePath = fullFilePath.replace(" (Not Found)", "");
1932            fullFilePath = fullFilePath.replace(" (not found)", "");
1933
1934            String testFileName = shapePathBase + "/" + fullFilePath;
1935            if (Platform::isFile(testFileName.c_str()))
1936            {
1937               filePath = testFileName;
1938            }
1939            else
1940            {
1941               //Hmm, didn't find it. It could be that the in-model filename could be different by virtue of
1942               //image extension. Some files have source content files like psd's, but the mesh was exported to use
1943               //a dds or png, etc
1944               Torque::Path testFilePath = testFileName;
1945               String imgFileName = AssetImporter::findImagePath(testFilePath.getPath() + "/" + testFilePath.getFileName());
1946               if (imgFileName.isNotEmpty())
1947                  filePath = imgFileName;
1948            }
1949         }
1950 
1951         matAssetItem = addImportingAsset("MaterialAsset", shapePathBase + "/", assetItem, matName);
1952         AssetImportObject* imageAssetItem = addImportingAsset("ImageAsset", filePath, matAssetItem, "");
1953
1954         String suffixType;
1955         String suffix = parseImageSuffixes(imageAssetItem->assetName, &suffixType);
1956         if (suffix.isNotEmpty())
1957         {
1958            imageAssetItem->imageSuffixType = suffixType;
1959         }
1960         else
1961         {
1962            //we'll assume it's albedo
1963            imageAssetItem->imageSuffixType = "Albedo";
1964         }
1965      }
1966      else
1967      {
1968         matAssetItem = addImportingAsset("MaterialAsset", shapePathBase + "/" + matName, assetItem, matName);
1969      }
1970   }
1971
1972   //In the event we modified the asset name(such as appending _Mat to avoid naming conflicts) update the name here
1973   //This preseves the 'clean asset name' which we can later use for lookups and the like as needed
1974   if (matAssetItem && matAssetName != matName)
1975      matAssetItem->assetName = matAssetName;
1976}
1977
1978void AssetImporter::processSoundAsset(AssetImportObject* assetItem)
1979{
1980   dSprintf(importLogBuffer, sizeof(importLogBuffer), "Preparing Image for Import: %s", assetItem->assetName.c_str());
1981   activityLog.push_back(importLogBuffer);
1982
1983   if ((activeImportConfig->GenerateMaterialOnImport && assetItem->parentAssetItem == nullptr)/* || assetItem->parentAssetItem != nullptr*/)
1984   {
1985      //find our suffix match, if any
1986      String noSuffixName = assetItem->assetName;
1987      String suffixType;
1988      String suffix = parseImageSuffixes(assetItem->assetName, &suffixType);
1989      if (suffix.isNotEmpty())
1990      {
1991         assetItem->imageSuffixType = suffixType;
1992         S32 suffixPos = assetItem->assetName.find(suffix, 0, String::NoCase | String::Left);
1993         noSuffixName = assetItem->assetName.substr(0, suffixPos);
1994      }
1995
1996      //We try to automatically populate materials under the naming convention: materialName: Rock, image maps: Rock_Albedo, Rock_Normal, etc
1997
1998      AssetImportObject* materialAsset = findImportingAssetByName(noSuffixName);
1999      if (materialAsset != nullptr && materialAsset->assetType != String("MaterialAsset"))
2000      {
2001         //We may have a situation where an asset matches the no-suffix name, but it's not a material asset. Ignore this
2002         //asset item for now
2003
2004         materialAsset = nullptr;
2005      }
2006
2007      //If we didn't find a matching material asset in our current items, we'll make one now
2008      if (materialAsset == nullptr)
2009      {
2010         if (!assetItem->filePath.isEmpty())
2011         {
2012            materialAsset = addImportingAsset("MaterialAsset", assetItem->filePath, nullptr, noSuffixName);
2013         }
2014      }
2015
2016      //Not that, one way or another, we have the generated material asset, lets move on to associating our image with it
2017      if (materialAsset != nullptr && materialAsset != assetItem->parentAssetItem)
2018      {
2019         if (assetItem->parentAssetItem != nullptr)
2020         {
2021            //If the image had an existing parent, it gets removed from that parent's child item list
2022            assetItem->parentAssetItem->childAssetItems.remove(assetItem);
2023         }
2024         else
2025         {
2026            //If it didn't have one, we're going to pull it from the importingAssets list
2027            importingAssets.remove(assetItem);
2028         }
2029
2030         //Now we can add it to the correct material asset
2031         materialAsset->childAssetItems.push_back(assetItem);
2032         assetItem->parentAssetItem = materialAsset;
2033
2034         assetHeirarchyChanged = true;
2035      }
2036
2037      //Now to do some cleverness. If we're generating a material, we can parse like assets being imported(similar filenames) but different suffixes
2038      //If we find these, we'll just populate into the original's material
2039
2040      //if we need to append the diffuse suffix and indeed didn't find a suffix on the name, do that here
2041      if (suffixType.isEmpty())
2042      {
2043         if (activeImportConfig->UseDiffuseSuffixOnOriginImage)
2044         {
2045            String diffuseToken = StringUnit::getUnit(activeImportConfig->DiffuseTypeSuffixes, 0, ",;\t");
2046            assetItem->assetName = assetItem->assetName + diffuseToken;
2047            assetItem->cleanAssetName = assetItem->assetName;
2048         }
2049         else
2050         {
2051            //We need to ensure that our image asset doesn't match the same name as the material asset, so if we're not trying to force the diffuse suffix
2052            //we'll give it a generic one
2053            if ((materialAsset && materialAsset->assetName.compare(assetItem->assetName) == 0) || activeImportConfig->AlwaysAddImageSuffix)
2054            {
2055               assetItem->assetName = assetItem->assetName + activeImportConfig->AddedImageSuffix;
2056               assetItem->cleanAssetName = assetItem->assetName;
2057            }
2058         }
2059
2060         //Assume for abledo if it has no suffix matches
2061         assetItem->imageSuffixType = "Albedo";
2062      }
2063   }
2064
2065   assetItem->processed = true;
2066}
2067//
2068// Validation
2069//
2070
2071bool AssetImporter::validateAssets()
2072{
2073   importIssues = false;
2074
2075   resetAssetValidationStatus();
2076
2077   for (U32 i = 0; i < importingAssets.size(); i++)
2078   {
2079      validateAsset(importingAssets[i]);
2080      resolveAssetItemIssues(importingAssets[i]);
2081   }
2082
2083   return importIssues;
2084}
2085
2086void AssetImporter::validateAsset(AssetImportObject* assetItem)
2087{
2088   if (assetItem->skip)
2089      return;
2090
2091   bool hasCollision = checkAssetForCollision(assetItem);
2092
2093   if (hasCollision)
2094   {
2095      importIssues = true;
2096      return;
2097   }
2098
2099   if (!isReimport)
2100   {
2101      AssetQuery aQuery;
2102      U32 numAssetsFound = AssetDatabase.findAllAssets(&aQuery);
2103
2104      bool hasCollision = false;
2105      for (U32 i = 0; i < numAssetsFound; i++)
2106      {
2107         StringTableEntry assetId = aQuery.mAssetList[i];
2108
2109         ModuleDefinition* moduleDef = AssetDatabase.getAssetModuleDefinition(assetId);
2110
2111         if ((moduleDef == NULL) || moduleDef->getModuleId() != StringTable->insert(targetModuleId.c_str()))
2112            continue;
2113
2114         StringTableEntry assetName = AssetDatabase.getAssetName(assetId);
2115
2116         if (assetName == StringTable->insert(assetItem->assetName.c_str()))
2117         {
2118            hasCollision = true;
2119            assetItem->status = "Error";
2120            assetItem->statusType = "DuplicateAsset";
2121            assetItem->statusInfo = "Duplicate asset names found within the target module!\nAsset \"" + assetItem->assetName + "\" of type \"" + assetItem->assetType + "\" has a matching name.\nPlease rename it and try again!";
2122
2123            //log it
2124            dSprintf(importLogBuffer, sizeof(importLogBuffer), "Error! Asset %s has an identically named asset in the target module.", assetItem->assetName.c_str());
2125            activityLog.push_back(importLogBuffer);
2126            break;
2127         }
2128      }
2129   }
2130
2131   if (!assetItem->filePath.isEmpty() && !assetItem->generatedAsset && !Platform::isFile(assetItem->filePath.getFullPath().c_str()))
2132   {
2133      assetItem->status = "Error";
2134      assetItem->statusType = "MissingFile";
2135      assetItem->statusInfo = "Unable to find file to be imported with provided path: " + assetItem->filePath + "\n Please select a valid file.";
2136
2137      //log it
2138      dSprintf(importLogBuffer, sizeof(importLogBuffer), "Error! Asset %s's file at %s was not found.", assetItem->assetName.c_str(), assetItem->filePath.getFullPath().c_str());
2139      activityLog.push_back(importLogBuffer);
2140   }
2141
2142   if (assetItem->status == String("Warning"))
2143   {
2144      if (activeImportConfig->WarningsAsErrors)
2145      {
2146         assetItem->status = "Error";
2147
2148         //log it
2149         dSprintf(importLogBuffer, sizeof(importLogBuffer), "Error! Import configuration has treated an import warning as an error.", assetItem->assetName.c_str());
2150         activityLog.push_back(importLogBuffer);
2151      }
2152   }
2153
2154   if (assetItem->status == String("Error"))
2155      importIssues = true;
2156
2157   for (U32 i = 0; i < assetItem->childAssetItems.size(); i++)
2158   {
2159      validateAsset(assetItem->childAssetItems[i]);
2160      resolveAssetItemIssues(assetItem->childAssetItems[i]);
2161   }
2162
2163   return;
2164}
2165
2166void AssetImporter::resetAssetValidationStatus(AssetImportObject* assetItem)
2167{
2168   if (assetItem == nullptr)
2169   {
2170      for (U32 i = 0; i < importingAssets.size(); i++)
2171      {
2172         if (importingAssets[i]->skip)
2173            continue;
2174
2175         importingAssets[i]->status = "";
2176         importingAssets[i]->statusType = "";
2177         importingAssets[i]->statusInfo = "";
2178
2179         //If it wasn't a match, try recusing on the children(if any)
2180         resetAssetValidationStatus(importingAssets[i]);
2181      }
2182   }
2183   else
2184   {
2185      //this is the child recursing section
2186      for (U32 i = 0; i < assetItem->childAssetItems.size(); i++)
2187      {
2188         if (assetItem->childAssetItems[i]->skip)
2189            continue;
2190
2191         assetItem->childAssetItems[i]->status = "";
2192         assetItem->childAssetItems[i]->statusType = "";
2193         assetItem->childAssetItems[i]->statusInfo = "";
2194
2195         //If it wasn't a match, try recusing on the children(if any)
2196         resetAssetValidationStatus(assetItem->childAssetItems[i]);
2197      }
2198   }
2199}
2200
2201bool AssetImporter::checkAssetForCollision(AssetImportObject* assetItemToCheck, AssetImportObject* assetItem)
2202{
2203   bool results = false;
2204
2205   if (assetItem == nullptr)
2206   {
2207      for (U32 i = 0; i < importingAssets.size(); i++)
2208      {
2209         AssetImportObject* importingAsset = importingAssets[i];
2210
2211         if (importingAsset->skip)
2212            continue;
2213
2214         if ((assetItemToCheck->assetName.compare(importingAsset->assetName) == 0) && (assetItemToCheck->getId() != importingAsset->getId()))
2215         {
2216            //we do have a collision, note the collsion and bail out
2217            assetItemToCheck->status = "Warning";
2218            assetItemToCheck->statusType = "DuplicateImportAsset";
2219            assetItemToCheck->statusInfo = "Duplicate asset names found with importing assets!\nAsset \"" + importingAsset->assetName + "\" of the type \"" + importingAsset->assetType + "\" and \"" +
2220                                             assetItemToCheck->assetName + "\" of the type \"" + assetItemToCheck->assetType + "\" have matching names.\nPlease rename one of them.";
2221
2222             dSprintf(importLogBuffer, sizeof(importLogBuffer), "Warning! Asset %s, type %s has a naming collision with another importing asset: %s, type %s",
2223                assetItemToCheck->assetName.c_str(), assetItemToCheck->assetType.c_str(),
2224                importingAsset->assetName.c_str(), importingAsset->assetType.c_str());
2225             activityLog.push_back(importLogBuffer);
2226
2227            return true;
2228         }
2229
2230         //If it wasn't a match, try recusing on the children(if any)
2231         results = checkAssetForCollision(assetItemToCheck, importingAsset);
2232         if (results)
2233            return results;
2234      }
2235   }
2236   else
2237   {
2238      //this is the child recursing section
2239      for (U32 i = 0; i < assetItem->childAssetItems.size(); i++)
2240      {
2241         AssetImportObject* childAsset = assetItem->childAssetItems[i];
2242
2243         if (childAsset->skip)
2244            continue;
2245
2246         if ((assetItemToCheck->assetName.compare(childAsset->assetName) == 0) && (assetItemToCheck->getId() != childAsset->getId()))
2247         {
2248            //we do have a collision, note the collsion and bail out
2249            assetItemToCheck->status = "Warning";
2250            assetItemToCheck->statusType = "DuplicateImportAsset";
2251            assetItemToCheck->statusInfo = "Duplicate asset names found with importing assets!\nAsset \"" + assetItem->assetName + "\" of the type \"" + assetItem->assetType + "\" and \"" +
2252               assetItemToCheck->assetName + "\" of the type \"" + assetItemToCheck->assetType + "\" have matching names.\nPlease rename one of them.";
2253
2254            dSprintf(importLogBuffer, sizeof(importLogBuffer), "Warning! Asset %s, type %s has a naming collision with another importing asset: %s, type %s",
2255               assetItemToCheck->assetName.c_str(), assetItemToCheck->assetType.c_str(),
2256               childAsset->assetName.c_str(), childAsset->assetType.c_str());
2257            activityLog.push_back(importLogBuffer);
2258
2259            return true;
2260         }
2261
2262         //If it wasn't a match, try recusing on the children(if any)
2263         results = checkAssetForCollision(assetItemToCheck, childAsset);
2264         if (results)
2265            return results;
2266      }
2267   }
2268
2269   return results;
2270}
2271
2272void AssetImporter::resolveAssetItemIssues(AssetImportObject* assetItem)
2273{
2274   if (assetItem->statusType == String("DuplicateImportAsset") || assetItem->statusType == String("DuplicateAsset"))
2275   {
2276      String humanReadableReason = assetItem->statusType == String("DuplicateImportAsset") ? "Importing asset was duplicate of another importing asset" : "Importing asset was duplicate of an existing asset";
2277
2278      //get the config value for duplicateAutoResolution
2279      if (activeImportConfig->DuplicatAutoResolution == String("AutoPrune"))
2280      {
2281         //delete the item
2282         deleteImportingAsset(assetItem);
2283
2284         //log it's deletion
2285         dSprintf(importLogBuffer, sizeof(importLogBuffer), "Asset %s was autoprined due to %s as part of the Import Configuration", assetItem->assetName.c_str(), humanReadableReason.c_str());
2286         activityLog.push_back(importLogBuffer);
2287
2288         importIssues = false;
2289      }
2290      else if (activeImportConfig->DuplicatAutoResolution == String("AutoRename"))
2291      {
2292         //Set trailing number
2293         String renamedAssetName = assetItem->assetName;
2294         renamedAssetName = Sim::getUniqueName(renamedAssetName.c_str());
2295
2296         //Log it's renaming
2297         dSprintf(importLogBuffer, sizeof(importLogBuffer), "Asset %s was renamed due to %s as part of the Import Configuration", assetItem->assetName.c_str(), humanReadableReason.c_str());
2298         activityLog.push_back(importLogBuffer);
2299
2300         dSprintf(importLogBuffer, sizeof(importLogBuffer), "Asset %s was renamed to %s", assetItem->assetName.c_str(), renamedAssetName.c_str());
2301         activityLog.push_back(importLogBuffer);
2302
2303         assetItem->assetName = renamedAssetName;
2304
2305         //Whatever status we had prior is no longer relevent, so reset the status
2306         resetAssetValidationStatus(assetItem);
2307         importIssues = false;
2308      }
2309      else if (activeImportConfig->DuplicatAutoResolution == String("UseExisting"))
2310      {
2311
2312      }
2313   }
2314   else if (assetItem->statusType == String("MissingFile"))
2315   {
2316      //Trigger callback to look?
2317   }
2318}
2319
2320void AssetImporter::resetImportConfig()
2321{
2322   //use a default import config
2323   if (activeImportConfig == nullptr)
2324   {
2325      activeImportConfig = new AssetImportConfig();
2326      activeImportConfig->registerObject();
2327   }
2328
2329   bool foundConfig = false;
2330   Settings* editorSettings;
2331   //See if we can get our editor settings
2332   if (Sim::findObject("EditorSettings", editorSettings))
2333   {
2334      String defaultImportConfig = editorSettings->value("Assets/AssetImporDefaultConfig");
2335
2336      //If we found it, grab the import configs
2337      Settings* importConfigs;
2338      if (Sim::findObject("AssetImportSettings", importConfigs))
2339      {
2340         //Now load the editor setting-deigned config!
2341         activeImportConfig->loadImportConfig(importConfigs, defaultImportConfig.c_str());
2342      }
2343   }
2344}
2345
2346//
2347// Importing
2348//
2349StringTableEntry AssetImporter::autoImportFile(Torque::Path filePath)
2350{
2351   //Just in case we're reusing the same importer object from another import session, nuke any existing files
2352   resetImportSession(true);
2353
2354   String assetType = getAssetTypeByFile(filePath);
2355
2356   if (assetType == String("Folder") || assetType == String("Zip"))
2357   {
2358      dSprintf(importLogBuffer, sizeof(importLogBuffer), "Unable to import file %s because it is a folder or zip.", filePath.getFullPath().c_str());
2359      activityLog.push_back(importLogBuffer);
2360      return StringTable->EmptyString();
2361   }
2362
2363   if (assetType.isEmpty())
2364   {
2365      dSprintf(importLogBuffer, sizeof(importLogBuffer), "Unable to import file %s because it is of an unrecognized/unsupported type.", filePath.getFullPath().c_str());
2366      activityLog.push_back(importLogBuffer);
2367      return StringTable->EmptyString();
2368   }
2369
2370   //Find out if the filepath has an associated module to it. If we're importing in-place, it needs to be within a module's directory
2371   ModuleDefinition* targetModuleDef = AssetImporter::getModuleFromPath(filePath);
2372
2373   if (targetModuleDef == nullptr)
2374   {
2375      //log it
2376      return StringTable->EmptyString();
2377   }
2378   else
2379   {
2380      targetModuleId = targetModuleDef->getModuleId();
2381   }
2382
2383   //set our path
2384   targetPath = filePath.getPath();
2385
2386   resetImportConfig();
2387
2388   AssetImportObject* assetItem = addImportingAsset(assetType, filePath, nullptr, "");
2389
2390   processImportAssets();
2391
2392   bool hasIssues = validateAssets();
2393
2394   if (hasIssues)
2395   {
2396      //log it
2397      dSprintf(importLogBuffer, sizeof(importLogBuffer), "Error! Import process has failed due to issues discovered during validation!");
2398      activityLog.push_back(importLogBuffer);
2399   }
2400   else
2401   {
2402      importAssets();
2403   }
2404
2405#if TORQUE_DEBUG
2406   Con::printf("/***************/");
2407   for (U32 i = 0; i < activityLog.size(); i++)
2408   {
2409      Con::printf(activityLog[i].c_str());
2410   }
2411   Con::printf("/***************/");
2412#endif
2413
2414   if (hasIssues)
2415   {
2416      return StringTable->EmptyString();
2417   }
2418   else
2419   {
2420      String assetId = targetModuleId + ":" + assetItem->assetName;
2421      return StringTable->insert(assetId.c_str());
2422   }
2423}
2424
2425void AssetImporter::importAssets(AssetImportObject* assetItem)
2426{
2427   ModuleDefinition* moduleDef = ModuleDatabase.findModule(targetModuleId.c_str(), 1);
2428
2429   if (moduleDef == nullptr)
2430   {
2431      dSprintf(importLogBuffer, sizeof(importLogBuffer), "AssetImporter::importAssets - Unable to find moduleId %s", targetModuleId.c_str());
2432      activityLog.push_back(importLogBuffer);
2433      return;
2434   }
2435
2436   if (assetItem == nullptr)
2437   {
2438      for (U32 i = 0; i < importingAssets.size(); i++)
2439      {
2440         if (importingAssets[i]->skip)
2441            continue;
2442
2443         Torque::Path assetPath;
2444         if (importingAssets[i]->assetType == String("ImageAsset"))
2445         {
2446            assetPath = importImageAsset(importingAssets[i]);
2447         }
2448         else if (importingAssets[i]->assetType == String("ShapeAsset"))
2449         {
2450            assetPath = importShapeAsset(importingAssets[i]);
2451         }
2452         else if (importingAssets[i]->assetType == String("SoundAsset"))
2453         {
2454            assetPath = importSoundAsset(importingAssets[i]);
2455         }
2456         else if (importingAssets[i]->assetType == String("MaterialAsset"))
2457         {
2458            assetPath = importMaterialAsset(importingAssets[i]);
2459         }
2460         else
2461         {
2462            finalImportedAssetPath = String::EmptyString;
2463
2464            String processCommand = "import";
2465            processCommand += importingAssets[i]->assetType;
2466            if (isMethod(processCommand.c_str()))
2467            {
2468               Con::executef(this, processCommand.c_str(), importingAssets[i]);
2469
2470               assetPath = finalImportedAssetPath;
2471            }
2472         }
2473         /*else if (importingAssets[i]->assetType == String("ShapeAnimationAsset"))
2474            assetPath = ShapeAnimationAsset::importAsset(importingAssets[i]);*/
2475
2476         if (assetPath.isEmpty() && importingAssets[i]->assetType != String("MaterialAsset"))
2477         {
2478            dSprintf(importLogBuffer, sizeof(importLogBuffer), "AssetImporter::importAssets - Import attempt of %s failed, so skipping asset.", importingAssets[i]->assetName.c_str());
2479            activityLog.push_back(importLogBuffer);
2480
2481            continue;
2482         }
2483         else
2484         {
2485            //If we got a valid filepath back from the import action, then we know we're good to go and we can go ahead and register the asset!
2486            if (!isReimport)
2487            {
2488               bool registerSuccess = AssetDatabase.addDeclaredAsset(moduleDef, assetPath.getFullPath().c_str());
2489
2490               if (!registerSuccess)
2491               {
2492                  dSprintf(importLogBuffer, sizeof(importLogBuffer), "AssetImporter::importAssets - Failed to successfully register new asset at path %s to moduleId %s", assetPath.getFullPath().c_str(), targetModuleId.c_str());
2493                  activityLog.push_back(importLogBuffer);
2494               }
2495            }
2496            else
2497            {
2498               String assetId = importingAssets[i]->moduleName + ":" + importingAssets[i]->assetName;
2499               bool refreshSuccess = AssetDatabase.refreshAsset(assetId.c_str());
2500
2501               if (!refreshSuccess)
2502               {
2503                  dSprintf(importLogBuffer, sizeof(importLogBuffer), "AssetImporter::importAssets - Failed to refresh reimporting asset %s.", importingAssets[i]->assetName.c_str());
2504                  activityLog.push_back(importLogBuffer);
2505               }
2506            }
2507         }
2508
2509         //recurse if needed
2510         importAssets(importingAssets[i]);
2511      }
2512   }
2513   else
2514   {
2515      //this is the child recursing section
2516      for (U32 i = 0; i < assetItem->childAssetItems.size(); i++)
2517      {
2518         AssetImportObject* childItem = assetItem->childAssetItems[i];
2519
2520         if (childItem->skip)
2521            continue;
2522
2523         Torque::Path assetPath;
2524         if (childItem->assetType == String("ImageAsset"))
2525         {
2526            assetPath = importImageAsset(childItem);
2527         }
2528         else if (childItem->assetType == String("ShapeAsset"))
2529         {
2530            assetPath = importShapeAsset(childItem);
2531         }
2532         else if (childItem->assetType == String("SoundAsset"))
2533         {
2534            assetPath = importSoundAsset(childItem);
2535         }
2536         else if (childItem->assetType == String("MaterialAsset"))
2537         {
2538            assetPath = importMaterialAsset(childItem);
2539         }
2540         /*else if (childItem->assetType == String("ShapeAnimationAsset"))
2541            assetPath = ShapeAnimationAsset::importAsset(childItem);*/
2542         else
2543         {
2544            finalImportedAssetPath = String::EmptyString;
2545
2546            String processCommand = "import";
2547            processCommand += childItem->assetType;
2548            if (isMethod(processCommand.c_str()))
2549            {
2550               ConsoleValueRef importReturnVal = Con::executef(this, processCommand.c_str(), childItem);
2551               assetPath = Torque::Path(importReturnVal.getStringValue());
2552            }
2553         }
2554
2555         if (assetPath.isEmpty() && childItem->assetType != String("MaterialAsset"))
2556         {
2557            dSprintf(importLogBuffer, sizeof(importLogBuffer), "AssetImporter::importAssets - Import attempt of %s failed, so skipping asset.", childItem->assetName.c_str());
2558            activityLog.push_back(importLogBuffer);
2559
2560            continue;
2561         }
2562         else
2563         {
2564            //If we got a valid filepath back from the import action, then we know we're good to go and we can go ahead and register the asset!
2565            if (!isReimport)
2566            {
2567               bool registerSuccess = AssetDatabase.addDeclaredAsset(moduleDef, assetPath.getFullPath().c_str());
2568
2569               if (!registerSuccess)
2570               {
2571                  dSprintf(importLogBuffer, sizeof(importLogBuffer), "AssetImporter::importAssets - Failed to successfully register new asset at path %s to moduleId %s", assetPath.getFullPath().c_str(), targetModuleId.c_str());
2572                  activityLog.push_back(importLogBuffer);
2573               }
2574            }
2575            else
2576            {
2577               String assetId = childItem->moduleName + ":" + childItem->assetName;
2578               bool refreshSuccess = AssetDatabase.refreshAsset(assetId.c_str());
2579
2580               if (!refreshSuccess)
2581               {
2582                  dSprintf(importLogBuffer, sizeof(importLogBuffer), "AssetImporter::importAssets - Failed to refresh reimporting asset %s.", childItem->assetName.c_str());
2583                  activityLog.push_back(importLogBuffer);
2584               }
2585            }
2586         }
2587
2588         //recurse if needed
2589         importAssets(childItem);
2590      }
2591   }
2592}
2593
2594//
2595// Type-specific import logic
2596//
2597
2598Torque::Path AssetImporter::importImageAsset(AssetImportObject* assetItem)
2599{
2600   dSprintf(importLogBuffer, sizeof(importLogBuffer), "Beginning importing of Image Asset: %s", assetItem->assetName.c_str());
2601   activityLog.push_back(importLogBuffer);
2602
2603   ImageAsset* newAsset = new ImageAsset();
2604   newAsset->registerObject();
2605
2606   StringTableEntry assetName = StringTable->insert(assetItem->assetName.c_str());
2607
2608   String imageFileName = assetItem->filePath.getFileName() + "." + assetItem->filePath.getExtension();
2609   String assetPath = targetPath + "/" + imageFileName;
2610   String tamlPath = targetPath + "/" + assetName + ".asset.taml";
2611   String originalPath = assetItem->filePath.getFullPath().c_str();
2612
2613   char qualifiedFromFile[2048];
2614   char qualifiedToFile[2048];
2615
2616   Platform::makeFullPathName(originalPath.c_str(), qualifiedFromFile, sizeof(qualifiedFromFile));
2617   Platform::makeFullPathName(assetPath.c_str(), qualifiedToFile, sizeof(qualifiedToFile));
2618   
2619   newAsset->setAssetName(assetName);
2620   newAsset->setImageFileName(imageFileName.c_str());
2621
2622   //If it's not a re-import, check that the file isn't being in-place imported. If it isn't, store off the original
2623   //file path for reimporting support later
2624   if (!isReimport && String::compare(qualifiedFromFile, qualifiedToFile))
2625   {
2626      newAsset->setDataField(StringTable->insert("originalFilePath"), nullptr, qualifiedFromFile);
2627   }
2628
2629   ImageAsset::ImageTypes imageType = ImageAsset::getImageTypeFromName(assetItem->imageSuffixType.c_str());
2630   newAsset->setImageType(imageType);
2631
2632   Taml tamlWriter;
2633   bool importSuccessful = tamlWriter.write(newAsset, tamlPath.c_str());
2634
2635   if (!importSuccessful)
2636   {
2637      dSprintf(importLogBuffer, sizeof(importLogBuffer), "Error! Unable to write asset taml file %s", tamlPath.c_str());
2638      activityLog.push_back(importLogBuffer);
2639      return "";
2640   }
2641
2642   if (!isReimport)
2643   {
2644      bool isInPlace = !String::compare(qualifiedFromFile, qualifiedToFile);
2645
2646      if (!isInPlace && !dPathCopy(qualifiedFromFile, qualifiedToFile, !isReimport))
2647      {
2648         dSprintf(importLogBuffer, sizeof(importLogBuffer), "Error! Unable to copy file %s", assetItem->filePath.getFullPath().c_str());
2649         activityLog.push_back(importLogBuffer);
2650         return "";
2651      }
2652   }
2653
2654   return tamlPath;
2655}
2656
2657Torque::Path AssetImporter::importMaterialAsset(AssetImportObject* assetItem)
2658{
2659   dSprintf(importLogBuffer, sizeof(importLogBuffer), "Beginning importing of Material Asset: %s", assetItem->assetName.c_str());
2660   activityLog.push_back(importLogBuffer);
2661
2662   MaterialAsset* newAsset = new MaterialAsset();
2663   newAsset->registerObject();
2664
2665   StringTableEntry assetName = StringTable->insert(assetItem->assetName.c_str());
2666
2667   String tamlPath = targetPath + "/" + assetName + ".asset.taml";
2668   String scriptName = assetItem->assetName + "." TORQUE_SCRIPT_EXTENSION;
2669   String scriptPath = targetPath + "/" + scriptName;
2670   String originalPath = assetItem->filePath.getFullPath().c_str();
2671
2672   char qualifiedFromFile[2048];
2673
2674   Platform::makeFullPathName(originalPath.c_str(), qualifiedFromFile, sizeof(qualifiedFromFile));
2675
2676   newAsset->setAssetName(assetName);
2677   newAsset->setScriptFile(scriptName.c_str());
2678   newAsset->setDataField(StringTable->insert("originalFilePath"), nullptr, qualifiedFromFile);
2679   newAsset->setDataField(StringTable->insert("materialDefinitionName"), nullptr, assetName);
2680   
2681
2682   //iterate through and write out the material maps dependencies
2683   S32 dependencySlotId = 0;
2684   for (U32 i = 0; i < assetItem->childAssetItems.size(); i++)
2685   {
2686      AssetImportObject* childItem = assetItem->childAssetItems[i];
2687
2688      if (childItem->skip || !childItem->processed || childItem->assetType.compare("ImageAsset") != 0)
2689         continue;
2690
2691      char dependencyFieldName[64];
2692      dSprintf(dependencyFieldName, 64, "imageMap%i", dependencySlotId);
2693
2694      char dependencyFieldDef[512];
2695      dSprintf(dependencyFieldDef, 512, "@Asset=%s:%s", targetModuleId.c_str(), childItem->assetName.c_str());
2696
2697      newAsset->setDataField(StringTable->insert(dependencyFieldName), nullptr, dependencyFieldDef);
2698
2699      dependencySlotId++;
2700   }
2701
2702   Taml tamlWriter;
2703   bool importSuccessful = tamlWriter.write(newAsset, tamlPath.c_str());
2704
2705   if (!importSuccessful)
2706   {
2707      dSprintf(importLogBuffer, sizeof(importLogBuffer), "Error! Unable to write asset taml file %s", tamlPath.c_str());
2708      activityLog.push_back(importLogBuffer);
2709      return "";
2710   }
2711
2712   //build the ORMConfig file if we're flagged to and have valid image maps
2713   if (activeImportConfig->CreateORMConfig)
2714   {
2715      AssetImportObject* ormMap = nullptr;
2716      AssetImportObject* roughnessMap = nullptr;
2717      AssetImportObject* metalnessMap = nullptr;
2718      AssetImportObject* aoMap = nullptr;
2719
2720      //We need to find any/all respective image maps for the given channels
2721      for (U32 i = 0; i < assetItem->childAssetItems.size(); i++)
2722      {
2723         AssetImportObject* childItem = assetItem->childAssetItems[i];
2724
2725         if (childItem->skip || childItem->assetType.compare("ImageAsset") != 0)
2726            continue;
2727
2728         if (childItem->imageSuffixType.compare("ORMConfig") == 0)
2729            ormMap = childItem;
2730         else if(childItem->imageSuffixType.compare("Roughness") == 0)
2731            roughnessMap = childItem;
2732         else if (childItem->imageSuffixType.compare("Metalness") == 0)
2733            metalnessMap = childItem;
2734         else if (childItem->imageSuffixType.compare("AO") == 0)
2735            aoMap = childItem;
2736      }
2737
2738      if (ormMap != nullptr && ormMap->generatedAsset)
2739      {
2740         if (roughnessMap != nullptr || metalnessMap != nullptr || aoMap != nullptr)
2741         {
2742            U32 channelKey[4] = { 0,1,2,3 };
2743
2744            GFX->getTextureManager()->saveCompositeTexture(aoMap->filePath.getFullPath(), roughnessMap->filePath.getFullPath(), metalnessMap->filePath.getFullPath(), "",
2745               channelKey, ormMap->filePath.getFullPath(), &GFXTexturePersistentProfile);
2746         }
2747      }
2748   }
2749
2750   FileObject* file = new FileObject();
2751   file->registerObject();
2752
2753   //Now write the script file containing our material out
2754   //There's 2 ways to do this. If we're in-place importing an existing asset, we can see if the definition existed already, like in an old
2755   //materials.tscript file. if it does, we can just find the object by name, and save it out to our new file
2756   //If not, we'll just generate one
2757   Material* existingMat = MATMGR->getMaterialDefinitionByName(assetName);
2758
2759   //It's also possible that, for legacy models, the material hooks in via the material's mapTo field, and the material name is something completely different
2760   //So we'll check for that as well if we didn't find it by name up above
2761   if (existingMat == nullptr)
2762   {
2763      existingMat = MATMGR->getMaterialDefinitionByMapTo(assetName);
2764   }
2765
2766   if (existingMat)
2767   {
2768      for (U32 i = 0; i < assetItem->childAssetItems.size(); i++)
2769      {
2770         AssetImportObject* childItem = assetItem->childAssetItems[i];
2771
2772         if (childItem->skip || !childItem->processed || childItem->assetType.compare("ImageAsset") != 0)
2773            continue;
2774
2775         String path = childItem->filePath.getFullFileName();
2776
2777         String mapFieldName = "";
2778         String assetFieldName = "";
2779
2780         ImageAsset::ImageTypes imageType = ImageAsset::getImageTypeFromName(childItem->imageSuffixType);
2781
2782         if (imageType == ImageAsset::ImageTypes::Albedo || childItem->imageSuffixType.isEmpty())
2783         {
2784            mapFieldName = "DiffuseMap";
2785         }
2786         else if (imageType == ImageAsset::ImageTypes::Normal)
2787         {
2788            mapFieldName = "NormalMap";
2789         }
2790         else if (imageType == ImageAsset::ImageTypes::ORMConfig)
2791         {
2792            mapFieldName = "ORMConfig";
2793         }
2794         else if (imageType == ImageAsset::ImageTypes::Metalness)
2795         {
2796            mapFieldName = "MetalnessMap";
2797         }
2798         else if (imageType == ImageAsset::ImageTypes::AO)
2799         {
2800            mapFieldName = "AOMap";
2801         }
2802         else if (imageType == ImageAsset::ImageTypes::Roughness)
2803         {
2804            mapFieldName = "RoughnessMap";
2805         }
2806
2807         assetFieldName = mapFieldName + "Asset[0]";
2808         mapFieldName += "[0]";
2809
2810         //If there's already an existing image map file on the material definition in this slot, don't override it
2811         if(!path.isEmpty())
2812            existingMat->writeField(mapFieldName.c_str(), path.c_str());
2813
2814         String targetAsset = targetModuleId + ":" + childItem->assetName;
2815
2816         existingMat->writeField(assetFieldName.c_str(), targetAsset.c_str());
2817      }
2818      existingMat->save(scriptPath.c_str());
2819   }
2820   //However, if we didn't find any existing material, then we'll want to go ahead and just write out a new one
2821   else if (file->openForWrite(scriptPath.c_str()))
2822   {
2823      file->writeLine((U8*)"//--- OBJECT WRITE BEGIN ---");
2824
2825      char lineBuffer[1024];
2826      dSprintf(lineBuffer, 1024, "singleton Material(%s) {", assetName);
2827      file->writeLine((U8*)lineBuffer);
2828
2829      dSprintf(lineBuffer, 1024, "   mapTo=\"%s\";", assetName);
2830      file->writeLine((U8*)lineBuffer);
2831
2832      bool hasRoughness = false;
2833      for (U32 i = 0; i < assetItem->childAssetItems.size(); i++)
2834      {
2835         AssetImportObject* childItem = assetItem->childAssetItems[i];
2836
2837         if (childItem->skip || !childItem->processed || childItem->assetType.compare("ImageAsset") != 0)
2838            continue;
2839
2840         String mapFieldName = "";
2841
2842         String assetFieldName = "";
2843
2844         ImageAsset::ImageTypes imageType = ImageAsset::getImageTypeFromName(childItem->imageSuffixType);
2845
2846         if (imageType == ImageAsset::ImageTypes::Albedo || childItem->imageSuffixType.isEmpty())
2847         {
2848            mapFieldName = "DiffuseMap";
2849         }
2850         else if (imageType == ImageAsset::ImageTypes::Normal)
2851         {
2852            mapFieldName = "NormalMap";
2853         }
2854         else if (imageType == ImageAsset::ImageTypes::ORMConfig)
2855         {
2856            mapFieldName = "ORMConfigMap";
2857         }
2858         else if (imageType == ImageAsset::ImageTypes::Metalness)
2859         {
2860            mapFieldName = "MetalnessMap";
2861         }
2862         else if (imageType == ImageAsset::ImageTypes::AO)
2863         {
2864            mapFieldName = "AOMap";
2865         }
2866         else if (imageType == ImageAsset::ImageTypes::Roughness)
2867         {
2868            mapFieldName = "RoughnessMap";
2869            hasRoughness = true;
2870         }
2871
2872         assetFieldName = mapFieldName + "Asset";
2873         mapFieldName += "[0]";
2874
2875         //String path = childItem->filePath.getFullFileName();
2876         //dSprintf(lineBuffer, 1024, "   %s = \"%s\";", mapFieldName.c_str(), path.c_str());
2877         //file->writeLine((U8*)lineBuffer);
2878
2879         dSprintf(lineBuffer, 1024, "   %s = \"%s:%s\";", assetFieldName.c_str(), targetModuleId.c_str(), childItem->assetName.c_str());
2880         file->writeLine((U8*)lineBuffer);
2881      }
2882
2883      if (hasRoughness)
2884      {
2885         file->writeLine((U8*)"   invertSmoothness = true;");
2886         
2887      }
2888
2889      file->writeLine((U8*)"};");
2890      file->writeLine((U8*)"//--- OBJECT WRITE END ---");
2891
2892      file->close();
2893   }
2894   else
2895   {
2896      dSprintf(importLogBuffer, sizeof(importLogBuffer), "Error! Unable to write asset script file %s", scriptPath.c_str());
2897      activityLog.push_back(importLogBuffer);
2898      return "";
2899   }
2900
2901   return tamlPath;
2902}
2903
2904Torque::Path AssetImporter::importShapeAsset(AssetImportObject* assetItem)
2905{
2906   dSprintf(importLogBuffer, sizeof(importLogBuffer), "Beginning importing of Shape Asset: %s", assetItem->assetName.c_str());
2907   activityLog.push_back(importLogBuffer);
2908
2909   ShapeAsset* newAsset = new ShapeAsset();
2910   newAsset->registerObject();
2911
2912   StringTableEntry assetName = StringTable->insert(assetItem->assetName.c_str());
2913
2914   String shapeFileName = assetItem->filePath.getFileName() + "." + assetItem->filePath.getExtension();
2915   String constructorFileName = assetItem->filePath.getFileName() + "." TORQUE_SCRIPT_EXTENSION;
2916   String assetPath = targetPath + "/" + shapeFileName;
2917   String constructorPath = targetPath + "/" + constructorFileName;
2918   String tamlPath = targetPath + "/" + assetName + ".asset.taml";
2919   String originalPath = assetItem->filePath.getFullPath().c_str();
2920   String originalConstructorPath = assetItem->filePath.getPath() + "/" + constructorFileName;
2921
2922   char qualifiedFromFile[2048];
2923   char qualifiedToFile[2048];
2924   char qualifiedFromCSFile[2048];
2925   char qualifiedToCSFile[2048];
2926
2927   Platform::makeFullPathName(originalPath.c_str(), qualifiedFromFile, sizeof(qualifiedFromFile));
2928   Platform::makeFullPathName(assetPath.c_str(), qualifiedToFile, sizeof(qualifiedToFile));
2929
2930   Platform::makeFullPathName(originalConstructorPath.c_str(), qualifiedFromCSFile, sizeof(qualifiedFromCSFile));
2931   Platform::makeFullPathName(constructorPath.c_str(), qualifiedToCSFile, sizeof(qualifiedToCSFile));
2932
2933   newAsset->setAssetName(assetName);
2934   newAsset->setShapeFile(shapeFileName.c_str());
2935   newAsset->setShapeConstructorFile(constructorFileName.c_str());
2936
2937   AssetImportConfig* cachedConfig = new AssetImportConfig();;
2938   cachedConfig->registerObject();
2939   activeImportConfig->CopyTo(cachedConfig);
2940
2941   if (!activeImportConfig->UseManualShapeConfigRules)
2942   {
2943      //Try and load a sis file if it exists for this format
2944      activeImportConfig->loadSISFile(assetItem->filePath);
2945   }
2946
2947   //If it's not a re-import, check that the file isn't being in-place imported. If it isn't, store off the original
2948   //file path for reimporting support later
2949   if (!isReimport && String::compare(qualifiedFromFile, qualifiedToFile))
2950   {
2951      newAsset->setDataField(StringTable->insert("originalFilePath"), nullptr, qualifiedFromFile);
2952   }
2953
2954   //iterate through and write out the material maps dependencies
2955   S32 dependencySlotId = 0;
2956   for (U32 i = 0; i < assetItem->childAssetItems.size(); i++)
2957   {
2958      AssetImportObject* childItem = assetItem->childAssetItems[i];
2959
2960      if (childItem->skip || !childItem->processed)
2961         continue;
2962
2963      if (childItem->assetType.compare("MaterialAsset") == 0)
2964      {
2965         char dependencyFieldName[64];
2966         dSprintf(dependencyFieldName, 64, "materialSlot%i", dependencySlotId);
2967
2968         char dependencyFieldDef[512];
2969         dSprintf(dependencyFieldDef, 512, "@Asset=%s:%s", targetModuleId.c_str(), childItem->assetName.c_str());
2970  
2971         newAsset->setDataField(StringTable->insert(dependencyFieldName), nullptr, dependencyFieldDef);
2972
2973         dependencySlotId++;
2974      }
2975      else if (childItem->assetType.compare("ShapeAnimationAsset") == 0)
2976      {
2977         char dependencyFieldName[64];
2978         dSprintf(dependencyFieldName, 64, "animationSequence%i", dependencySlotId);
2979
2980         char dependencyFieldDef[512];
2981         dSprintf(dependencyFieldDef, 512, "@Asset=%s:%s", targetModuleId.c_str(), childItem->assetName.c_str());
2982
2983         newAsset->setDataField(StringTable->insert(dependencyFieldName), nullptr, dependencyFieldDef);
2984
2985         dependencySlotId++;
2986      }
2987   }
2988
2989   Taml tamlWriter;
2990   bool importSuccessful = tamlWriter.write(newAsset, tamlPath.c_str());
2991
2992   if (!importSuccessful)
2993   {
2994      dSprintf(importLogBuffer, sizeof(importLogBuffer), "Error! Unable to write asset taml file %s", tamlPath.c_str());
2995      activityLog.push_back(importLogBuffer);
2996      return "";
2997   }
2998
2999   bool makeNewConstructor = true;
3000   if (!isReimport)
3001   {
3002      bool isInPlace = !String::compare(qualifiedFromFile, qualifiedToFile);
3003
3004      if (!isInPlace && !dPathCopy(qualifiedFromFile, qualifiedToFile, !isReimport))
3005      {
3006         dSprintf(importLogBuffer, sizeof(importLogBuffer), "Error! Unable to copy file %s", qualifiedFromFile);
3007         activityLog.push_back(importLogBuffer);
3008         return "";
3009      }
3010
3011      if (!isInPlace && Platform::isFile(qualifiedFromCSFile))
3012      {
3013         if(!dPathCopy(qualifiedFromCSFile, qualifiedToCSFile, !isReimport))
3014         {
3015            dSprintf(importLogBuffer, sizeof(importLogBuffer), "Error! Unable to copy file %s", qualifiedFromCSFile);
3016            activityLog.push_back(importLogBuffer);
3017         }
3018         else
3019         {
3020            //We successfully copied the original constructor file, so no extra work required
3021            makeNewConstructor = false;
3022            dSprintf(importLogBuffer, sizeof(importLogBuffer), "Successfully copied original TSShape Constructor file %s", qualifiedFromCSFile);
3023            activityLog.push_back(importLogBuffer);
3024         }
3025      }
3026   }
3027
3028   if (makeNewConstructor)
3029   {
3030      dSprintf(importLogBuffer, sizeof(importLogBuffer), "Beginning creation of new TSShapeConstructor file: %s", qualifiedToCSFile);
3031      activityLog.push_back(importLogBuffer);
3032
3033      //find/create shape constructor
3034      TSShapeConstructor* constructor = TSShapeConstructor::findShapeConstructor(Torque::Path(qualifiedToFile).getFullPath());
3035      if (constructor == nullptr)
3036      {
3037         constructor = new TSShapeConstructor(qualifiedToFile);
3038
3039         String constructorName = assetItem->filePath.getFileName() + assetItem->filePath.getExtension().substr(0, 3);
3040         constructorName.replace(" ", "_");
3041         constructorName.replace("-", "_");
3042         constructorName.replace(".", "_");
3043         constructorName = Sim::getUniqueName(constructorName.c_str());
3044         constructor->registerObject(constructorName.c_str());
3045      }
3046
3047
3048      //now we write the import config logic into the constructor itself to ensure we load like we wanted it to
3049      String neverImportMats;
3050
3051      if (activeImportConfig->IgnoreMaterials.isNotEmpty())
3052      {
3053         U32 ignoredMatNamesCount = StringUnit::getUnitCount(activeImportConfig->IgnoreMaterials, ",;\t");
3054         for (U32 i = 0; i < ignoredMatNamesCount; i++)
3055         {
3056            if (i == 0)
3057               neverImportMats = StringUnit::getUnit(activeImportConfig->IgnoreMaterials, i, ",;\t");
3058            else
3059               neverImportMats += String("\t") + StringUnit::getUnit(activeImportConfig->IgnoreMaterials, i, ",;\t");
3060         }
3061      }
3062
3063      if (activeImportConfig->DoUpAxisOverride)
3064      {
3065         S32 upAxis = domUpAxisType::UPAXISTYPE_Z_UP;
3066         if (activeImportConfig->UpAxisOverride.compare("X_AXIS") == 0)
3067         {
3068            upAxis = domUpAxisType::UPAXISTYPE_X_UP;
3069         }
3070         else if (activeImportConfig->UpAxisOverride.compare("Y_AXIS") == 0)
3071         {
3072            upAxis = domUpAxisType::UPAXISTYPE_Y_UP;
3073         }
3074         else if (activeImportConfig->UpAxisOverride.compare("Z_AXIS") == 0)
3075         {
3076            upAxis = domUpAxisType::UPAXISTYPE_Z_UP;
3077         }
3078         constructor->mOptions.upAxis = (domUpAxisType)upAxis;
3079      }
3080
3081      if (activeImportConfig->DoScaleOverride)
3082         constructor->mOptions.unit = activeImportConfig->ScaleOverride;
3083      else
3084         constructor->mOptions.unit = -1;
3085
3086      enum eAnimTimingType
3087      {
3088         FrameCount = 0,
3089         Seconds = 1,
3090         Milliseconds = 1000
3091      };
3092
3093      S32 lodType = ColladaUtils::ImportOptions::eLodType::TrailingNumber;
3094      if (activeImportConfig->LODType.compare("TrailingNumber") == 0)
3095         lodType = ColladaUtils::ImportOptions::eLodType::TrailingNumber;
3096      else if (activeImportConfig->LODType.compare("SingleSize") == 0)
3097         lodType = ColladaUtils::ImportOptions::eLodType::SingleSize;
3098      else if (activeImportConfig->LODType.compare("DetectDTS") == 0)
3099         lodType = ColladaUtils::ImportOptions::eLodType::DetectDTS;
3100      constructor->mOptions.lodType = (ColladaUtils::ImportOptions::eLodType)lodType;
3101
3102      constructor->mOptions.singleDetailSize = activeImportConfig->convertLeftHanded;
3103      constructor->mOptions.alwaysImport = activeImportConfig->AlwaysImportedNodes;
3104      constructor->mOptions.neverImport = activeImportConfig->AlwaysIgnoreNodes;
3105      constructor->mOptions.alwaysImportMesh = activeImportConfig->AlwaysImportMeshes;
3106      constructor->mOptions.neverImportMesh = activeImportConfig->AlwaysIgnoreMeshes;
3107      constructor->mOptions.ignoreNodeScale = activeImportConfig->IgnoreNodeScale;
3108      constructor->mOptions.adjustCenter = activeImportConfig->AdjustCenter;
3109      constructor->mOptions.adjustFloor = activeImportConfig->AdjustFloor;
3110
3111      constructor->mOptions.convertLeftHanded = activeImportConfig->convertLeftHanded;
3112      constructor->mOptions.calcTangentSpace = activeImportConfig->calcTangentSpace;
3113      constructor->mOptions.genUVCoords = activeImportConfig->genUVCoords;
3114      constructor->mOptions.flipUVCoords = activeImportConfig->flipUVCoords;
3115      constructor->mOptions.findInstances = activeImportConfig->findInstances;
3116      constructor->mOptions.limitBoneWeights = activeImportConfig->limitBoneWeights;
3117      constructor->mOptions.joinIdenticalVerts = activeImportConfig->JoinIdenticalVerts;
3118      constructor->mOptions.reverseWindingOrder = activeImportConfig->reverseWindingOrder;
3119      constructor->mOptions.invertNormals = activeImportConfig->invertNormals;
3120      constructor->mOptions.removeRedundantMats = activeImportConfig->removeRedundantMats;
3121
3122      S32 animTimingType;
3123      if (activeImportConfig->animTiming.compare("FrameCount") == 0)
3124         animTimingType = ColladaUtils::ImportOptions::eAnimTimingType::FrameCount;
3125      else if (activeImportConfig->animTiming.compare("Seconds") == 0)
3126         animTimingType = ColladaUtils::ImportOptions::eAnimTimingType::Seconds;
3127      else// (activeImportConfig->animTiming.compare("Milliseconds") == 0)
3128         animTimingType = ColladaUtils::ImportOptions::eAnimTimingType::Milliseconds;
3129
3130      constructor->mOptions.animTiming = (ColladaUtils::ImportOptions::eAnimTimingType)animTimingType;
3131
3132      constructor->mOptions.animFPS = activeImportConfig->animFPS;
3133
3134      constructor->mOptions.neverImportMat = neverImportMats;
3135
3136      PersistenceManager* constructorPersist = new PersistenceManager();
3137      constructorPersist->registerObject();
3138      constructorPersist->setDirty(constructor, qualifiedToCSFile);
3139
3140      if (!constructorPersist->saveDirtyObject(constructor))
3141      {
3142         dSprintf(importLogBuffer, sizeof(importLogBuffer), "Error! Failed to save shape constructor file to %s", constructorPath.c_str());
3143         activityLog.push_back(importLogBuffer);
3144      }
3145      else
3146      {
3147         dSprintf(importLogBuffer, sizeof(importLogBuffer), "Finished creating shape constructor file to %s", constructorPath.c_str());
3148         activityLog.push_back(importLogBuffer);
3149      }
3150
3151      constructorPersist->destroySelf();
3152   }
3153
3154   //restore the cached version just in case we loaded a sis file
3155   cachedConfig->CopyTo(activeImportConfig);
3156   cachedConfig->deleteObject();
3157
3158   return tamlPath;
3159}
3160
3161Torque::Path AssetImporter::importSoundAsset(AssetImportObject* assetItem)
3162{
3163   dSprintf(importLogBuffer, sizeof(importLogBuffer), "Beginning importing of Sound Asset: %s", assetItem->assetName.c_str());
3164   activityLog.push_back(importLogBuffer);
3165
3166   SoundAsset* newAsset = new SoundAsset();
3167   newAsset->registerObject();
3168
3169   StringTableEntry assetName = StringTable->insert(assetItem->assetName.c_str());
3170
3171   String imageFileName = assetItem->filePath.getFileName() + "." + assetItem->filePath.getExtension();
3172   String assetPath = targetPath + "/" + imageFileName;
3173   String tamlPath = targetPath + "/" + assetName + ".asset.taml";
3174   String originalPath = assetItem->filePath.getFullPath().c_str();
3175
3176   char qualifiedFromFile[2048];
3177   char qualifiedToFile[2048];
3178
3179   Platform::makeFullPathName(originalPath.c_str(), qualifiedFromFile, sizeof(qualifiedFromFile));
3180   Platform::makeFullPathName(assetPath.c_str(), qualifiedToFile, sizeof(qualifiedToFile));
3181
3182   newAsset->setAssetName(assetName);
3183   newAsset->setSoundFile(imageFileName.c_str());
3184
3185   //If it's not a re-import, check that the file isn't being in-place imported. If it isn't, store off the original
3186   //file path for reimporting support later
3187   if (!isReimport && String::compare(qualifiedFromFile, qualifiedToFile))
3188   {
3189      newAsset->setDataField(StringTable->insert("originalFilePath"), nullptr, qualifiedFromFile);
3190   }
3191
3192   Taml tamlWriter;
3193   bool importSuccessful = tamlWriter.write(newAsset, tamlPath.c_str());
3194
3195   if (!importSuccessful)
3196   {
3197      dSprintf(importLogBuffer, sizeof(importLogBuffer), "Error! Unable to write asset taml file %s", tamlPath.c_str());
3198      activityLog.push_back(importLogBuffer);
3199      return "";
3200   }
3201
3202   if (!isReimport)
3203   {
3204      bool isInPlace = !String::compare(qualifiedFromFile, qualifiedToFile);
3205
3206      if (!isInPlace && !dPathCopy(qualifiedFromFile, qualifiedToFile, !isReimport))
3207      {
3208         dSprintf(importLogBuffer, sizeof(importLogBuffer), "Error! Unable to copy file %s", assetItem->filePath.getFullPath().c_str());
3209         activityLog.push_back(importLogBuffer);
3210         return "";
3211      }
3212   }
3213
3214   return tamlPath;
3215}
3216
3217Torque::Path AssetImporter::importShapeAnimationAsset(AssetImportObject* assetItem)
3218{
3219   dSprintf(importLogBuffer, sizeof(importLogBuffer), "Beginning importing of Shape Animation Asset: %s", assetItem->assetName.c_str());
3220   activityLog.push_back(importLogBuffer);
3221
3222   ShapeAnimationAsset* newAsset = new ShapeAnimationAsset();
3223   newAsset->registerObject();
3224
3225   StringTableEntry assetName = StringTable->insert(assetItem->assetName.c_str());
3226
3227   String imageFileName = assetItem->filePath.getFileName() + "." + assetItem->filePath.getExtension();
3228   String assetPath = targetPath + "/" + imageFileName;
3229   String tamlPath = targetPath + "/" + assetName + ".asset.taml";
3230   String originalPath = assetItem->filePath.getFullPath().c_str();
3231
3232   char qualifiedFromFile[2048];
3233   char qualifiedToFile[2048];
3234
3235   Platform::makeFullPathName(originalPath.c_str(), qualifiedFromFile, sizeof(qualifiedFromFile));
3236   Platform::makeFullPathName(assetPath.c_str(), qualifiedToFile, sizeof(qualifiedToFile));
3237
3238   newAsset->setAssetName(assetName);
3239   newAsset->setAnimationFile(imageFileName.c_str());
3240
3241   //If it's not a re-import, check that the file isn't being in-place imported. If it isn't, store off the original
3242   //file path for reimporting support later
3243   if (!isReimport && String::compare(qualifiedFromFile, qualifiedToFile))
3244   {
3245      newAsset->setDataField(StringTable->insert("originalFilePath"), nullptr, qualifiedFromFile);
3246   }
3247
3248   Taml tamlWriter;
3249   bool importSuccessful = tamlWriter.write(newAsset, tamlPath.c_str());
3250
3251   if (!importSuccessful)
3252   {
3253      dSprintf(importLogBuffer, sizeof(importLogBuffer), "Error! Unable to write asset taml file %s", tamlPath.c_str());
3254      activityLog.push_back(importLogBuffer);
3255      return "";
3256   }
3257
3258   if (!isReimport)
3259   {
3260      bool isInPlace = !String::compare(qualifiedFromFile, qualifiedToFile);
3261
3262      if (!isInPlace && !dPathCopy(qualifiedFromFile, qualifiedToFile, !isReimport))
3263      {
3264         dSprintf(importLogBuffer, sizeof(importLogBuffer), "Error! Unable to copy file %s", assetItem->filePath.getFullPath().c_str());
3265         activityLog.push_back(importLogBuffer);
3266         return "";
3267      }
3268   }
3269
3270   return tamlPath;
3271}
3272