assetImporter.cpp 132 KB

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