assetImporter.cpp 145 KB

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