assetImporter.cpp
Engine/source/T3D/assets/assetImporter.cpp
Classes:
class
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