assetImporter.cpp 114 KB

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