colladaUtils.cpp 122 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include <algorithm>
  23. #include "console/console.h"
  24. #include "gfx/bitmap/gBitmap.h"
  25. #include "ts/collada/colladaUtils.h"
  26. #include "materials/matInstance.h"
  27. //special handling for export classes
  28. #include "T3D/convexShape.h"
  29. using namespace ColladaUtils;
  30. #define MAX_PATH_LENGTH 256
  31. // Helper macro to create Collada elements
  32. #define CREATE_ELEMENT(container, name, type) \
  33. type* name = daeSafeCast<type>(container->createAndPlace(#name));
  34. ColladaUtils::ImportOptions& ColladaUtils::getOptions()
  35. {
  36. static ImportOptions options;
  37. return options;
  38. }
  39. //------------------------------------------------------------------------------
  40. // Utility functions
  41. // Convert a transform from the Collada model coordinate system to the DTS coordinate
  42. // system
  43. void ColladaUtils::convertTransform(MatrixF& mat)
  44. {
  45. MatrixF rot(true);
  46. switch (ColladaUtils::getOptions().upAxis)
  47. {
  48. case UPAXISTYPE_X_UP:
  49. // rotate 90 around Y-axis, then 90 around Z-axis
  50. rot(0,0) = 0.0f; rot(1,0) = 1.0f;
  51. rot(1,1) = 0.0f; rot(2,1) = 1.0f;
  52. rot(0,2) = 1.0f; rot(2,2) = 0.0f;
  53. // pre-multiply the transform by the rotation matrix
  54. mat.mulL(rot);
  55. break;
  56. case UPAXISTYPE_Y_UP:
  57. // rotate 180 around Y-axis, then 90 around X-axis
  58. rot(0,0) = -1.0f;
  59. rot(1,1) = 0.0f; rot(2,1) = 1.0f;
  60. rot(1,2) = 1.0f; rot(2,2) = 0.0f;
  61. // pre-multiply the transform by the rotation matrix
  62. mat.mulL(rot);
  63. break;
  64. case UPAXISTYPE_Z_UP:
  65. default:
  66. // nothing to do
  67. break;
  68. }
  69. }
  70. /// Find the COMMON profile element in an effect
  71. const domProfile_COMMON* ColladaUtils::findEffectCommonProfile(const domEffect* effect)
  72. {
  73. if (effect) {
  74. // Find the COMMON profile
  75. const domFx_profile_abstract_Array& profiles = effect->getFx_profile_abstract_array();
  76. for (S32 iProfile = 0; iProfile < profiles.getCount(); iProfile++) {
  77. if (profiles[iProfile]->getElementType() == COLLADA_TYPE::PROFILE_COMMON)
  78. return daeSafeCast<domProfile_COMMON>(profiles[iProfile]);
  79. }
  80. }
  81. return NULL;
  82. }
  83. /// Find the <diffuse> element in the COMMON profile of an effect
  84. const domCommon_color_or_texture_type_complexType* ColladaUtils::findEffectDiffuse(const domEffect* effect)
  85. {
  86. const domProfile_COMMON* profile = findEffectCommonProfile(effect);
  87. if (profile) {
  88. if (profile->getTechnique()->getLambert())
  89. return profile->getTechnique()->getLambert()->getDiffuse();
  90. else if (profile->getTechnique()->getPhong())
  91. return profile->getTechnique()->getPhong()->getDiffuse();
  92. else if (profile->getTechnique()->getBlinn())
  93. return profile->getTechnique()->getBlinn()->getDiffuse();
  94. }
  95. return NULL;
  96. }
  97. /// Find the <specular> element in the COMMON profile of an effect
  98. const domCommon_color_or_texture_type_complexType* ColladaUtils::findEffectSpecular(const domEffect* effect)
  99. {
  100. const domProfile_COMMON* profile = findEffectCommonProfile(effect);
  101. if (profile) {
  102. if (profile->getTechnique()->getLambert())
  103. return NULL; // no <specular> element for Lambert shader
  104. else if (profile->getTechnique()->getPhong())
  105. return profile->getTechnique()->getPhong()->getSpecular();
  106. else if (profile->getTechnique()->getBlinn())
  107. return profile->getTechnique()->getBlinn()->getSpecular();
  108. }
  109. return NULL;
  110. }
  111. const domFx_sampler2D_common_complexType* ColladaUtils::getTextureSampler(const domEffect* effect,
  112. const domCommon_color_or_texture_type_complexType* texture)
  113. {
  114. // <texture texture="new_param_SID">.<newparam>.<sampler2D>
  115. if (texture) {
  116. const domCommon_color_or_texture_type_complexType::domTexture* domTex = texture->getTexture();
  117. if (domTex && domTex->getTexture()) {
  118. daeSIDResolver resolver(const_cast<domEffect*>(effect), domTex->getTexture());
  119. const domCommon_newparam_type* param = daeSafeCast<domCommon_newparam_type>(resolver.getElement());
  120. if (param)
  121. return param->getSampler2D();
  122. }
  123. }
  124. return NULL;
  125. }
  126. String ColladaUtils::getSamplerImagePath(const domEffect* effect,
  127. const domFx_sampler2D_common_complexType* sampler2D)
  128. {
  129. // <sampler2D>.<source>.<newparam>.<surface>.<init_from>.<image>.<init_from>
  130. const domProfile_COMMON* profile = findEffectCommonProfile(effect);
  131. if (profile && sampler2D && sampler2D->getSource()) {
  132. // Resolve the SID to get the <surface> param
  133. daeSIDResolver resolver(const_cast<domProfile_COMMON*>(profile), sampler2D->getSource()->getValue());
  134. domCommon_newparam_type* surfaceParam = daeSafeCast<domCommon_newparam_type>(resolver.getElement());
  135. // Get the surface <init_from> element
  136. if (surfaceParam && surfaceParam->getSurface()) {
  137. const domFx_surface_init_common* surfaceInit = surfaceParam->getSurface()->getFx_surface_init_common();
  138. if (surfaceInit && surfaceInit->getInit_from_array().getCount()) {
  139. // Resolve the ID to get the <image>, then read the texture path
  140. xsIDREF& idRef = surfaceInit->getInit_from_array()[0]->getValue();
  141. const domImage* image = daeSafeCast<domImage>(idRef.getElement());
  142. if (image && image->getInit_from())
  143. return resolveImagePath(image);
  144. }
  145. }
  146. }
  147. return "";
  148. }
  149. // Resolve image path into something we can use.
  150. String ColladaUtils::resolveImagePath(const domImage* image)
  151. {
  152. // 1. If the URI string contains an absolute path, use it if
  153. // it is inside the Torque folder, otherwise force textures
  154. // to be in the same folder as the shape.
  155. // 2. If the URI string contains a relative path, append it
  156. // to the shape path (since materials.cs cannot handle
  157. // relative paths).
  158. Torque::Path imagePath;
  159. String imageStr(image->getInit_from()->getValue().originalStr().c_str());
  160. // Trim leading "file://"
  161. if (imageStr.compare("file://", 7) == 0)
  162. imageStr.erase(0, 7);
  163. // Trim leading slash from absolute windows paths. eg. /D:/
  164. if ((imageStr.compare("/", 1) == 0) && (imageStr.find(':') == 2))
  165. imageStr.erase(0, 1);
  166. // Replace %20 with space
  167. imageStr.replace("%20", " ");
  168. if (Platform::isFullPath(imageStr))
  169. {
  170. // Absolute path => check for outside the Torque game folder
  171. imagePath = String( Platform::makeRelativePathName(imageStr, Platform::getMainDotCsDir()) );
  172. if ( !imagePath.getRoot().isEmpty() || // different drive (eg. C:/ vs D:/)
  173. (imagePath.getPath().find("/") == 0) || // different OS (eg. /home vs C:/home)
  174. (imagePath.getPath().find("../") == 0) ) // same drive, outside Torque game folder
  175. {
  176. // Force these to the shape folder
  177. imagePath.setRoot("");
  178. imagePath.setPath("");
  179. }
  180. }
  181. else
  182. {
  183. // Relative path => prepend with shape path
  184. Torque::Path tempPath(imageStr);
  185. imagePath = TSShapeLoader::getShapePath();
  186. imagePath.appendPath(tempPath);
  187. imagePath.setFileName(tempPath.getFileName());
  188. }
  189. // No need to specify the path if it is in the same folder as the model
  190. if (imagePath.getPath() == TSShapeLoader::getShapePath().getPath())
  191. imagePath.setPath("");
  192. // Don't care about the extension
  193. imagePath.setExtension("");
  194. return imagePath.getFullPath();
  195. }
  196. //-----------------------------------------------------------------------------
  197. // Construct the appropriate child class
  198. BasePrimitive* BasePrimitive::get(const daeElement* element)
  199. {
  200. switch (element->getElementType()) {
  201. case COLLADA_TYPE::TRIANGLES: return new ColladaPrimitive<domTriangles>(element);
  202. case COLLADA_TYPE::TRISTRIPS: return new ColladaPrimitive<domTristrips>(element);
  203. case COLLADA_TYPE::TRIFANS: return new ColladaPrimitive<domTrifans>(element);
  204. case COLLADA_TYPE::POLYGONS: return new ColladaPrimitive<domPolygons>(element);
  205. case COLLADA_TYPE::POLYLIST: return new ColladaPrimitive<domPolylist>(element);
  206. default: return 0;
  207. }
  208. }
  209. //------------------------------------------------------------------------------
  210. // Collada animation curves
  211. /// Determine which elements are being targeted
  212. void AnimData::parseTargetString(const char* target, S32 fullCount, const char* elements[])
  213. {
  214. // Assume targeting all elements at offset 0
  215. targetValueCount = fullCount;
  216. targetValueOffset = 0;
  217. // Check for array syntax: (n) or (n)(m)
  218. if (const char* p = dStrchr(target, '(')) {
  219. S32 indN, indM;
  220. if (dSscanf(p, "(%d)(%d)", &indN, &indM) == 2) {
  221. targetValueOffset = (indN * 4) + indM; // @todo: 4x4 matrix only
  222. targetValueCount = 1;
  223. }
  224. else if (dSscanf(p, "(%d)", &indN) == 1) {
  225. targetValueOffset = indN;
  226. targetValueCount = 1;
  227. }
  228. }
  229. else if (const char* p2 = dStrrchr(target, '.')) {
  230. // Check for named elements
  231. for (S32 iElem = 0; elements[iElem][0] != 0; iElem++) {
  232. if (!String::compare(p2, elements[iElem])) {
  233. targetValueOffset = iElem;
  234. targetValueCount = 1;
  235. break;
  236. }
  237. }
  238. }
  239. }
  240. /// Solve the cubic spline B(s) = param for s
  241. F32 AnimData::invertParamCubic(F32 param, F32 x0, F32 x1, F32 x2, F32 x3) const
  242. {
  243. const F64 INVERTPARAMCUBIC_TOL = 1.0e-09;
  244. const F64 INVERTPARAMCUBIC_SMALLERTOL = 1.0e-20;
  245. const F64 INVERTPARAMCUBIC_MAXIT = 100;
  246. // check input value for outside range
  247. if ((param - x0) < INVERTPARAMCUBIC_SMALLERTOL)
  248. return 0.0f;
  249. else if ((x3 - param) < INVERTPARAMCUBIC_SMALLERTOL)
  250. return 1.0f;
  251. U32 iterations = 0;
  252. // de Casteljau Subdivision.
  253. F32 u = 0.0f;
  254. F32 v = 1.0f;
  255. while (iterations < INVERTPARAMCUBIC_MAXIT) {
  256. F64 a = (x0 + x1)*0.5f;
  257. F64 b = (x1 + x2)*0.5f;
  258. F64 c = (x2 + x3)*0.5f;
  259. F64 d = (a + b)*0.5f;
  260. F64 e = (b + c)*0.5f;
  261. F64 f = (d + e)*0.5f;
  262. if (mFabs(f - param) < INVERTPARAMCUBIC_TOL)
  263. break;
  264. if (f < param) {
  265. x0 = f;
  266. x1 = e;
  267. x2 = c;
  268. u = (u + v)*0.5f;
  269. }
  270. else {
  271. x1 = a;
  272. x2 = d;
  273. x3 = f;
  274. v = (u + v)*0.5f;
  275. }
  276. iterations++;
  277. }
  278. return mClampF((u+v)*0.5f, 0.0f, 1.0f);
  279. }
  280. /// Get the interpolated value at time 't'
  281. void AnimData::interpValue(F32 t, U32 offset, double* value) const
  282. {
  283. // handle degenerate animation data
  284. if (input.size() == 0)
  285. {
  286. *value = 0.0f;
  287. return;
  288. }
  289. else if (input.size() == 1)
  290. {
  291. *value = output.getStringArrayData(0)[offset];
  292. return;
  293. }
  294. // clamp time to valid range
  295. F32 curveStart = input.getFloatValue(0);
  296. F32 curveEnd = input.getFloatValue(input.size()-1);
  297. t = mClampF(t, curveStart, curveEnd);
  298. // find the index of the input keyframe BEFORE 't'
  299. S32 index;
  300. for (index = 0; index < input.size()-2; index++) {
  301. if (input.getFloatValue(index + 1) > t)
  302. break;
  303. }
  304. // get the data for the two control points either side of 't'
  305. Point2F v0;
  306. v0.x = input.getFloatValue(index);
  307. v0.y = output.getStringArrayData(index)[offset];
  308. Point2F v3;
  309. v3.x = input.getFloatValue(index + 1);
  310. v3.y = output.getStringArrayData(index + 1)[offset];
  311. // If spline interpolation is specified but the tangents are not available,
  312. // default to LINEAR.
  313. const char* interp_method = interpolation.getStringValue(index);
  314. if (dStrEqual(interp_method, "BEZIER") ||
  315. dStrEqual(interp_method, "HERMITE") ||
  316. dStrEqual(interp_method, "CARDINAL")) {
  317. const double* inArray = inTangent.getStringArrayData(index + 1);
  318. const double* outArray = outTangent.getStringArrayData(index);
  319. if (!inArray || !outArray)
  320. interp_method = "LINEAR";
  321. }
  322. if (dStrEqual(interp_method, "STEP")) {
  323. // STEP interpolation
  324. *value = v0.y;
  325. }
  326. else if (dStrEqual(interp_method, "BEZIER") ||
  327. dStrEqual(interp_method, "HERMITE") ||
  328. dStrEqual(interp_method, "CARDINAL") ||
  329. dStrEqual(interp_method, "BSPLINE"))
  330. {
  331. // Cubic spline interpolation. The only difference between the 4 supported
  332. // forms is in the calculation of the other 2 control points:
  333. // BEZIER: control points are specified explicitly
  334. // HERMITE: tangents are specified, need to offset to get the control points
  335. // CARDINAL: (baked) tangents are specified, need to offset to get the control points
  336. // BSPLINE: control points are based on previous and next points
  337. // Get the 2 extra control points
  338. Point2F v1, v2;
  339. if (dStrEqual(interp_method, "BSPLINE")) {
  340. // v0 and v3 are the center points => need to
  341. // get the control points before and after them
  342. v1 = v0;
  343. v2 = v3;
  344. if (index > 0) {
  345. v0.x = input.getFloatValue(index-1);
  346. v0.y = output.getStringArrayData(index-1)[offset];
  347. }
  348. else {
  349. // mirror P1 through P0
  350. v0 = v1 + (v1 - v2);
  351. }
  352. if (index < (input.size()-2)) {
  353. v3.x = input.getFloatValue(index+2);
  354. v3.y = output.getStringArrayData(index+2)[offset];
  355. }
  356. else {
  357. // mirror P0 through P1
  358. v3 = v2 + (v2 - v1);
  359. }
  360. }
  361. else {
  362. const double* inArray = inTangent.getStringArrayData(index + 1);
  363. const double* outArray = outTangent.getStringArrayData(index);
  364. if (output.stride() == inTangent.stride()) {
  365. // This degenerate form (1D control points) does 2 things wrong:
  366. // 1) it does not specify the key (time) value
  367. // 2) the control point is specified as a tangent for both bezier and hermite
  368. // => interpolate to get the key values, and offset the tangent values
  369. v1.set((v0.x*2 + v3.x)/3, v0.y + outArray[offset]);
  370. v2.set((v0.x + v3.x*2)/3, v3.y - inArray[offset]);
  371. }
  372. else {
  373. // the expected form (2D control points)
  374. v1.set(outArray[offset*2], outArray[offset*2+1]);
  375. v2.set(inArray[offset*2], inArray[offset*2+1]);
  376. // if this is a hermite or cardinal spline, treat the values as tangents
  377. if (dStrEqual(interp_method, "HERMITE") || dStrEqual(interp_method, "CARDINAL")) {
  378. v1.set(v0.x + v1.x, v3.y - v1.y);
  379. v2.set(v0.x + v2.x, v3.x - v2.y);
  380. }
  381. }
  382. }
  383. // find 's' that gives the desired 't' value
  384. F32 s = invertParamCubic(t, v0.x, v1.x, v2.x, v3.x);
  385. // Calculate the output value using Bernstein evaluation and the
  386. // computed 's' value
  387. F32 c = 3.0f*(v1.y - v0.y);
  388. F32 e = 3.0f*(v2.y - v1.y);
  389. *value = (((v3.y - v0.y - e)*s + e - c)*s + c)*s + v0.y;
  390. }
  391. else {
  392. // default to LINEAR interpolation
  393. F32 s = mClampF((t - v0.x) / (v3.x - v0.x), 0.0f, 1.0f);
  394. *value = v0.y + (v3.y - v0.y) * s;
  395. }
  396. }
  397. void AnimData::interpValue(F32 t, U32 offset, const char** value) const
  398. {
  399. if (input.size() == 0)
  400. *value = "";
  401. else if (input.size() == 1)
  402. *value = output.getStringValue(0);
  403. else
  404. {
  405. // clamp time to valid range
  406. F32 curveStart = input.getFloatValue(0);
  407. F32 curveEnd = input.getFloatValue(input.size()-1);
  408. t = mClampF(t, curveStart, curveEnd);
  409. // find the index of the input keyframe BEFORE 't'
  410. S32 index;
  411. for (index = 0; index < input.size()-2; index++) {
  412. if (input.getFloatValue(index + 1) > t)
  413. break;
  414. }
  415. // String values only support STEP interpolation, so just get the
  416. // value at the input keyframe
  417. *value = output.getStringValue(index);
  418. }
  419. }
  420. //------------------------------------------------------------------------------
  421. // Collada document conditioners
  422. static void conditioner_fixupTextureSIDs(domCOLLADA* root)
  423. {
  424. for (S32 iLib = 0; iLib < root->getLibrary_effects_array().getCount(); iLib++) {
  425. domLibrary_effects* lib = root->getLibrary_effects_array()[iLib];
  426. for (S32 iEffect = 0; iEffect < lib->getEffect_array().getCount(); iEffect++) {
  427. domEffect* effect = lib->getEffect_array()[iEffect];
  428. const domCommon_color_or_texture_type_complexType* diffuse = findEffectDiffuse(effect);
  429. if (!diffuse || !diffuse->getTexture())
  430. continue;
  431. // Resolve the SID => if it is an <image>, add <sampler2D> and
  432. // <surface> elements to conform to the Collada spec.
  433. const char *image_sid = diffuse->getTexture()->getTexture();
  434. daeSIDResolver resolver(effect, image_sid);
  435. if (!daeSafeCast<domImage>(resolver.getElement()))
  436. continue;
  437. daeErrorHandler::get()->handleWarning(avar("Fixup %s <diffuse>.<texture> "
  438. "pointing at <image> instead of <sampler2D>", effect->getID()));
  439. // Generate SIDs for the new sampler2D and surface elements
  440. std::string sampler_sid(std::string(image_sid) + "-sampler");
  441. std::string surface_sid(std::string(image_sid) + "-surface");
  442. domProfile_COMMON* profile = const_cast<domProfile_COMMON*>(findEffectCommonProfile(effect));
  443. // Create <newparam>.<sampler2D>.<source>
  444. {
  445. CREATE_ELEMENT(profile, newparam, domCommon_newparam_type)
  446. CREATE_ELEMENT(newparam, sampler2D, domFx_sampler2D_common)
  447. CREATE_ELEMENT(sampler2D, source, domFx_sampler2D_common_complexType::domSource)
  448. newparam->setSid(sampler_sid.c_str());
  449. source->setValue(surface_sid.c_str());
  450. }
  451. // Create <newparam>.<surface>.<init_from>
  452. {
  453. CREATE_ELEMENT(profile, newparam, domCommon_newparam_type)
  454. CREATE_ELEMENT(newparam, surface, domFx_surface_common)
  455. CREATE_ELEMENT(surface, init_from, domFx_surface_init_from_common)
  456. CREATE_ELEMENT(surface, format, domFx_surface_common_complexType::domFormat)
  457. newparam->setSid(surface_sid.c_str());
  458. surface->setType(FX_SURFACE_TYPE_ENUM_2D);
  459. format->setValue("A8R8G8B8");
  460. init_from->setValue(image_sid);
  461. }
  462. // Store sampler2D sid in the <diffuse>.<texture> "texture" attribute
  463. diffuse->getTexture()->setTexture(sampler_sid.c_str());
  464. }
  465. }
  466. }
  467. static void conditioner_fixupImageURIs(domCOLLADA* root)
  468. {
  469. for (S32 iLib = 0; iLib < root->getLibrary_images_array().getCount(); iLib++) {
  470. domLibrary_images* lib = root->getLibrary_images_array()[iLib];
  471. for (S32 iImage = 0; iImage < lib->getImage_array().getCount(); iImage++) {
  472. domImage* image = lib->getImage_array()[iImage];
  473. if (image->getInit_from()) {
  474. xsAnyURI& uri = image->getInit_from()->getValue();
  475. // Replace '\' with '/'
  476. if (uri.originalStr().find("\\") != std::string::npos) {
  477. daeErrorHandler::get()->handleWarning(avar("Fixup invalid URI "
  478. "in %s: \"%s\"", image->getID(), uri.originalStr().c_str()));
  479. std::string str(uri.originalStr());
  480. std::replace(str.begin(), str.end(), '\\', '/');
  481. uri.set(str);
  482. }
  483. // Detect file://texture.jpg => this is an invalid URI and will
  484. // not be parsed correctly
  485. if (uri.scheme() == "file" &&
  486. uri.pathFile().empty() &&
  487. !uri.authority().empty()) {
  488. daeErrorHandler::get()->handleWarning(avar("Fixup invalid URI "
  489. "in %s: \"%s\"", image->getID(), uri.originalStr().c_str()));
  490. uri.set(uri.authority());
  491. }
  492. }
  493. }
  494. }
  495. }
  496. static void conditioner_fixupTransparency(domCOLLADA* root)
  497. {
  498. // Transparency is another example of something simple made complicated by
  499. // Collada. There are two (optional) elements that determine transparency:
  500. //
  501. // <transparent>: a color
  502. // <transparency>: a percentage applied to the color values
  503. //
  504. // Additionally, <transparent> has an optional "opaque" attribute that changes
  505. // the way transparency is determined. If set to A_ONE (the default), only the
  506. // alpha value of the transparent color is used, and a value of "1" means fully
  507. // opaque. If set to RGB_ZERO, only the RGB values of transparent are used, and
  508. // a value of "0" means fully opaque.
  509. //
  510. // To further complicate matters, Google Sketchup (all versions) and FeelingSoftware
  511. // ColladaMax (pre 3.03) export materials with the transparency element inverted
  512. // (1-transparency)
  513. // Get the <authoring_tool> string
  514. const char *authoringTool = "";
  515. if (const domAsset* asset = root->getAsset()) {
  516. for (S32 iContrib = 0; iContrib < asset->getContributor_array().getCount(); iContrib++) {
  517. const domAsset::domContributor* contrib = asset->getContributor_array()[iContrib];
  518. if (contrib->getAuthoring_tool()) {
  519. authoringTool = contrib->getAuthoring_tool()->getValue();
  520. break;
  521. }
  522. }
  523. }
  524. // Check for a match with the known problem-tools
  525. bool invertTransparency = false;
  526. const char *toolNames[] = { "FBX COLLADA exporter", "Google SketchUp",
  527. "Illusoft Collada Exporter", "FCollada" };
  528. for (S32 iName = 0; iName < (sizeof(toolNames)/sizeof(toolNames[0])); iName++) {
  529. if (dStrstr(authoringTool, toolNames[iName])) {
  530. invertTransparency = true;
  531. break;
  532. }
  533. }
  534. if (!invertTransparency)
  535. return;
  536. // Invert transparency as required for each effect
  537. for (S32 iLib = 0; iLib < root->getLibrary_effects_array().getCount(); iLib++) {
  538. domLibrary_effects* lib = root->getLibrary_effects_array()[iLib];
  539. for (S32 iEffect = 0; iEffect < lib->getEffect_array().getCount(); iEffect++) {
  540. domEffect* effect = lib->getEffect_array()[iEffect];
  541. // Find the common profile
  542. const domProfile_COMMON* commonProfile = findEffectCommonProfile(effect);
  543. if (!commonProfile)
  544. continue;
  545. domCommon_transparent_type* transparent = 0;
  546. if (commonProfile->getTechnique()->getConstant())
  547. transparent = commonProfile->getTechnique()->getConstant()->getTransparent();
  548. else if (commonProfile->getTechnique()->getLambert())
  549. transparent = commonProfile->getTechnique()->getLambert()->getTransparent();
  550. else if (commonProfile->getTechnique()->getPhong())
  551. transparent = commonProfile->getTechnique()->getPhong()->getTransparent();
  552. else if (commonProfile->getTechnique()->getBlinn())
  553. transparent = commonProfile->getTechnique()->getBlinn()->getTransparent();
  554. if (!transparent)
  555. continue;
  556. // If the shader "opaque" attribute is not specified, set it to
  557. // RGB_ZERO (the opposite of the Collada default), as this is what
  558. // the bad exporter tools seem to assume.
  559. if (!transparent->isAttributeSet("opaque")) {
  560. daeErrorHandler::get()->handleWarning(avar("Setting <transparent> "
  561. "\"opaque\" attribute to RGB_ZERO for %s <effect>", effect->getID()));
  562. transparent->setOpaque(FX_OPAQUE_ENUM_RGB_ZERO);
  563. }
  564. }
  565. }
  566. }
  567. static void conditioner_checkBindShapeMatrix(domCOLLADA* root)
  568. {
  569. for (S32 iLib = 0; iLib < root->getLibrary_controllers_array().getCount(); iLib++) {
  570. domLibrary_controllers* lib = root->getLibrary_controllers_array().get(iLib);
  571. for (S32 iCon = 0; iCon < lib->getController_array().getCount(); iCon++) {
  572. domController* con = lib->getController_array().get(iCon);
  573. if (con->getSkin() && con->getSkin()->getBind_shape_matrix()) {
  574. MatrixF mat = vecToMatrixF<domMatrix>(con->getSkin()->getBind_shape_matrix()->getValue());
  575. if (!mat.fullInverse()) {
  576. daeErrorHandler::get()->handleWarning(avar("<bind_shape_matrix> "
  577. "in %s <controller> is not invertible (may cause problems with "
  578. "skinning)", con->getID()));
  579. }
  580. }
  581. }
  582. }
  583. }
  584. static void conditioner_fixupVertexWeightJoints(domCOLLADA* root)
  585. {
  586. for (S32 iLib = 0; iLib < root->getLibrary_controllers_array().getCount(); iLib++) {
  587. domLibrary_controllers* lib = root->getLibrary_controllers_array().get(iLib);
  588. for (S32 iCon = 0; iCon < lib->getController_array().getCount(); iCon++) {
  589. domController* con = lib->getController_array().get(iCon);
  590. if (con->getSkin() && con->getSkin()->getVertex_weights())
  591. {
  592. domInputLocalOffset_Array& vw_inputs = con->getSkin()->getVertex_weights()->getInput_array();
  593. for (S32 vInput = 0; vInput < vw_inputs.getCount(); vInput++) {
  594. domInputLocalOffset *vw_input = vw_inputs.get(vInput);
  595. if (dStrEqual(vw_input->getSemantic(), "JOINT")) {
  596. // Check if this input points at a float array (bad)
  597. domSource* vw_source = daeSafeCast<domSource>(vw_input->getSource().getElement());
  598. if (vw_source->getFloat_array()) {
  599. // Copy the value from the <joints> JOINTS input instead
  600. domInputLocal_Array& joint_inputs = con->getSkin()->getJoints()->getInput_array();
  601. for (S32 jInput = 0; jInput < joint_inputs.getCount(); jInput++) {
  602. domInputLocal *joint_input = joint_inputs.get(jInput);
  603. if (dStrEqual(joint_input->getSemantic(), "JOINT")) {
  604. vw_input->setSource(joint_input->getSource());
  605. break;
  606. }
  607. }
  608. }
  609. }
  610. }
  611. }
  612. }
  613. }
  614. }
  615. static void conditioner_createDefaultClip(domCOLLADA* root)
  616. {
  617. // Check if the document has any <animation_clip>s
  618. for (S32 iLib = 0; iLib < root->getLibrary_animation_clips_array().getCount(); iLib++) {
  619. if (root->getLibrary_animation_clips_array()[iLib]->getAnimation_clip_array().getCount())
  620. return;
  621. }
  622. // Get all top-level <animation>s into an array
  623. domAnimation_Array animations;
  624. for (S32 iAnimLib = 0; iAnimLib < root->getLibrary_animations_array().getCount(); iAnimLib++) {
  625. const domLibrary_animations* libraryAnims = root->getLibrary_animations_array()[iAnimLib];
  626. for (S32 iAnim = 0; iAnim < libraryAnims->getAnimation_array().getCount(); iAnim++)
  627. animations.append(libraryAnims->getAnimation_array()[iAnim]);
  628. }
  629. if (!animations.getCount())
  630. return;
  631. daeErrorHandler::get()->handleWarning("Creating cyclic animation clip to "
  632. "hold all animations");
  633. // Get animation_clip library (create one if necessary)
  634. if (!root->getLibrary_animation_clips_array().getCount()) {
  635. root->createAndPlace("library_animation_clips");
  636. }
  637. domLibrary_animation_clips* libraryClips = root->getLibrary_animation_clips_array()[0];
  638. // Create new animation_clip for the default sequence
  639. CREATE_ELEMENT(libraryClips, animation_clip, domAnimation_clip)
  640. animation_clip->setName("ambient");
  641. animation_clip->setId("dummy_ambient_clip");
  642. animation_clip->setStart(0);
  643. animation_clip->setEnd(0);
  644. // Add all top_level animations to the clip (sub-animations will be included
  645. // when the clip is procesed)
  646. for (S32 iAnim = 0; iAnim < animations.getCount(); iAnim++) {
  647. if (!animations[iAnim]->getId())
  648. animations[iAnim]->setId(avar("dummy-animation-id%d", iAnim));
  649. CREATE_ELEMENT(animation_clip, instance_animation, domInstanceWithExtra)
  650. std::string url(std::string("#") + animations[iAnim]->getId());
  651. instance_animation->setUrl(url.c_str());
  652. }
  653. // Add the 'Torque' profile to specify the 'Cyclic' flag
  654. CREATE_ELEMENT(animation_clip, extra, domExtra)
  655. CREATE_ELEMENT(extra, technique, domTechnique)
  656. CREATE_ELEMENT(technique, any, domAny)
  657. technique->setProfile("Torque");
  658. any->setElementName("cyclic");
  659. any->setValue("1");
  660. }
  661. static void conditioner_fixupAnimation(domAnimation* anim)
  662. {
  663. S32 visibilityLen = dStrlen("/visibility");
  664. for (S32 iChannel = 0; iChannel < anim->getChannel_array().getCount(); iChannel++) {
  665. // Get the animation elements: <channel>, <sampler>
  666. domChannel* channel = anim->getChannel_array()[iChannel];
  667. domSampler* sampler = daeSafeCast<domSampler>(channel->getSource().getElement());
  668. if (!sampler)
  669. continue;
  670. /*
  671. // If using a spline interpolation type but no tangents are specified,
  672. // fall back to LINEAR interpolation.
  673. bool isSpline = false;
  674. bool foundInTangent = false;
  675. bool foundOutTangent = false;
  676. for (int iInput = 0; iInput < sampler->getInput_array().getCount(); iInput++) {
  677. const char *semantic = sampler->getInput_array()[iInput]->getSemantic();
  678. if (dStrEqual(semantic, "INTERPOLATION")) {
  679. if (
  680. }
  681. if (dStrEqual(semantic, "IN_TANGENT"))
  682. foundInTangent = true;
  683. if (dStrEqual(semantic, "OUT_TANGENT"))
  684. foundOutTangent = true;
  685. }
  686. if (isSpline && (!foundInTangent || !foundOutTangent)) {
  687. daeErrorHandler::get()->handleWarning(avar("%s type interpolation "
  688. "specified for %s, but IN/OUT TANGENTS are not provided. Using "
  689. "LINEAR interpolation instead.");
  690. }
  691. */
  692. // Find the animation channel target
  693. daeSIDResolver resolver(channel, channel->getTarget());
  694. daeElement* target = resolver.getElement();
  695. if (!target) {
  696. // Some exporters generate visibility animations but don't add the
  697. // FCOLLADA extension, so the target doesn't actually exist! Detect
  698. // this situation and add the extension manually so the animation
  699. // still works.
  700. if (dStrEndsWith(channel->getTarget(), "/visibility")) {
  701. // Get parent SID string
  702. char *parentSID = dStrdup(channel->getTarget());
  703. parentSID[dStrlen(parentSID) - visibilityLen] = '\0';
  704. // Find the parent element (should be a <node>)
  705. daeSIDResolver parentResolver(channel, parentSID);
  706. daeElement* parent = parentResolver.getElement();
  707. delete [] parentSID;
  708. if (parent && (parent->getElementType() == COLLADA_TYPE::NODE)) {
  709. // Create the FCOLLADA extension
  710. daeErrorHandler::get()->handleWarning(avar("Creating missing "
  711. "visibility animation target: %s", channel->getTarget()));
  712. // Check if the <visibility> element exists but is missing the SID
  713. daeElement* vis = parent->getDescendant("visibility");
  714. if (vis)
  715. {
  716. vis->setAttribute("sid", "visibility");
  717. }
  718. else
  719. {
  720. CREATE_ELEMENT(parent, extra, domExtra)
  721. CREATE_ELEMENT(extra, technique, domTechnique)
  722. CREATE_ELEMENT(technique, any, domAny)
  723. technique->setProfile("FCOLLADA");
  724. any->setElementName("visibility");
  725. any->setAttribute("sid", "visibility");
  726. any->setValue(""); // real initial value will be set when animation is processed in ColladaShapeLoader::processAnimation
  727. }
  728. }
  729. }
  730. }
  731. }
  732. // Process child animations
  733. for (S32 iAnim = 0; iAnim < anim->getAnimation_array().getCount(); iAnim++)
  734. conditioner_fixupAnimation(anim->getAnimation_array()[iAnim]);
  735. }
  736. /// Apply the set of model conditioners
  737. void ColladaUtils::applyConditioners(domCOLLADA* root)
  738. {
  739. //--------------------------------------------------------------------------
  740. // The built-in MAX FBX exporter specifies an <image> SID in the <texture>
  741. // "texture" attribute instead of a <newparam> SID. Detect and fix this.
  742. conditioner_fixupTextureSIDs(root);
  743. //--------------------------------------------------------------------------
  744. // The built-in MAX FBX exporter also generates invalid URI paths in the
  745. // <image>.<init_from> tag, so fix that up too.
  746. conditioner_fixupImageURIs(root);
  747. //--------------------------------------------------------------------------
  748. // Many exporters get transparency backwards. Check if the model was exported
  749. // by one with a known issue and correct it.
  750. conditioner_fixupTransparency(root);
  751. //--------------------------------------------------------------------------
  752. // Some exporters (AutoDesk) generate invalid bind_shape matrices. Warn if
  753. // the bind_shape_matrix is not invertible.
  754. conditioner_checkBindShapeMatrix(root);
  755. //--------------------------------------------------------------------------
  756. // The PoserPro exporter points the <vertex_weights> JOINT input to the
  757. // inverse bind matrices instead of the joint names array. Detect and fix it.
  758. conditioner_fixupVertexWeightJoints(root);
  759. //--------------------------------------------------------------------------
  760. // If the model contains <animation>s but no <animation_clip>s, just put all
  761. // top level animations into a single clip.
  762. conditioner_createDefaultClip(root);
  763. //--------------------------------------------------------------------------
  764. // Apply some animation fixups:
  765. // 1) Some exporters (eg. Blender) generate "BEZIER" type animation curves,
  766. // but do not specify the IN and OUT tangent data arrays. Detect this and
  767. // fall back to LINEAR interpolation.
  768. // 2) Some exporters generate visibility animations but don't add the FCOLLADA
  769. // extension, so the target doesn't actually exist! Detect this situation
  770. // and add the extension manually so the animation still works.
  771. for (S32 iLib = 0; iLib < root->getLibrary_animations_array().getCount(); iLib++) {
  772. const domLibrary_animations* lib = root->getLibrary_animations_array()[iLib];
  773. for (S32 iAnim = 0; iAnim < lib->getAnimation_array().getCount(); iAnim++)
  774. conditioner_fixupAnimation(lib->getAnimation_array()[iAnim]);
  775. }
  776. }
  777. Torque::Path ColladaUtils::findTexture(const Torque::Path& diffuseMap)
  778. {
  779. Vector<Torque::Path> foundPaths;
  780. GBitmap::sFindFiles(diffuseMap, &foundPaths);
  781. if (foundPaths.size() > 0)
  782. return Torque::Path(foundPaths[0]);
  783. // If unable to load texture in current directory
  784. // look in the parent directory. But never look in the root.
  785. Torque::Path newPath(diffuseMap);
  786. String filePath = newPath.getPath();
  787. String::SizeType slash = filePath.find('/', filePath.length(), String::Right);
  788. if (slash != String::NPos)
  789. {
  790. slash = filePath.find('/', filePath.length(), String::Right);
  791. if (slash != String::NPos)
  792. {
  793. String truncPath = filePath.substr(0, slash);
  794. newPath.setPath(truncPath);
  795. return findTexture(newPath);
  796. }
  797. }
  798. return String::EmptyString;
  799. }
  800. void ColladaUtils::exportColladaHeader(TiXmlElement* rootNode)
  801. {
  802. TiXmlElement* assetNode = new TiXmlElement("asset");
  803. rootNode->LinkEndChild(assetNode);
  804. TiXmlElement* contributorNode = new TiXmlElement("contributor");
  805. assetNode->LinkEndChild(contributorNode);
  806. TiXmlElement* authorNode = new TiXmlElement("author");
  807. contributorNode->LinkEndChild(authorNode);
  808. TiXmlText* authorNodeText = new TiXmlText("Torque3D MIT User");
  809. authorNode->LinkEndChild(authorNodeText);
  810. TiXmlElement* authoringToolNode = new TiXmlElement("authoring_tool");
  811. contributorNode->LinkEndChild(authoringToolNode);
  812. TiXmlText* authorText = new TiXmlText(avar("%s %s Object Exporter", getEngineProductString(), getVersionString()));
  813. authoringToolNode->LinkEndChild(authorText);
  814. //TiXmlElement* commentsNode = new TiXmlElement("comments");
  815. //contributorNode->LinkEndChild(commentsNode);
  816. // Get the current time
  817. Platform::LocalTime lt;
  818. Platform::getLocalTime(lt);
  819. String localTime = Platform::localTimeToString(lt);
  820. localTime.replace('\t', ' ');
  821. TiXmlElement* createdNode = new TiXmlElement("created");
  822. assetNode->LinkEndChild(createdNode);
  823. TiXmlText* createdText = new TiXmlText(avar("%s", localTime.c_str()));
  824. createdNode->LinkEndChild(createdText);
  825. TiXmlElement* modifiedNode = new TiXmlElement("modified");
  826. assetNode->LinkEndChild(modifiedNode);
  827. TiXmlText* modifiedText = new TiXmlText(avar("%s", localTime.c_str()));
  828. modifiedNode->LinkEndChild(modifiedText);
  829. //TiXmlElement* revisionNode = new TiXmlElement("revision");
  830. //assetNode->LinkEndChild(revisionNode);
  831. //TiXmlElement* titleNode = new TiXmlElement("title");
  832. //assetNode->LinkEndChild(titleNode);
  833. //TiXmlElement* subjectNode = new TiXmlElement("subject");
  834. //assetNode->LinkEndChild(subjectNode);
  835. //TiXmlElement* keywordsNode = new TiXmlElement("keywords");
  836. //assetNode->LinkEndChild(keywordsNode);
  837. // Torque uses Z_UP with 1 unit equal to 1 meter by default
  838. TiXmlElement* unitNode = new TiXmlElement("unit");
  839. assetNode->LinkEndChild(unitNode);
  840. unitNode->SetAttribute("name", "meter");
  841. unitNode->SetAttribute("meter", "1");
  842. TiXmlElement* axisNode = new TiXmlElement("up_axis");
  843. assetNode->LinkEndChild(axisNode);
  844. TiXmlText* axisText = new TiXmlText("Z_UP");
  845. axisNode->LinkEndChild(axisText);
  846. }
  847. void ColladaUtils::exportColladaMaterials(TiXmlElement* rootNode, const OptimizedPolyList& mesh, Vector<String>& matNames, const Torque::Path& colladaFile)
  848. {
  849. // First the image library
  850. TiXmlElement* imgLibNode = new TiXmlElement("library_images");
  851. rootNode->LinkEndChild(imgLibNode);
  852. for (U32 i = 0; i < mesh.mMaterialList.size(); i++)
  853. {
  854. BaseMatInstance* baseInst = mesh.mMaterialList[i];
  855. matNames.push_back(String::ToString("Material%d", i));
  856. Material* mat = dynamic_cast<Material*>(baseInst->getMaterial());
  857. if (!mat)
  858. continue;
  859. String diffuseMap;
  860. if (mat->getName() && mat->getName()[0])
  861. matNames.last() = mat->mMapTo;
  862. // Handle an auto-generated "Default Material" specially
  863. if (mat->isAutoGenerated())
  864. {
  865. Torque::Path diffusePath;
  866. if (mat->mDiffuseMapFilename[0].isNotEmpty())
  867. diffusePath = mat->mDiffuseMapFilename[0];
  868. else
  869. diffusePath = String("warningMat");
  870. matNames.last() = diffusePath.getFileName();
  871. diffuseMap += diffusePath.getFullFileName();
  872. }
  873. else
  874. {
  875. if (mat->mDiffuseMapFilename[0].isNotEmpty())
  876. diffuseMap += mat->mDiffuseMapFilename[0];
  877. else
  878. diffuseMap += "warningMat";
  879. }
  880. Torque::Path diffusePath = findTexture(colladaFile.getPath() + "/" + diffuseMap);
  881. // If we didn't get a path
  882. if (diffusePath.getFullPath().isNotEmpty())
  883. diffuseMap = Torque::Path::MakeRelativePath(diffusePath, colladaFile);
  884. TiXmlElement* imageNode = new TiXmlElement("image");
  885. imgLibNode->LinkEndChild(imageNode);
  886. imageNode->SetAttribute("id", avar("%s", matNames.last().c_str()));
  887. imageNode->SetAttribute("name", avar("%s", matNames.last().c_str()));
  888. TiXmlElement* initNode = new TiXmlElement("init_from");
  889. imageNode->LinkEndChild(initNode);
  890. TiXmlText* initText = new TiXmlText(avar("file://%s", diffuseMap.c_str())); // "the file://" is needed to load the texture in some old apps (ex: 3ds Max 2009)
  891. initNode->LinkEndChild(initText);
  892. }
  893. // Next the effects library
  894. TiXmlElement* effectLibNode = new TiXmlElement("library_effects");
  895. rootNode->LinkEndChild(effectLibNode);
  896. for (U32 i = 0; i < mesh.mMaterialList.size(); i++)
  897. {
  898. BaseMatInstance* baseInst = mesh.mMaterialList[i];
  899. Material* mat = dynamic_cast<Material*>(baseInst->getMaterial());
  900. if (!mat)
  901. continue;
  902. TiXmlElement* effectNode = new TiXmlElement("effect");
  903. effectLibNode->LinkEndChild(effectNode);
  904. effectNode->SetAttribute("id", avar("%s-effect", matNames[i].c_str()));
  905. effectNode->SetAttribute("name", avar("%s-effect", matNames[i].c_str()));
  906. TiXmlElement* profileNode = new TiXmlElement("profile_COMMON");
  907. effectNode->LinkEndChild(profileNode);
  908. // ---------------------------
  909. TiXmlElement* newParamNode = new TiXmlElement("newparam");
  910. profileNode->LinkEndChild(newParamNode);
  911. newParamNode->SetAttribute("sid", avar("%s-surface", matNames[i].c_str()));
  912. TiXmlElement* surfaceNode = new TiXmlElement("surface");
  913. newParamNode->LinkEndChild(surfaceNode);
  914. surfaceNode->SetAttribute("type", "2D");
  915. TiXmlElement* initNode2 = new TiXmlElement("init_from");
  916. surfaceNode->LinkEndChild(initNode2);
  917. TiXmlText* init2Text = new TiXmlText(avar("%s", matNames[i].c_str()));
  918. initNode2->LinkEndChild(init2Text);
  919. TiXmlElement* formatNode = new TiXmlElement("format");
  920. surfaceNode->LinkEndChild(formatNode);
  921. TiXmlText* formatText = new TiXmlText("A8R8G8B8");
  922. formatNode->LinkEndChild(formatText);
  923. // ---------------------------
  924. TiXmlElement* newParam2Node = new TiXmlElement("newparam");
  925. profileNode->LinkEndChild(newParam2Node);
  926. newParam2Node->SetAttribute("sid", avar("%s-sampler", matNames[i].c_str()));
  927. TiXmlElement* sampler2DNode = new TiXmlElement("sampler2D");
  928. newParam2Node->LinkEndChild(sampler2DNode);
  929. TiXmlElement* sourceSampler2DNode = new TiXmlElement("source");
  930. sampler2DNode->LinkEndChild(sourceSampler2DNode);
  931. TiXmlText* sourceSampler2DText = new TiXmlText(avar("%s-surface", matNames[i].c_str()));
  932. sourceSampler2DNode->LinkEndChild(sourceSampler2DText);
  933. // ---------------------------
  934. TiXmlElement* techniqueNode = new TiXmlElement("technique");
  935. profileNode->LinkEndChild(techniqueNode);
  936. techniqueNode->SetAttribute("sid", "common");
  937. TiXmlElement* blinnNode = new TiXmlElement("blinn");
  938. techniqueNode->LinkEndChild(blinnNode);
  939. // ---------------------------
  940. TiXmlElement* emissionNode = new TiXmlElement("emission");
  941. blinnNode->LinkEndChild(emissionNode);
  942. TiXmlElement* colorEmissionNode = new TiXmlElement("color");
  943. emissionNode->LinkEndChild(colorEmissionNode);
  944. colorEmissionNode->SetAttribute("sid", "emission");
  945. TiXmlText* colorEmissionNodeText = new TiXmlText("0.0 0.0 0.0 1.0");
  946. colorEmissionNode->LinkEndChild(colorEmissionNodeText);
  947. // ---------------------------
  948. TiXmlElement* ambientNode = new TiXmlElement("ambient");
  949. blinnNode->LinkEndChild(ambientNode);
  950. TiXmlElement* colorAmbientNode = new TiXmlElement("color");
  951. ambientNode->LinkEndChild(colorAmbientNode);
  952. colorAmbientNode->SetAttribute("sid", "ambient");
  953. TiXmlText* colorAmbientNodeText = new TiXmlText("0.0 0.0 0.0 1.0");
  954. colorAmbientNode->LinkEndChild(colorAmbientNodeText);
  955. // ---------------------------
  956. TiXmlElement* diffuseNode = new TiXmlElement("diffuse");
  957. blinnNode->LinkEndChild(diffuseNode);
  958. TiXmlElement* textureDiffuseNode = new TiXmlElement("texture");
  959. diffuseNode->LinkEndChild(textureDiffuseNode);
  960. textureDiffuseNode->SetAttribute("texture", avar("%s-sampler", matNames[i].c_str()));
  961. textureDiffuseNode->SetAttribute("texcoord", "UVMap");
  962. // Extra info useful for getting the texture to show up correctly in MAYA and 3DS Max
  963. TiXmlElement* extraNode = new TiXmlElement("extra");
  964. textureDiffuseNode->LinkEndChild(extraNode);
  965. TiXmlElement* extraTechNode = new TiXmlElement("technique");
  966. extraNode->LinkEndChild(extraTechNode);
  967. extraTechNode->SetAttribute("profile", "MAYA");
  968. TiXmlElement* extraWrapUNode = new TiXmlElement("wrapU");
  969. extraTechNode->LinkEndChild(extraWrapUNode);
  970. extraWrapUNode->SetAttribute("sid", "wrapU0");
  971. TiXmlText* extraWrapUText = new TiXmlText("TRUE");
  972. extraWrapUNode->LinkEndChild(extraWrapUText);
  973. TiXmlElement* extraWrapVNode = new TiXmlElement("wrapV");
  974. extraTechNode->LinkEndChild(extraWrapVNode);
  975. extraWrapVNode->SetAttribute("sid", "wrapV0");
  976. TiXmlText* extraWrapVText = new TiXmlText("TRUE");
  977. extraWrapVNode->LinkEndChild(extraWrapVText);
  978. TiXmlElement* extraBlendNode = new TiXmlElement("blend_mode");
  979. extraTechNode->LinkEndChild(extraBlendNode);
  980. TiXmlText* extraBlendText = new TiXmlText("ADD");
  981. extraBlendNode->LinkEndChild(extraBlendText);
  982. // ---------------------------
  983. TiXmlElement* specularNode = new TiXmlElement("specular");
  984. blinnNode->LinkEndChild(specularNode);
  985. TiXmlElement* colorSpecularNode = new TiXmlElement("color");
  986. specularNode->LinkEndChild(colorSpecularNode);
  987. colorSpecularNode->SetAttribute("sid", "specular");
  988. TiXmlText* colorSpecularNodeText = new TiXmlText("0.5 0.5 0.5 1.0");
  989. colorSpecularNode->LinkEndChild(colorSpecularNodeText);
  990. // ---------------------------
  991. TiXmlElement* shininessNode = new TiXmlElement("shininess");
  992. blinnNode->LinkEndChild(shininessNode);
  993. TiXmlElement* colorShininessNode = new TiXmlElement("float");
  994. shininessNode->LinkEndChild(colorShininessNode);
  995. colorShininessNode->SetAttribute("sid", "shininess");
  996. TiXmlText* colorShininessNodeText = new TiXmlText("1.0");
  997. colorShininessNode->LinkEndChild(colorShininessNodeText);
  998. // ---------------------------
  999. TiXmlElement* reflectiveNode = new TiXmlElement("reflective");
  1000. blinnNode->LinkEndChild(reflectiveNode);
  1001. TiXmlElement* colorReflectiveNode = new TiXmlElement("color");
  1002. reflectiveNode->LinkEndChild(colorReflectiveNode);
  1003. colorReflectiveNode->SetAttribute("sid", "reflective");
  1004. TiXmlText* colorReflectiveNodeText = new TiXmlText("0.0 0.0 0.0 1.0");
  1005. colorReflectiveNode->LinkEndChild(colorReflectiveNodeText);
  1006. // ---------------------------
  1007. TiXmlElement* reflectivityNode = new TiXmlElement("reflectivity");
  1008. blinnNode->LinkEndChild(reflectivityNode);
  1009. TiXmlElement* floatReflectivityNode = new TiXmlElement("float");
  1010. reflectivityNode->LinkEndChild(floatReflectivityNode);
  1011. floatReflectivityNode->SetAttribute("sid", "reflectivity");
  1012. TiXmlText* floatReflectivityText = new TiXmlText("0.5");
  1013. floatReflectivityNode->LinkEndChild(floatReflectivityText);
  1014. // ---------------------------
  1015. TiXmlElement* transparentNode = new TiXmlElement("transparent");
  1016. blinnNode->LinkEndChild(transparentNode);
  1017. transparentNode->SetAttribute("opaque", "RGB_ZERO");
  1018. TiXmlElement* colorTransparentNode = new TiXmlElement("color");
  1019. transparentNode->LinkEndChild(colorTransparentNode);
  1020. colorTransparentNode->SetAttribute("sid", "transparent");
  1021. TiXmlText* colorTransparentNodeText = new TiXmlText("0.0 0.0 0.0 1.0");
  1022. colorTransparentNode->LinkEndChild(colorTransparentNodeText);
  1023. // ---------------------------
  1024. TiXmlElement* transparencyNode = new TiXmlElement("transparency");
  1025. blinnNode->LinkEndChild(transparencyNode);
  1026. TiXmlElement* floatTransparencyNode = new TiXmlElement("float");
  1027. transparencyNode->LinkEndChild(floatTransparencyNode);
  1028. floatTransparencyNode->SetAttribute("sid", "transparency");
  1029. TiXmlText* floatTransparencyText = new TiXmlText("0.0");
  1030. floatTransparencyNode->LinkEndChild(floatTransparencyText);
  1031. // ---------------------------
  1032. TiXmlElement* refractionNode = new TiXmlElement("index_of_refraction");
  1033. blinnNode->LinkEndChild(refractionNode);
  1034. TiXmlElement* colorRefractionNode = new TiXmlElement("float");
  1035. refractionNode->LinkEndChild(colorRefractionNode);
  1036. colorRefractionNode->SetAttribute("sid", "index_of_refraction");
  1037. TiXmlText* colorRefractionNodeText = new TiXmlText("1");
  1038. colorRefractionNode->LinkEndChild(colorRefractionNodeText);
  1039. }
  1040. // Finally the material library
  1041. TiXmlElement* matLibNode = new TiXmlElement("library_materials");
  1042. rootNode->LinkEndChild(matLibNode);
  1043. for (U32 i = 0; i < mesh.mMaterialList.size(); i++)
  1044. {
  1045. BaseMatInstance* baseInst = mesh.mMaterialList[i];
  1046. Material* mat = dynamic_cast<Material*>(baseInst->getMaterial());
  1047. if (!mat)
  1048. continue;
  1049. TiXmlElement* materialNode = new TiXmlElement("material");
  1050. matLibNode->LinkEndChild(materialNode);
  1051. materialNode->SetAttribute("id", avar("%s-material", matNames[i].c_str()));
  1052. materialNode->SetAttribute("name", matNames[i].c_str());
  1053. TiXmlElement* instEffectNode = new TiXmlElement("instance_effect");
  1054. materialNode->LinkEndChild(instEffectNode);
  1055. instEffectNode->SetAttribute("url", avar("#%s-effect", matNames[i].c_str()));
  1056. }
  1057. }
  1058. void ColladaUtils::exportColladaMaterials(TiXmlElement* rootNode, const ExportData& exportData, const Torque::Path& colladaFile)
  1059. {
  1060. // First the image library
  1061. TiXmlElement* imgLibNode = new TiXmlElement("library_images");
  1062. rootNode->LinkEndChild(imgLibNode);
  1063. Vector<String> matNames;
  1064. for (U32 i = 0; i < exportData.materials.size(); i++)
  1065. {
  1066. BaseMatInstance* baseInst = exportData.materials[i];
  1067. matNames.push_back(String::ToString("Material%d", i));
  1068. Material* mat = dynamic_cast<Material*>(baseInst->getMaterial());
  1069. if (!mat)
  1070. continue;
  1071. String diffuseMap;
  1072. if (mat->getName() && mat->getName()[0])
  1073. matNames.last() = mat->mMapTo;
  1074. // Handle an auto-generated "Default Material" specially
  1075. if (mat->isAutoGenerated())
  1076. {
  1077. Torque::Path diffusePath;
  1078. if (mat->mDiffuseMapFilename[0].isNotEmpty())
  1079. diffusePath = mat->mDiffuseMapFilename[0];
  1080. else
  1081. diffusePath = String("warningMat");
  1082. matNames.last() = diffusePath.getFileName();
  1083. diffuseMap += diffusePath.getFullFileName();
  1084. }
  1085. else
  1086. {
  1087. if (mat->mDiffuseMapFilename[0].isNotEmpty())
  1088. diffuseMap += mat->mDiffuseMapFilename[0];
  1089. else
  1090. diffuseMap += "warningMat";
  1091. }
  1092. Torque::Path diffusePath = findTexture(colladaFile.getPath() + "/" + diffuseMap);
  1093. // If we didn't get a path
  1094. if (diffusePath.getFullPath().isNotEmpty())
  1095. diffuseMap = Torque::Path::MakeRelativePath(diffusePath, colladaFile);
  1096. TiXmlElement* imageNode = new TiXmlElement("image");
  1097. imgLibNode->LinkEndChild(imageNode);
  1098. imageNode->SetAttribute("id", avar("%s", matNames.last().c_str()));
  1099. imageNode->SetAttribute("name", avar("%s", matNames.last().c_str()));
  1100. TiXmlElement* initNode = new TiXmlElement("init_from");
  1101. imageNode->LinkEndChild(initNode);
  1102. TiXmlText* initText = new TiXmlText(avar("file://%s", diffuseMap.c_str())); // "the file://" is needed to load the texture in some old apps (ex: 3ds Max 2009)
  1103. initNode->LinkEndChild(initText);
  1104. }
  1105. // Next the effects library
  1106. TiXmlElement* effectLibNode = new TiXmlElement("library_effects");
  1107. rootNode->LinkEndChild(effectLibNode);
  1108. for (U32 i = 0; i < exportData.materials.size(); i++)
  1109. {
  1110. BaseMatInstance* baseInst = exportData.materials[i];
  1111. Material* mat = dynamic_cast<Material*>(baseInst->getMaterial());
  1112. if (!mat)
  1113. continue;
  1114. TiXmlElement* effectNode = new TiXmlElement("effect");
  1115. effectLibNode->LinkEndChild(effectNode);
  1116. effectNode->SetAttribute("id", avar("%s-effect", matNames[i].c_str()));
  1117. effectNode->SetAttribute("name", avar("%s-effect", matNames[i].c_str()));
  1118. TiXmlElement* profileNode = new TiXmlElement("profile_COMMON");
  1119. effectNode->LinkEndChild(profileNode);
  1120. // ---------------------------
  1121. TiXmlElement* newParamNode = new TiXmlElement("newparam");
  1122. profileNode->LinkEndChild(newParamNode);
  1123. newParamNode->SetAttribute("sid", avar("%s-surface", matNames[i].c_str()));
  1124. TiXmlElement* surfaceNode = new TiXmlElement("surface");
  1125. newParamNode->LinkEndChild(surfaceNode);
  1126. surfaceNode->SetAttribute("type", "2D");
  1127. TiXmlElement* initNode2 = new TiXmlElement("init_from");
  1128. surfaceNode->LinkEndChild(initNode2);
  1129. TiXmlText* init2Text = new TiXmlText(avar("%s", matNames[i].c_str()));
  1130. initNode2->LinkEndChild(init2Text);
  1131. TiXmlElement* formatNode = new TiXmlElement("format");
  1132. surfaceNode->LinkEndChild(formatNode);
  1133. TiXmlText* formatText = new TiXmlText("A8R8G8B8");
  1134. formatNode->LinkEndChild(formatText);
  1135. // ---------------------------
  1136. TiXmlElement* newParam2Node = new TiXmlElement("newparam");
  1137. profileNode->LinkEndChild(newParam2Node);
  1138. newParam2Node->SetAttribute("sid", avar("%s-sampler", matNames[i].c_str()));
  1139. TiXmlElement* sampler2DNode = new TiXmlElement("sampler2D");
  1140. newParam2Node->LinkEndChild(sampler2DNode);
  1141. TiXmlElement* sourceSampler2DNode = new TiXmlElement("source");
  1142. sampler2DNode->LinkEndChild(sourceSampler2DNode);
  1143. TiXmlText* sourceSampler2DText = new TiXmlText(avar("%s-surface", matNames[i].c_str()));
  1144. sourceSampler2DNode->LinkEndChild(sourceSampler2DText);
  1145. // ---------------------------
  1146. TiXmlElement* techniqueNode = new TiXmlElement("technique");
  1147. profileNode->LinkEndChild(techniqueNode);
  1148. techniqueNode->SetAttribute("sid", "common");
  1149. TiXmlElement* blinnNode = new TiXmlElement("blinn");
  1150. techniqueNode->LinkEndChild(blinnNode);
  1151. // ---------------------------
  1152. TiXmlElement* emissionNode = new TiXmlElement("emission");
  1153. blinnNode->LinkEndChild(emissionNode);
  1154. TiXmlElement* colorEmissionNode = new TiXmlElement("color");
  1155. emissionNode->LinkEndChild(colorEmissionNode);
  1156. colorEmissionNode->SetAttribute("sid", "emission");
  1157. TiXmlText* colorEmissionNodeText = new TiXmlText("0.0 0.0 0.0 1.0");
  1158. colorEmissionNode->LinkEndChild(colorEmissionNodeText);
  1159. // ---------------------------
  1160. TiXmlElement* ambientNode = new TiXmlElement("ambient");
  1161. blinnNode->LinkEndChild(ambientNode);
  1162. TiXmlElement* colorAmbientNode = new TiXmlElement("color");
  1163. ambientNode->LinkEndChild(colorAmbientNode);
  1164. colorAmbientNode->SetAttribute("sid", "ambient");
  1165. TiXmlText* colorAmbientNodeText = new TiXmlText("0.0 0.0 0.0 1.0");
  1166. colorAmbientNode->LinkEndChild(colorAmbientNodeText);
  1167. // ---------------------------
  1168. TiXmlElement* diffuseNode = new TiXmlElement("diffuse");
  1169. blinnNode->LinkEndChild(diffuseNode);
  1170. TiXmlElement* textureDiffuseNode = new TiXmlElement("texture");
  1171. diffuseNode->LinkEndChild(textureDiffuseNode);
  1172. textureDiffuseNode->SetAttribute("texture", avar("%s-sampler", matNames[i].c_str()));
  1173. textureDiffuseNode->SetAttribute("texcoord", "UVMap");
  1174. // Extra info useful for getting the texture to show up correctly in MAYA and 3DS Max
  1175. TiXmlElement* extraNode = new TiXmlElement("extra");
  1176. textureDiffuseNode->LinkEndChild(extraNode);
  1177. TiXmlElement* extraTechNode = new TiXmlElement("technique");
  1178. extraNode->LinkEndChild(extraTechNode);
  1179. extraTechNode->SetAttribute("profile", "MAYA");
  1180. TiXmlElement* extraWrapUNode = new TiXmlElement("wrapU");
  1181. extraTechNode->LinkEndChild(extraWrapUNode);
  1182. extraWrapUNode->SetAttribute("sid", "wrapU0");
  1183. TiXmlText* extraWrapUText = new TiXmlText("TRUE");
  1184. extraWrapUNode->LinkEndChild(extraWrapUText);
  1185. TiXmlElement* extraWrapVNode = new TiXmlElement("wrapV");
  1186. extraTechNode->LinkEndChild(extraWrapVNode);
  1187. extraWrapVNode->SetAttribute("sid", "wrapV0");
  1188. TiXmlText* extraWrapVText = new TiXmlText("TRUE");
  1189. extraWrapVNode->LinkEndChild(extraWrapVText);
  1190. TiXmlElement* extraBlendNode = new TiXmlElement("blend_mode");
  1191. extraTechNode->LinkEndChild(extraBlendNode);
  1192. TiXmlText* extraBlendText = new TiXmlText("ADD");
  1193. extraBlendNode->LinkEndChild(extraBlendText);
  1194. // ---------------------------
  1195. TiXmlElement* specularNode = new TiXmlElement("specular");
  1196. blinnNode->LinkEndChild(specularNode);
  1197. TiXmlElement* colorSpecularNode = new TiXmlElement("color");
  1198. specularNode->LinkEndChild(colorSpecularNode);
  1199. colorSpecularNode->SetAttribute("sid", "specular");
  1200. TiXmlText* colorSpecularNodeText = new TiXmlText("0.5 0.5 0.5 1.0");
  1201. colorSpecularNode->LinkEndChild(colorSpecularNodeText);
  1202. // ---------------------------
  1203. TiXmlElement* shininessNode = new TiXmlElement("shininess");
  1204. blinnNode->LinkEndChild(shininessNode);
  1205. TiXmlElement* colorShininessNode = new TiXmlElement("float");
  1206. shininessNode->LinkEndChild(colorShininessNode);
  1207. colorShininessNode->SetAttribute("sid", "shininess");
  1208. TiXmlText* colorShininessNodeText = new TiXmlText("1.0");
  1209. colorShininessNode->LinkEndChild(colorShininessNodeText);
  1210. // ---------------------------
  1211. TiXmlElement* reflectiveNode = new TiXmlElement("reflective");
  1212. blinnNode->LinkEndChild(reflectiveNode);
  1213. TiXmlElement* colorReflectiveNode = new TiXmlElement("color");
  1214. reflectiveNode->LinkEndChild(colorReflectiveNode);
  1215. colorReflectiveNode->SetAttribute("sid", "reflective");
  1216. TiXmlText* colorReflectiveNodeText = new TiXmlText("0.0 0.0 0.0 1.0");
  1217. colorReflectiveNode->LinkEndChild(colorReflectiveNodeText);
  1218. // ---------------------------
  1219. TiXmlElement* reflectivityNode = new TiXmlElement("reflectivity");
  1220. blinnNode->LinkEndChild(reflectivityNode);
  1221. TiXmlElement* floatReflectivityNode = new TiXmlElement("float");
  1222. reflectivityNode->LinkEndChild(floatReflectivityNode);
  1223. floatReflectivityNode->SetAttribute("sid", "reflectivity");
  1224. TiXmlText* floatReflectivityText = new TiXmlText("0.5");
  1225. floatReflectivityNode->LinkEndChild(floatReflectivityText);
  1226. // ---------------------------
  1227. TiXmlElement* transparentNode = new TiXmlElement("transparent");
  1228. blinnNode->LinkEndChild(transparentNode);
  1229. transparentNode->SetAttribute("opaque", "RGB_ZERO");
  1230. TiXmlElement* colorTransparentNode = new TiXmlElement("color");
  1231. transparentNode->LinkEndChild(colorTransparentNode);
  1232. colorTransparentNode->SetAttribute("sid", "transparent");
  1233. TiXmlText* colorTransparentNodeText = new TiXmlText("0.0 0.0 0.0 1.0");
  1234. colorTransparentNode->LinkEndChild(colorTransparentNodeText);
  1235. // ---------------------------
  1236. TiXmlElement* transparencyNode = new TiXmlElement("transparency");
  1237. blinnNode->LinkEndChild(transparencyNode);
  1238. TiXmlElement* floatTransparencyNode = new TiXmlElement("float");
  1239. transparencyNode->LinkEndChild(floatTransparencyNode);
  1240. floatTransparencyNode->SetAttribute("sid", "transparency");
  1241. TiXmlText* floatTransparencyText = new TiXmlText("0.0");
  1242. floatTransparencyNode->LinkEndChild(floatTransparencyText);
  1243. // ---------------------------
  1244. TiXmlElement* refractionNode = new TiXmlElement("index_of_refraction");
  1245. blinnNode->LinkEndChild(refractionNode);
  1246. TiXmlElement* colorRefractionNode = new TiXmlElement("float");
  1247. refractionNode->LinkEndChild(colorRefractionNode);
  1248. colorRefractionNode->SetAttribute("sid", "index_of_refraction");
  1249. TiXmlText* colorRefractionNodeText = new TiXmlText("1");
  1250. colorRefractionNode->LinkEndChild(colorRefractionNodeText);
  1251. }
  1252. // Finally the material library
  1253. TiXmlElement* matLibNode = new TiXmlElement("library_materials");
  1254. rootNode->LinkEndChild(matLibNode);
  1255. for (U32 i = 0; i < exportData.materials.size(); i++)
  1256. {
  1257. BaseMatInstance* baseInst = exportData.materials[i];
  1258. Material* mat = dynamic_cast<Material*>(baseInst->getMaterial());
  1259. if (!mat)
  1260. continue;
  1261. TiXmlElement* materialNode = new TiXmlElement("material");
  1262. matLibNode->LinkEndChild(materialNode);
  1263. materialNode->SetAttribute("id", avar("%s-material", matNames[i].c_str()));
  1264. materialNode->SetAttribute("name", matNames[i].c_str());
  1265. TiXmlElement* instEffectNode = new TiXmlElement("instance_effect");
  1266. materialNode->LinkEndChild(instEffectNode);
  1267. instEffectNode->SetAttribute("url", avar("#%s-effect", matNames[i].c_str()));
  1268. }
  1269. }
  1270. void ColladaUtils::exportColladaTriangles(TiXmlElement* meshNode, const OptimizedPolyList& mesh, const String& meshName, const Vector<String>& matNames)
  1271. {
  1272. // Start at -1 so we will export polygons that do not have a material.
  1273. for (S32 i = -1; i < matNames.size(); i++)
  1274. {
  1275. // Calculate the number of triangles that uses this Material
  1276. U32 triangleCount = 0;
  1277. for (U32 j = 0; j < mesh.mPolyList.size(); j++)
  1278. {
  1279. const OptimizedPolyList::Poly& poly = mesh.mPolyList[j];
  1280. if (poly.material != i)
  1281. continue;
  1282. if (poly.vertexCount < 3)
  1283. continue;
  1284. if (poly.type == OptimizedPolyList::TriangleList ||
  1285. poly.type == OptimizedPolyList::TriangleFan ||
  1286. poly.type == OptimizedPolyList::TriangleStrip)
  1287. {
  1288. triangleCount += poly.vertexCount - 2;
  1289. }
  1290. else
  1291. AssertISV(false, "ColladaUtils::exportColladaTriangles(): Unknown Poly type!");
  1292. }
  1293. // Make sure that we are actually using this Material
  1294. if (triangleCount == 0)
  1295. continue;
  1296. TiXmlElement* trianglesNode = new TiXmlElement("triangles");
  1297. meshNode->LinkEndChild(trianglesNode);
  1298. trianglesNode->SetAttribute("material", ( i > -1 ) ? avar("%s-material", matNames[i].c_str()) : "" );
  1299. trianglesNode->SetAttribute("count", avar("%d", triangleCount));
  1300. TiXmlElement* trianglesVertInputNode = new TiXmlElement("input");
  1301. trianglesNode->LinkEndChild(trianglesVertInputNode);
  1302. trianglesVertInputNode->SetAttribute("semantic", "VERTEX");
  1303. trianglesVertInputNode->SetAttribute("source", avar("#%s-mesh-vertices", meshName.c_str()));
  1304. trianglesVertInputNode->SetAttribute("offset", "0");
  1305. TiXmlElement* trianglesNormalInputNode = new TiXmlElement("input");
  1306. trianglesNode->LinkEndChild(trianglesNormalInputNode);
  1307. trianglesNormalInputNode->SetAttribute("semantic", "NORMAL");
  1308. trianglesNormalInputNode->SetAttribute("source", avar("#%s-mesh-normals", meshName.c_str()));
  1309. trianglesNormalInputNode->SetAttribute("offset", "1");
  1310. TiXmlElement* trianglesUV0InputNode = new TiXmlElement("input");
  1311. trianglesNode->LinkEndChild(trianglesUV0InputNode);
  1312. trianglesUV0InputNode->SetAttribute("semantic", "TEXCOORD");
  1313. trianglesUV0InputNode->SetAttribute("source", avar("#%s-mesh-map-0", meshName.c_str()));
  1314. trianglesUV0InputNode->SetAttribute("offset", "2");
  1315. trianglesUV0InputNode->SetAttribute("set", "0");
  1316. TiXmlElement* polyNode = new TiXmlElement("p");
  1317. trianglesNode->LinkEndChild(polyNode);
  1318. Vector<U32> tempIndices;
  1319. tempIndices.reserve(4);
  1320. for (U32 j = 0; j < mesh.mPolyList.size(); j++)
  1321. {
  1322. const OptimizedPolyList::Poly& poly = mesh.mPolyList[j];
  1323. if (poly.vertexCount < 3)
  1324. continue;
  1325. if (poly.material != i)
  1326. continue;
  1327. tempIndices.setSize(poly.vertexCount);
  1328. dMemset(tempIndices.address(), 0, poly.vertexCount);
  1329. if (poly.type == OptimizedPolyList::TriangleStrip)
  1330. {
  1331. tempIndices[0] = 0;
  1332. U32 idx = 1;
  1333. for (U32 k = 1; k < poly.vertexCount; k += 2)
  1334. tempIndices[idx++] = k;
  1335. for (U32 k = ((poly.vertexCount - 1) & (~0x1)); k > 0; k -= 2)
  1336. tempIndices[idx++] = k;
  1337. }
  1338. else if (poly.type == OptimizedPolyList::TriangleList ||
  1339. poly.type == OptimizedPolyList::TriangleFan)
  1340. {
  1341. for (U32 k = 0; k < poly.vertexCount; k++)
  1342. tempIndices[k] = k;
  1343. }
  1344. else
  1345. AssertISV(false, "ColladaUtils::exportColladaTriangles(): Unknown Poly type!");
  1346. const U32& firstIdx = mesh.mIndexList[poly.vertexStart];
  1347. const OptimizedPolyList::VertIndex& firstVertIdx = mesh.mVertexList[firstIdx];
  1348. for (U32 k = 1; k < poly.vertexCount - 1; k++)
  1349. {
  1350. const U32& secondIdx = mesh.mIndexList[poly.vertexStart + tempIndices[k]];
  1351. const U32& thirdIdx = mesh.mIndexList[poly.vertexStart + tempIndices[k + 1]];
  1352. const OptimizedPolyList::VertIndex& secondVertIdx = mesh.mVertexList[secondIdx];
  1353. const OptimizedPolyList::VertIndex& thirdVertIdx = mesh.mVertexList[thirdIdx];
  1354. // Note the reversed winding on the triangles
  1355. const char* tri = avar("%d %d %d %d %d %d %d %d %d ",
  1356. thirdVertIdx.vertIdx, thirdVertIdx.normalIdx, thirdVertIdx.uv0Idx,
  1357. secondVertIdx.vertIdx, secondVertIdx.normalIdx, secondVertIdx.uv0Idx,
  1358. firstVertIdx.vertIdx, firstVertIdx.normalIdx, firstVertIdx.uv0Idx);
  1359. TiXmlText* triangleText = new TiXmlText(tri);
  1360. polyNode->LinkEndChild(triangleText);
  1361. }
  1362. }
  1363. }
  1364. }
  1365. void ColladaUtils::exportColladaTriangles(TiXmlElement* meshNode, const ExportData& exportData, const U32 detailLevel, const String& meshName)
  1366. {
  1367. // Calculate the number of triangles that uses this Material
  1368. U32 triangleCount = 0;
  1369. const ExportData::detailLevel* dl = &exportData.detailLevels[detailLevel];
  1370. for (S32 i = 0; i < dl->materialRefList.size(); i++)
  1371. {
  1372. int matIdx;
  1373. dl->materialRefList.tryGetValue(i, matIdx);
  1374. BaseMatInstance* baseInst = exportData.materials[matIdx];
  1375. Material* mat = dynamic_cast<Material*>(baseInst->getMaterial());
  1376. if (!mat)
  1377. continue;
  1378. String matName;
  1379. if (mat->getName() && mat->getName()[0])
  1380. matName = mat->mMapTo;
  1381. for (U32 j = 0; j < dl->mesh.mPolyList.size(); j++)
  1382. {
  1383. const OptimizedPolyList::Poly& poly = dl->mesh.mPolyList[j];
  1384. if (poly.material != i)
  1385. continue;
  1386. if (poly.vertexCount < 3)
  1387. continue;
  1388. if (poly.type == OptimizedPolyList::TriangleList ||
  1389. poly.type == OptimizedPolyList::TriangleFan ||
  1390. poly.type == OptimizedPolyList::TriangleStrip)
  1391. {
  1392. triangleCount += poly.vertexCount - 2;
  1393. }
  1394. else
  1395. AssertISV(false, "ColladaUtils::exportColladaTriangles(): Unknown Poly type!");
  1396. }
  1397. // Make sure that we are actually using this Material
  1398. if (triangleCount == 0)
  1399. continue;
  1400. TiXmlElement* trianglesNode = new TiXmlElement("triangles");
  1401. meshNode->LinkEndChild(trianglesNode);
  1402. trianglesNode->SetAttribute("material", (i > -1) ? avar("%s-material", matName.c_str()) : "");
  1403. trianglesNode->SetAttribute("count", avar("%d", triangleCount));
  1404. TiXmlElement* trianglesVertInputNode = new TiXmlElement("input");
  1405. trianglesNode->LinkEndChild(trianglesVertInputNode);
  1406. trianglesVertInputNode->SetAttribute("semantic", "VERTEX");
  1407. trianglesVertInputNode->SetAttribute("source", avar("#%s-mesh-vertices", meshName.c_str()));
  1408. trianglesVertInputNode->SetAttribute("offset", "0");
  1409. TiXmlElement* trianglesNormalInputNode = new TiXmlElement("input");
  1410. trianglesNode->LinkEndChild(trianglesNormalInputNode);
  1411. trianglesNormalInputNode->SetAttribute("semantic", "NORMAL");
  1412. trianglesNormalInputNode->SetAttribute("source", avar("#%s-mesh-normals", meshName.c_str()));
  1413. trianglesNormalInputNode->SetAttribute("offset", "1");
  1414. TiXmlElement* trianglesUV0InputNode = new TiXmlElement("input");
  1415. trianglesNode->LinkEndChild(trianglesUV0InputNode);
  1416. trianglesUV0InputNode->SetAttribute("semantic", "TEXCOORD");
  1417. trianglesUV0InputNode->SetAttribute("source", avar("#%s-mesh-map-0", meshName.c_str()));
  1418. trianglesUV0InputNode->SetAttribute("offset", "2");
  1419. trianglesUV0InputNode->SetAttribute("set", "0");
  1420. TiXmlElement* polyNode = new TiXmlElement("p");
  1421. trianglesNode->LinkEndChild(polyNode);
  1422. Vector<U32> tempIndices;
  1423. tempIndices.reserve(4);
  1424. for (U32 j = 0; j < dl->mesh.mPolyList.size(); j++)
  1425. {
  1426. const OptimizedPolyList::Poly& poly = dl->mesh.mPolyList[j];
  1427. if (poly.vertexCount < 3)
  1428. continue;
  1429. if (poly.material != i)
  1430. continue;
  1431. tempIndices.setSize(poly.vertexCount);
  1432. dMemset(tempIndices.address(), 0, poly.vertexCount);
  1433. if (poly.type == OptimizedPolyList::TriangleStrip)
  1434. {
  1435. tempIndices[0] = 0;
  1436. U32 idx = 1;
  1437. for (U32 k = 1; k < poly.vertexCount; k += 2)
  1438. tempIndices[idx++] = k;
  1439. for (U32 k = ((poly.vertexCount - 1) & (~0x1)); k > 0; k -= 2)
  1440. tempIndices[idx++] = k;
  1441. }
  1442. else if (poly.type == OptimizedPolyList::TriangleList ||
  1443. poly.type == OptimizedPolyList::TriangleFan)
  1444. {
  1445. for (U32 k = 0; k < poly.vertexCount; k++)
  1446. tempIndices[k] = k;
  1447. }
  1448. else
  1449. AssertISV(false, "ColladaUtils::exportColladaTriangles(): Unknown Poly type!");
  1450. const U32& firstIdx = dl->mesh.mIndexList[poly.vertexStart];
  1451. const OptimizedPolyList::VertIndex& firstVertIdx = dl->mesh.mVertexList[firstIdx];
  1452. for (U32 k = 1; k < poly.vertexCount - 1; k++)
  1453. {
  1454. const U32& secondIdx = dl->mesh.mIndexList[poly.vertexStart + tempIndices[k]];
  1455. const U32& thirdIdx = dl->mesh.mIndexList[poly.vertexStart + tempIndices[k + 1]];
  1456. const OptimizedPolyList::VertIndex& secondVertIdx = dl->mesh.mVertexList[secondIdx];
  1457. const OptimizedPolyList::VertIndex& thirdVertIdx = dl->mesh.mVertexList[thirdIdx];
  1458. // Note the reversed winding on the triangles
  1459. const char* tri = avar("%d %d %d %d %d %d %d %d %d ",
  1460. thirdVertIdx.vertIdx, thirdVertIdx.normalIdx, thirdVertIdx.uv0Idx,
  1461. secondVertIdx.vertIdx, secondVertIdx.normalIdx, secondVertIdx.uv0Idx,
  1462. firstVertIdx.vertIdx, firstVertIdx.normalIdx, firstVertIdx.uv0Idx);
  1463. TiXmlText* triangleText = new TiXmlText(tri);
  1464. polyNode->LinkEndChild(triangleText);
  1465. }
  1466. }
  1467. }
  1468. }
  1469. void ColladaUtils::exportColladaCollisionTriangles(TiXmlElement* meshNode, const ExportData& exportData, const U32 collisionIdx)
  1470. {
  1471. // Calculate the number of triangles that uses this Material
  1472. U32 triangleCount = 0;
  1473. const ExportData::colMesh* col = &exportData.colMeshes[collisionIdx];
  1474. String meshName = col->colMeshName;
  1475. for (U32 j = 0; j < col->mesh.mPolyList.size(); j++)
  1476. {
  1477. const OptimizedPolyList::Poly& poly = col->mesh.mPolyList[j];
  1478. if (poly.vertexCount < 3)
  1479. continue;
  1480. if (poly.type == OptimizedPolyList::TriangleList ||
  1481. poly.type == OptimizedPolyList::TriangleFan ||
  1482. poly.type == OptimizedPolyList::TriangleStrip)
  1483. {
  1484. triangleCount += poly.vertexCount - 2;
  1485. }
  1486. else
  1487. AssertISV(false, "ColladaUtils::exportColladaCollisionTriangles(): Unknown Poly type!");
  1488. }
  1489. // Make sure that we are actually using this Material
  1490. if (triangleCount == 0)
  1491. return;
  1492. TiXmlElement* trianglesNode = new TiXmlElement("triangles");
  1493. meshNode->LinkEndChild(trianglesNode);
  1494. trianglesNode->SetAttribute("material", "");
  1495. trianglesNode->SetAttribute("count", avar("%d", triangleCount));
  1496. TiXmlElement* trianglesVertInputNode = new TiXmlElement("input");
  1497. trianglesNode->LinkEndChild(trianglesVertInputNode);
  1498. trianglesVertInputNode->SetAttribute("semantic", "VERTEX");
  1499. trianglesVertInputNode->SetAttribute("source", avar("#%s-mesh-vertices", meshName.c_str()));
  1500. trianglesVertInputNode->SetAttribute("offset", "0");
  1501. TiXmlElement* trianglesNormalInputNode = new TiXmlElement("input");
  1502. trianglesNode->LinkEndChild(trianglesNormalInputNode);
  1503. trianglesNormalInputNode->SetAttribute("semantic", "NORMAL");
  1504. trianglesNormalInputNode->SetAttribute("source", avar("#%s-mesh-normals", meshName.c_str()));
  1505. trianglesNormalInputNode->SetAttribute("offset", "1");
  1506. TiXmlElement* trianglesUV0InputNode = new TiXmlElement("input");
  1507. trianglesNode->LinkEndChild(trianglesUV0InputNode);
  1508. trianglesUV0InputNode->SetAttribute("semantic", "TEXCOORD");
  1509. trianglesUV0InputNode->SetAttribute("source", avar("#%s-mesh-map-0", meshName.c_str()));
  1510. trianglesUV0InputNode->SetAttribute("offset", "2");
  1511. trianglesUV0InputNode->SetAttribute("set", "0");
  1512. TiXmlElement* polyNode = new TiXmlElement("p");
  1513. trianglesNode->LinkEndChild(polyNode);
  1514. Vector<U32> tempIndices;
  1515. tempIndices.reserve(4);
  1516. for (U32 j = 0; j < col->mesh.mPolyList.size(); j++)
  1517. {
  1518. const OptimizedPolyList::Poly& poly = col->mesh.mPolyList[j];
  1519. if (poly.vertexCount < 3)
  1520. continue;
  1521. tempIndices.setSize(poly.vertexCount);
  1522. dMemset(tempIndices.address(), 0, poly.vertexCount);
  1523. if (poly.type == OptimizedPolyList::TriangleStrip)
  1524. {
  1525. tempIndices[0] = 0;
  1526. U32 idx = 1;
  1527. for (U32 k = 1; k < poly.vertexCount; k += 2)
  1528. tempIndices[idx++] = k;
  1529. for (U32 k = ((poly.vertexCount - 1) & (~0x1)); k > 0; k -= 2)
  1530. tempIndices[idx++] = k;
  1531. }
  1532. else if (poly.type == OptimizedPolyList::TriangleList ||
  1533. poly.type == OptimizedPolyList::TriangleFan)
  1534. {
  1535. for (U32 k = 0; k < poly.vertexCount; k++)
  1536. tempIndices[k] = k;
  1537. }
  1538. else
  1539. AssertISV(false, "ColladaUtils::exportColladaTriangles(): Unknown Poly type!");
  1540. const U32& firstIdx = col->mesh.mIndexList[poly.vertexStart];
  1541. const OptimizedPolyList::VertIndex& firstVertIdx = col->mesh.mVertexList[firstIdx];
  1542. for (U32 k = 1; k < poly.vertexCount - 1; k++)
  1543. {
  1544. const U32& secondIdx = col->mesh.mIndexList[poly.vertexStart + tempIndices[k]];
  1545. const U32& thirdIdx = col->mesh.mIndexList[poly.vertexStart + tempIndices[k + 1]];
  1546. const OptimizedPolyList::VertIndex& secondVertIdx = col->mesh.mVertexList[secondIdx];
  1547. const OptimizedPolyList::VertIndex& thirdVertIdx = col->mesh.mVertexList[thirdIdx];
  1548. // Note the reversed winding on the triangles
  1549. const char* tri = avar("%d %d %d %d %d %d %d %d %d ",
  1550. thirdVertIdx.vertIdx, thirdVertIdx.normalIdx, thirdVertIdx.uv0Idx,
  1551. secondVertIdx.vertIdx, secondVertIdx.normalIdx, secondVertIdx.uv0Idx,
  1552. firstVertIdx.vertIdx, firstVertIdx.normalIdx, firstVertIdx.uv0Idx);
  1553. TiXmlText* triangleText = new TiXmlText(tri);
  1554. polyNode->LinkEndChild(triangleText);
  1555. }
  1556. }
  1557. }
  1558. void ColladaUtils::exportColladaMesh(TiXmlElement* rootNode, const OptimizedPolyList& mesh, const String& meshName, const Vector<String>& matNames)
  1559. {
  1560. TiXmlElement* libGeomsNode = new TiXmlElement("library_geometries");
  1561. rootNode->LinkEndChild(libGeomsNode);
  1562. TiXmlElement* geometryNode = new TiXmlElement("geometry");
  1563. libGeomsNode->LinkEndChild(geometryNode);
  1564. geometryNode->SetAttribute("id", avar("%s-mesh", meshName.c_str()));
  1565. geometryNode->SetAttribute("name", avar("%s", meshName.c_str()));
  1566. TiXmlElement* meshNode = new TiXmlElement("mesh");
  1567. geometryNode->LinkEndChild(meshNode);
  1568. // Save out the vertices
  1569. TiXmlElement* vertsSourceNode = new TiXmlElement("source");
  1570. meshNode->LinkEndChild(vertsSourceNode);
  1571. vertsSourceNode->SetAttribute("id", avar("%s-mesh-positions", meshName.c_str()));
  1572. TiXmlElement* vertsNode = new TiXmlElement("float_array");
  1573. vertsSourceNode->LinkEndChild(vertsNode);
  1574. vertsNode->SetAttribute("id", avar("%s-mesh-positions-array", meshName.c_str()));
  1575. vertsNode->SetAttribute("count", avar("%d", mesh.mPoints.size() * 3));
  1576. for (U32 i = 0; i < mesh.mPoints.size(); i++)
  1577. {
  1578. const Point3F& vert = mesh.mPoints[i];
  1579. TiXmlText* vertText = new TiXmlText(avar("%.4f %.4f %.4f ", vert.x, vert.y, vert.z));
  1580. vertsNode->LinkEndChild(vertText);
  1581. }
  1582. // Save the vertex accessor
  1583. TiXmlElement* vertsTechNode = new TiXmlElement("technique_common");
  1584. vertsSourceNode->LinkEndChild(vertsTechNode);
  1585. TiXmlElement* vertsAccNode = new TiXmlElement("accessor");
  1586. vertsTechNode->LinkEndChild(vertsAccNode);
  1587. vertsAccNode->SetAttribute("source", avar("#%s-mesh-positions-array", meshName.c_str()));
  1588. vertsAccNode->SetAttribute("count", avar("%d", mesh.mPoints.size()));
  1589. vertsAccNode->SetAttribute("stride", "3");
  1590. TiXmlElement* vertsAccXNode = new TiXmlElement("param");
  1591. vertsAccNode->LinkEndChild(vertsAccXNode);
  1592. vertsAccXNode->SetAttribute("name", "X");
  1593. vertsAccXNode->SetAttribute("type", "float");
  1594. TiXmlElement* vertsAccYNode = new TiXmlElement("param");
  1595. vertsAccNode->LinkEndChild(vertsAccYNode);
  1596. vertsAccYNode->SetAttribute("name", "Y");
  1597. vertsAccYNode->SetAttribute("type", "float");
  1598. TiXmlElement* vertsAccZNode = new TiXmlElement("param");
  1599. vertsAccNode->LinkEndChild(vertsAccZNode);
  1600. vertsAccZNode->SetAttribute("name", "Z");
  1601. vertsAccZNode->SetAttribute("type", "float");
  1602. // Save out the normals
  1603. TiXmlElement* normalsSourceNode = new TiXmlElement("source");
  1604. meshNode->LinkEndChild(normalsSourceNode);
  1605. normalsSourceNode->SetAttribute("id", avar("%s-mesh-normals", meshName.c_str()));
  1606. TiXmlElement* normalsNode = new TiXmlElement("float_array");
  1607. normalsSourceNode->LinkEndChild(normalsNode);
  1608. normalsNode->SetAttribute("id", avar("%s-mesh-normals-array", meshName.c_str()));
  1609. normalsNode->SetAttribute("count", avar("%d", mesh.mNormals.size() * 3));
  1610. for (U32 i = 0; i < mesh.mNormals.size(); i++)
  1611. {
  1612. const Point3F& normal = mesh.mNormals[i];
  1613. TiXmlText* normalText = new TiXmlText(avar("%.4f %.4f %.4f ", normal.x, normal.y, normal.z));
  1614. normalsNode->LinkEndChild(normalText);
  1615. }
  1616. // Save the normals accessor
  1617. TiXmlElement* normalsTechNode = new TiXmlElement("technique_common");
  1618. normalsSourceNode->LinkEndChild(normalsTechNode);
  1619. TiXmlElement* normalsAccNode = new TiXmlElement("accessor");
  1620. normalsTechNode->LinkEndChild(normalsAccNode);
  1621. normalsAccNode->SetAttribute("source", avar("#%s-mesh-normals-array", meshName.c_str()));
  1622. normalsAccNode->SetAttribute("count", avar("%d", mesh.mNormals.size()));
  1623. normalsAccNode->SetAttribute("stride", "3");
  1624. TiXmlElement* normalsAccXNode = new TiXmlElement("param");
  1625. normalsAccNode->LinkEndChild(normalsAccXNode);
  1626. normalsAccXNode->SetAttribute("name", "X");
  1627. normalsAccXNode->SetAttribute("type", "float");
  1628. TiXmlElement* normalsAccYNode = new TiXmlElement("param");
  1629. normalsAccNode->LinkEndChild(normalsAccYNode);
  1630. normalsAccYNode->SetAttribute("name", "Y");
  1631. normalsAccYNode->SetAttribute("type", "float");
  1632. TiXmlElement* normalsAccZNode = new TiXmlElement("param");
  1633. normalsAccNode->LinkEndChild(normalsAccZNode);
  1634. normalsAccZNode->SetAttribute("name", "Z");
  1635. normalsAccZNode->SetAttribute("type", "float");
  1636. // Save out the uvs
  1637. TiXmlElement* uv0SourceNode = new TiXmlElement("source");
  1638. meshNode->LinkEndChild(uv0SourceNode);
  1639. uv0SourceNode->SetAttribute("id", avar("%s-mesh-map-0", meshName.c_str()));
  1640. TiXmlElement* uv0Node = new TiXmlElement("float_array");
  1641. uv0SourceNode->LinkEndChild(uv0Node);
  1642. uv0Node->SetAttribute("id", avar("%s-mesh-map-0-array", meshName.c_str()));
  1643. uv0Node->SetAttribute("count", avar("%d", mesh.mUV0s.size() * 2));
  1644. for (U32 i = 0; i < mesh.mUV0s.size(); i++)
  1645. {
  1646. const Point2F& uv0 = mesh.mUV0s[i];
  1647. TiXmlText* uv0Text = new TiXmlText(avar("%.4f %.4f ", uv0.x, 1.0f - uv0.y)); // COLLADA uvs are upside down compared to Torque
  1648. uv0Node->LinkEndChild(uv0Text);
  1649. }
  1650. // Save the uv0 accessor
  1651. TiXmlElement* uv0TechNode = new TiXmlElement("technique_common");
  1652. uv0SourceNode->LinkEndChild(uv0TechNode);
  1653. TiXmlElement* uv0AccNode = new TiXmlElement("accessor");
  1654. uv0TechNode->LinkEndChild(uv0AccNode);
  1655. uv0AccNode->SetAttribute("source", avar("#%s-mesh-map-0-array", meshName.c_str()));
  1656. uv0AccNode->SetAttribute("count", avar("%d", mesh.mUV0s.size()));
  1657. uv0AccNode->SetAttribute("stride", "2");
  1658. TiXmlElement* uv0AccSNode = new TiXmlElement("param");
  1659. uv0AccNode->LinkEndChild(uv0AccSNode);
  1660. uv0AccSNode->SetAttribute("name", "S");
  1661. uv0AccSNode->SetAttribute("type", "float");
  1662. TiXmlElement* uv0AccTNode = new TiXmlElement("param");
  1663. uv0AccNode->LinkEndChild(uv0AccTNode);
  1664. uv0AccTNode->SetAttribute("name", "T");
  1665. uv0AccTNode->SetAttribute("type", "float");
  1666. // Define the vertices position array
  1667. TiXmlElement* verticesNode = new TiXmlElement("vertices");
  1668. meshNode->LinkEndChild(verticesNode);
  1669. verticesNode->SetAttribute("id", avar("%s-mesh-vertices", meshName.c_str()));
  1670. TiXmlElement* verticesInputNode = new TiXmlElement("input");
  1671. verticesNode->LinkEndChild(verticesInputNode);
  1672. verticesInputNode->SetAttribute("semantic", "POSITION");
  1673. verticesInputNode->SetAttribute("source", avar("#%s-mesh-positions", meshName.c_str()));
  1674. exportColladaTriangles(meshNode, mesh, meshName, matNames);
  1675. // Extra info useful for COLLADAMaya importer (OpenCOLLADA)
  1676. TiXmlElement* extraGeoNode = new TiXmlElement("extra");
  1677. libGeomsNode->LinkEndChild(extraGeoNode);
  1678. TiXmlElement* extraGeoNodeTech = new TiXmlElement("technique");
  1679. extraGeoNode->LinkEndChild(extraGeoNodeTech);
  1680. extraGeoNodeTech->SetAttribute("profile", "OpenCOLLADAMaya");
  1681. TiXmlElement* mayaNode2Id = new TiXmlElement("originalMayaNodeId");
  1682. extraGeoNodeTech->LinkEndChild(mayaNode2Id);
  1683. mayaNode2Id->SetAttribute("sid", "originalMayaNodeId");
  1684. TiXmlText* mayaIdMesh = new TiXmlText(avar("%s", meshName.c_str()));
  1685. mayaNode2Id->LinkEndChild(mayaIdMesh);
  1686. TiXmlElement* doubleSidedId = new TiXmlElement("double_sided");
  1687. extraGeoNodeTech->LinkEndChild(doubleSidedId);
  1688. doubleSidedId->SetAttribute("sid", "double_sided");
  1689. TiXmlText* doubleSideIdText = new TiXmlText("1");
  1690. doubleSidedId->LinkEndChild(doubleSideIdText);
  1691. TiXmlElement* paramExtraNode = new TiXmlElement("param");
  1692. extraGeoNodeTech->LinkEndChild(paramExtraNode);
  1693. paramExtraNode->SetAttribute("sid", "colladaId");
  1694. paramExtraNode->SetAttribute("type", "string");
  1695. TiXmlText* mayaParamMesh = new TiXmlText(avar("%s-mesh", meshName.c_str()));
  1696. paramExtraNode->LinkEndChild(mayaParamMesh);
  1697. }
  1698. void ColladaUtils::exportColladaMesh(TiXmlElement* rootNode, const ExportData& exportData, const String& meshName)
  1699. {
  1700. TiXmlElement* libGeomsNode = new TiXmlElement("library_geometries");
  1701. rootNode->LinkEndChild(libGeomsNode);
  1702. for (U32 d = 0; d < exportData.detailLevels.size(); d++)
  1703. {
  1704. char lodMeshName[256];
  1705. dSprintf(lodMeshName, 256, "%s%d", meshName.c_str(), exportData.detailLevels[d].size);
  1706. char lodMeshID[256];
  1707. dSprintf(lodMeshID, 256, "%s-mesh", lodMeshName);
  1708. TiXmlElement* geometryNode = new TiXmlElement("geometry");
  1709. libGeomsNode->LinkEndChild(geometryNode);
  1710. geometryNode->SetAttribute("id", lodMeshID);
  1711. geometryNode->SetAttribute("name", lodMeshName);
  1712. TiXmlElement* meshNode = new TiXmlElement("mesh");
  1713. geometryNode->LinkEndChild(meshNode);
  1714. // Save out the vertices
  1715. TiXmlElement* vertsSourceNode = new TiXmlElement("source");
  1716. meshNode->LinkEndChild(vertsSourceNode);
  1717. vertsSourceNode->SetAttribute("id", avar("%s-mesh-positions", lodMeshName));
  1718. TiXmlElement* vertsNode = new TiXmlElement("float_array");
  1719. vertsSourceNode->LinkEndChild(vertsNode);
  1720. vertsNode->SetAttribute("id", avar("%s-mesh-positions-array", lodMeshName));
  1721. vertsNode->SetAttribute("count", avar("%d", exportData.detailLevels[d].mesh.mPoints.size() * 3));
  1722. for (U32 i = 0; i < exportData.detailLevels[d].mesh.mPoints.size(); i++)
  1723. {
  1724. const Point3F& vert = exportData.detailLevels[d].mesh.mPoints[i];
  1725. TiXmlText* vertText = new TiXmlText(avar("%.4f %.4f %.4f ", vert.x, vert.y, vert.z));
  1726. vertsNode->LinkEndChild(vertText);
  1727. }
  1728. // Save the vertex accessor
  1729. TiXmlElement* vertsTechNode = new TiXmlElement("technique_common");
  1730. vertsSourceNode->LinkEndChild(vertsTechNode);
  1731. TiXmlElement* vertsAccNode = new TiXmlElement("accessor");
  1732. vertsTechNode->LinkEndChild(vertsAccNode);
  1733. vertsAccNode->SetAttribute("source", avar("#%s-mesh-positions-array", lodMeshName));
  1734. vertsAccNode->SetAttribute("count", avar("%d", exportData.detailLevels[d].mesh.mPoints.size()));
  1735. vertsAccNode->SetAttribute("stride", "3");
  1736. TiXmlElement* vertsAccXNode = new TiXmlElement("param");
  1737. vertsAccNode->LinkEndChild(vertsAccXNode);
  1738. vertsAccXNode->SetAttribute("name", "X");
  1739. vertsAccXNode->SetAttribute("type", "float");
  1740. TiXmlElement* vertsAccYNode = new TiXmlElement("param");
  1741. vertsAccNode->LinkEndChild(vertsAccYNode);
  1742. vertsAccYNode->SetAttribute("name", "Y");
  1743. vertsAccYNode->SetAttribute("type", "float");
  1744. TiXmlElement* vertsAccZNode = new TiXmlElement("param");
  1745. vertsAccNode->LinkEndChild(vertsAccZNode);
  1746. vertsAccZNode->SetAttribute("name", "Z");
  1747. vertsAccZNode->SetAttribute("type", "float");
  1748. // Save out the normals
  1749. TiXmlElement* normalsSourceNode = new TiXmlElement("source");
  1750. meshNode->LinkEndChild(normalsSourceNode);
  1751. normalsSourceNode->SetAttribute("id", avar("%s-mesh-normals", lodMeshName));
  1752. TiXmlElement* normalsNode = new TiXmlElement("float_array");
  1753. normalsSourceNode->LinkEndChild(normalsNode);
  1754. normalsNode->SetAttribute("id", avar("%s-mesh-normals-array", lodMeshName));
  1755. normalsNode->SetAttribute("count", avar("%d", exportData.detailLevels[d].mesh.mNormals.size() * 3));
  1756. for (U32 i = 0; i < exportData.detailLevels[d].mesh.mNormals.size(); i++)
  1757. {
  1758. const Point3F& normal = exportData.detailLevels[d].mesh.mNormals[i];
  1759. TiXmlText* normalText = new TiXmlText(avar("%.4f %.4f %.4f ", normal.x, normal.y, normal.z));
  1760. normalsNode->LinkEndChild(normalText);
  1761. }
  1762. // Save the normals accessor
  1763. TiXmlElement* normalsTechNode = new TiXmlElement("technique_common");
  1764. normalsSourceNode->LinkEndChild(normalsTechNode);
  1765. TiXmlElement* normalsAccNode = new TiXmlElement("accessor");
  1766. normalsTechNode->LinkEndChild(normalsAccNode);
  1767. normalsAccNode->SetAttribute("source", avar("#%s-mesh-normals-array", lodMeshName));
  1768. normalsAccNode->SetAttribute("count", avar("%d", exportData.detailLevels[d].mesh.mNormals.size()));
  1769. normalsAccNode->SetAttribute("stride", "3");
  1770. TiXmlElement* normalsAccXNode = new TiXmlElement("param");
  1771. normalsAccNode->LinkEndChild(normalsAccXNode);
  1772. normalsAccXNode->SetAttribute("name", "X");
  1773. normalsAccXNode->SetAttribute("type", "float");
  1774. TiXmlElement* normalsAccYNode = new TiXmlElement("param");
  1775. normalsAccNode->LinkEndChild(normalsAccYNode);
  1776. normalsAccYNode->SetAttribute("name", "Y");
  1777. normalsAccYNode->SetAttribute("type", "float");
  1778. TiXmlElement* normalsAccZNode = new TiXmlElement("param");
  1779. normalsAccNode->LinkEndChild(normalsAccZNode);
  1780. normalsAccZNode->SetAttribute("name", "Z");
  1781. normalsAccZNode->SetAttribute("type", "float");
  1782. // Save out the uvs
  1783. TiXmlElement* uv0SourceNode = new TiXmlElement("source");
  1784. meshNode->LinkEndChild(uv0SourceNode);
  1785. uv0SourceNode->SetAttribute("id", avar("%s-mesh-map-0", lodMeshName));
  1786. TiXmlElement* uv0Node = new TiXmlElement("float_array");
  1787. uv0SourceNode->LinkEndChild(uv0Node);
  1788. uv0Node->SetAttribute("id", avar("%s-mesh-map-0-array", lodMeshName));
  1789. uv0Node->SetAttribute("count", avar("%d", exportData.detailLevels[d].mesh.mUV0s.size() * 2));
  1790. for (U32 i = 0; i < exportData.detailLevels[d].mesh.mUV0s.size(); i++)
  1791. {
  1792. const Point2F& uv0 = exportData.detailLevels[d].mesh.mUV0s[i];
  1793. TiXmlText* uv0Text = new TiXmlText(avar("%.4f %.4f ", uv0.x, 1.0f - uv0.y)); // COLLADA uvs are upside down compared to Torque
  1794. uv0Node->LinkEndChild(uv0Text);
  1795. }
  1796. // Save the uv0 accessor
  1797. TiXmlElement* uv0TechNode = new TiXmlElement("technique_common");
  1798. uv0SourceNode->LinkEndChild(uv0TechNode);
  1799. TiXmlElement* uv0AccNode = new TiXmlElement("accessor");
  1800. uv0TechNode->LinkEndChild(uv0AccNode);
  1801. uv0AccNode->SetAttribute("source", avar("#%s-mesh-map-0-array", lodMeshName));
  1802. uv0AccNode->SetAttribute("count", avar("%d", exportData.detailLevels[d].mesh.mUV0s.size()));
  1803. uv0AccNode->SetAttribute("stride", "2");
  1804. TiXmlElement* uv0AccSNode = new TiXmlElement("param");
  1805. uv0AccNode->LinkEndChild(uv0AccSNode);
  1806. uv0AccSNode->SetAttribute("name", "S");
  1807. uv0AccSNode->SetAttribute("type", "float");
  1808. TiXmlElement* uv0AccTNode = new TiXmlElement("param");
  1809. uv0AccNode->LinkEndChild(uv0AccTNode);
  1810. uv0AccTNode->SetAttribute("name", "T");
  1811. uv0AccTNode->SetAttribute("type", "float");
  1812. // Define the vertices position array
  1813. TiXmlElement* verticesNode = new TiXmlElement("vertices");
  1814. meshNode->LinkEndChild(verticesNode);
  1815. verticesNode->SetAttribute("id", avar("%s-mesh-vertices", lodMeshName));
  1816. TiXmlElement* verticesInputNode = new TiXmlElement("input");
  1817. verticesNode->LinkEndChild(verticesInputNode);
  1818. verticesInputNode->SetAttribute("semantic", "POSITION");
  1819. verticesInputNode->SetAttribute("source", avar("#%s-mesh-positions", lodMeshName));
  1820. Vector<String> mapNames;
  1821. //exportColladaTriangles(meshNode, exportData.detailLevels[d].mesh, lodMeshName, mapNames);
  1822. exportColladaTriangles(meshNode, exportData, d, lodMeshName);
  1823. // Extra info useful for COLLADAMaya importer (OpenCOLLADA)
  1824. TiXmlElement* extraGeoNode = new TiXmlElement("extra");
  1825. libGeomsNode->LinkEndChild(extraGeoNode);
  1826. TiXmlElement* extraGeoNodeTech = new TiXmlElement("technique");
  1827. extraGeoNode->LinkEndChild(extraGeoNodeTech);
  1828. extraGeoNodeTech->SetAttribute("profile", "OpenCOLLADAMaya");
  1829. TiXmlElement* mayaNode2Id = new TiXmlElement("originalMayaNodeId");
  1830. extraGeoNodeTech->LinkEndChild(mayaNode2Id);
  1831. mayaNode2Id->SetAttribute("sid", "originalMayaNodeId");
  1832. TiXmlText* mayaIdMesh = new TiXmlText(avar("%s", lodMeshName));
  1833. mayaNode2Id->LinkEndChild(mayaIdMesh);
  1834. TiXmlElement* doubleSidedId = new TiXmlElement("double_sided");
  1835. extraGeoNodeTech->LinkEndChild(doubleSidedId);
  1836. doubleSidedId->SetAttribute("sid", "double_sided");
  1837. TiXmlText* doubleSideIdText = new TiXmlText("1");
  1838. doubleSidedId->LinkEndChild(doubleSideIdText);
  1839. TiXmlElement* paramExtraNode = new TiXmlElement("param");
  1840. extraGeoNodeTech->LinkEndChild(paramExtraNode);
  1841. paramExtraNode->SetAttribute("sid", "colladaId");
  1842. paramExtraNode->SetAttribute("type", "string");
  1843. TiXmlText* mayaParamMesh = new TiXmlText(avar("%s-mesh", lodMeshName));
  1844. paramExtraNode->LinkEndChild(mayaParamMesh);
  1845. }
  1846. //And now collisions
  1847. for (U32 d = 0; d < exportData.colMeshes.size(); d++)
  1848. {
  1849. const char* colMeshName = exportData.colMeshes[d].colMeshName;
  1850. char colMeshId[256];
  1851. dSprintf(colMeshId, 256, "%s-mesh", colMeshName);
  1852. TiXmlElement* geometryNode = new TiXmlElement("geometry");
  1853. libGeomsNode->LinkEndChild(geometryNode);
  1854. geometryNode->SetAttribute("id", colMeshId);
  1855. geometryNode->SetAttribute("name", colMeshName);
  1856. TiXmlElement* meshNode = new TiXmlElement("mesh");
  1857. geometryNode->LinkEndChild(meshNode);
  1858. // Save out the vertices
  1859. TiXmlElement* vertsSourceNode = new TiXmlElement("source");
  1860. meshNode->LinkEndChild(vertsSourceNode);
  1861. vertsSourceNode->SetAttribute("id", avar("%s-mesh-positions", colMeshName));
  1862. TiXmlElement* vertsNode = new TiXmlElement("float_array");
  1863. vertsSourceNode->LinkEndChild(vertsNode);
  1864. vertsNode->SetAttribute("id", avar("%s-mesh-positions-array", colMeshName));
  1865. vertsNode->SetAttribute("count", avar("%d", exportData.colMeshes[d].mesh.mPoints.size() * 3));
  1866. for (U32 i = 0; i < exportData.colMeshes[d].mesh.mPoints.size(); i++)
  1867. {
  1868. const Point3F& vert = exportData.colMeshes[d].mesh.mPoints[i];
  1869. TiXmlText* vertText = new TiXmlText(avar("%.4f %.4f %.4f ", vert.x, vert.y, vert.z));
  1870. vertsNode->LinkEndChild(vertText);
  1871. }
  1872. // Save the vertex accessor
  1873. TiXmlElement* vertsTechNode = new TiXmlElement("technique_common");
  1874. vertsSourceNode->LinkEndChild(vertsTechNode);
  1875. TiXmlElement* vertsAccNode = new TiXmlElement("accessor");
  1876. vertsTechNode->LinkEndChild(vertsAccNode);
  1877. vertsAccNode->SetAttribute("source", avar("#%s-mesh-positions-array", colMeshName));
  1878. vertsAccNode->SetAttribute("count", avar("%d", exportData.colMeshes[d].mesh.mPoints.size()));
  1879. vertsAccNode->SetAttribute("stride", "3");
  1880. TiXmlElement* vertsAccXNode = new TiXmlElement("param");
  1881. vertsAccNode->LinkEndChild(vertsAccXNode);
  1882. vertsAccXNode->SetAttribute("name", "X");
  1883. vertsAccXNode->SetAttribute("type", "float");
  1884. TiXmlElement* vertsAccYNode = new TiXmlElement("param");
  1885. vertsAccNode->LinkEndChild(vertsAccYNode);
  1886. vertsAccYNode->SetAttribute("name", "Y");
  1887. vertsAccYNode->SetAttribute("type", "float");
  1888. TiXmlElement* vertsAccZNode = new TiXmlElement("param");
  1889. vertsAccNode->LinkEndChild(vertsAccZNode);
  1890. vertsAccZNode->SetAttribute("name", "Z");
  1891. vertsAccZNode->SetAttribute("type", "float");
  1892. // Save out the normals
  1893. TiXmlElement* normalsSourceNode = new TiXmlElement("source");
  1894. meshNode->LinkEndChild(normalsSourceNode);
  1895. normalsSourceNode->SetAttribute("id", avar("%s-mesh-normals", colMeshName));
  1896. TiXmlElement* normalsNode = new TiXmlElement("float_array");
  1897. normalsSourceNode->LinkEndChild(normalsNode);
  1898. normalsNode->SetAttribute("id", avar("%s-mesh-normals-array", colMeshName));
  1899. normalsNode->SetAttribute("count", avar("%d", exportData.colMeshes[d].mesh.mNormals.size() * 3));
  1900. for (U32 i = 0; i < exportData.colMeshes[d].mesh.mNormals.size(); i++)
  1901. {
  1902. const Point3F& normal = exportData.colMeshes[d].mesh.mNormals[i];
  1903. TiXmlText* normalText = new TiXmlText(avar("%.4f %.4f %.4f ", normal.x, normal.y, normal.z));
  1904. normalsNode->LinkEndChild(normalText);
  1905. }
  1906. // Save the normals accessor
  1907. TiXmlElement* normalsTechNode = new TiXmlElement("technique_common");
  1908. normalsSourceNode->LinkEndChild(normalsTechNode);
  1909. TiXmlElement* normalsAccNode = new TiXmlElement("accessor");
  1910. normalsTechNode->LinkEndChild(normalsAccNode);
  1911. normalsAccNode->SetAttribute("source", avar("#%s-mesh-normals-array", colMeshName));
  1912. normalsAccNode->SetAttribute("count", avar("%d", exportData.colMeshes[d].mesh.mNormals.size()));
  1913. normalsAccNode->SetAttribute("stride", "3");
  1914. TiXmlElement* normalsAccXNode = new TiXmlElement("param");
  1915. normalsAccNode->LinkEndChild(normalsAccXNode);
  1916. normalsAccXNode->SetAttribute("name", "X");
  1917. normalsAccXNode->SetAttribute("type", "float");
  1918. TiXmlElement* normalsAccYNode = new TiXmlElement("param");
  1919. normalsAccNode->LinkEndChild(normalsAccYNode);
  1920. normalsAccYNode->SetAttribute("name", "Y");
  1921. normalsAccYNode->SetAttribute("type", "float");
  1922. TiXmlElement* normalsAccZNode = new TiXmlElement("param");
  1923. normalsAccNode->LinkEndChild(normalsAccZNode);
  1924. normalsAccZNode->SetAttribute("name", "Z");
  1925. normalsAccZNode->SetAttribute("type", "float");
  1926. // Save out the uvs
  1927. TiXmlElement* uv0SourceNode = new TiXmlElement("source");
  1928. meshNode->LinkEndChild(uv0SourceNode);
  1929. uv0SourceNode->SetAttribute("id", avar("%s-mesh-map-0", colMeshName));
  1930. TiXmlElement* uv0Node = new TiXmlElement("float_array");
  1931. uv0SourceNode->LinkEndChild(uv0Node);
  1932. uv0Node->SetAttribute("id", avar("%s-mesh-map-0-array", colMeshName));
  1933. uv0Node->SetAttribute("count", avar("%d", exportData.colMeshes[d].mesh.mUV0s.size() * 2));
  1934. for (U32 i = 0; i < exportData.colMeshes[d].mesh.mUV0s.size(); i++)
  1935. {
  1936. const Point2F& uv0 = exportData.colMeshes[d].mesh.mUV0s[i];
  1937. TiXmlText* uv0Text = new TiXmlText(avar("%.4f %.4f ", uv0.x, 1.0f - uv0.y)); // COLLADA uvs are upside down compared to Torque
  1938. uv0Node->LinkEndChild(uv0Text);
  1939. }
  1940. // Save the uv0 accessor
  1941. TiXmlElement* uv0TechNode = new TiXmlElement("technique_common");
  1942. uv0SourceNode->LinkEndChild(uv0TechNode);
  1943. TiXmlElement* uv0AccNode = new TiXmlElement("accessor");
  1944. uv0TechNode->LinkEndChild(uv0AccNode);
  1945. uv0AccNode->SetAttribute("source", avar("#%s-mesh-map-0-array", colMeshName));
  1946. uv0AccNode->SetAttribute("count", avar("%d", exportData.colMeshes[d].mesh.mUV0s.size()));
  1947. uv0AccNode->SetAttribute("stride", "2");
  1948. TiXmlElement* uv0AccSNode = new TiXmlElement("param");
  1949. uv0AccNode->LinkEndChild(uv0AccSNode);
  1950. uv0AccSNode->SetAttribute("name", "S");
  1951. uv0AccSNode->SetAttribute("type", "float");
  1952. TiXmlElement* uv0AccTNode = new TiXmlElement("param");
  1953. uv0AccNode->LinkEndChild(uv0AccTNode);
  1954. uv0AccTNode->SetAttribute("name", "T");
  1955. uv0AccTNode->SetAttribute("type", "float");
  1956. // Define the vertices position array
  1957. TiXmlElement* verticesNode = new TiXmlElement("vertices");
  1958. meshNode->LinkEndChild(verticesNode);
  1959. verticesNode->SetAttribute("id", avar("%s-mesh-vertices", colMeshName));
  1960. TiXmlElement* verticesInputNode = new TiXmlElement("input");
  1961. verticesNode->LinkEndChild(verticesInputNode);
  1962. verticesInputNode->SetAttribute("semantic", "POSITION");
  1963. verticesInputNode->SetAttribute("source", avar("#%s-mesh-positions", colMeshName));
  1964. Vector<String> mapNames;
  1965. //exportColladaTriangles(meshNode, exportData.detailLevels[d].mesh, lodMeshName, mapNames);
  1966. exportColladaCollisionTriangles(meshNode, exportData, d);
  1967. // Extra info useful for COLLADAMaya importer (OpenCOLLADA)
  1968. TiXmlElement* extraGeoNode = new TiXmlElement("extra");
  1969. libGeomsNode->LinkEndChild(extraGeoNode);
  1970. TiXmlElement* extraGeoNodeTech = new TiXmlElement("technique");
  1971. extraGeoNode->LinkEndChild(extraGeoNodeTech);
  1972. extraGeoNodeTech->SetAttribute("profile", "OpenCOLLADAMaya");
  1973. TiXmlElement* mayaNode2Id = new TiXmlElement("originalMayaNodeId");
  1974. extraGeoNodeTech->LinkEndChild(mayaNode2Id);
  1975. mayaNode2Id->SetAttribute("sid", "originalMayaNodeId");
  1976. TiXmlText* mayaIdMesh = new TiXmlText(avar("%s", colMeshName));
  1977. mayaNode2Id->LinkEndChild(mayaIdMesh);
  1978. TiXmlElement* doubleSidedId = new TiXmlElement("double_sided");
  1979. extraGeoNodeTech->LinkEndChild(doubleSidedId);
  1980. doubleSidedId->SetAttribute("sid", "double_sided");
  1981. TiXmlText* doubleSideIdText = new TiXmlText("1");
  1982. doubleSidedId->LinkEndChild(doubleSideIdText);
  1983. TiXmlElement* paramExtraNode = new TiXmlElement("param");
  1984. extraGeoNodeTech->LinkEndChild(paramExtraNode);
  1985. paramExtraNode->SetAttribute("sid", "colladaId");
  1986. paramExtraNode->SetAttribute("type", "string");
  1987. TiXmlText* mayaParamMesh = new TiXmlText(avar("%s-mesh", colMeshName));
  1988. paramExtraNode->LinkEndChild(mayaParamMesh);
  1989. }
  1990. }
  1991. void ColladaUtils::exportColladaScene(TiXmlElement* rootNode, const String& meshName, const Vector<String>& matNames)
  1992. {
  1993. TiXmlElement* libSceneNode = new TiXmlElement("library_visual_scenes");
  1994. rootNode->LinkEndChild(libSceneNode);
  1995. TiXmlElement* visSceneNode = new TiXmlElement("visual_scene");
  1996. libSceneNode->LinkEndChild(visSceneNode);
  1997. visSceneNode->SetAttribute("id", "RootNode");
  1998. visSceneNode->SetAttribute("name", "RootNode");
  1999. TiXmlElement* nodeNode = new TiXmlElement("node");
  2000. visSceneNode->LinkEndChild(nodeNode);
  2001. nodeNode->SetAttribute("id", avar("%s", meshName.c_str()));
  2002. nodeNode->SetAttribute("name", avar("%s", meshName.c_str()));
  2003. nodeNode->SetAttribute("type", "NODE");
  2004. TiXmlElement* instanceGeomNode = new TiXmlElement("instance_geometry");
  2005. nodeNode->LinkEndChild(instanceGeomNode);
  2006. instanceGeomNode->SetAttribute("url", avar("#%s-mesh", meshName.c_str()));
  2007. instanceGeomNode->SetAttribute("name", avar("%s", meshName.c_str()));
  2008. TiXmlElement* bindMatNode = new TiXmlElement("bind_material");
  2009. instanceGeomNode->LinkEndChild(bindMatNode);
  2010. TiXmlElement* techniqueNode = new TiXmlElement("technique_common");
  2011. bindMatNode->LinkEndChild(techniqueNode);
  2012. // Bind the materials
  2013. for (U32 i = 0; i < matNames.size(); i++)
  2014. {
  2015. TiXmlElement* instMatNode = new TiXmlElement("instance_material");
  2016. techniqueNode->LinkEndChild(instMatNode);
  2017. instMatNode->SetAttribute("symbol", avar("%s-material", matNames[i].c_str()));
  2018. instMatNode->SetAttribute("target", avar("#%s-material", matNames[i].c_str()));
  2019. TiXmlElement* bindVertexNode = new TiXmlElement("bind_vertex_input");
  2020. instMatNode->LinkEndChild(bindVertexNode);
  2021. //bindVertexNode->SetAttribute("semantic", avar("%s-mesh-map-0", meshName.c_str()));
  2022. bindVertexNode->SetAttribute("semantic", "UVMap");
  2023. bindVertexNode->SetAttribute("input_semantic", "TEXCOORD");
  2024. bindVertexNode->SetAttribute("input_set", "0");
  2025. }
  2026. // Extra info useful for COLLADAMax importer (OpenCOLLADA)
  2027. TiXmlElement* extraInsGeoNode = new TiXmlElement("extra");
  2028. nodeNode->LinkEndChild(extraInsGeoNode);
  2029. TiXmlElement* extraInsGeoTechNode = new TiXmlElement("technique");
  2030. extraInsGeoNode->LinkEndChild(extraInsGeoTechNode);
  2031. extraInsGeoTechNode->SetAttribute("profile", "OpenCOLLADA");
  2032. TiXmlElement* castShadowsNode = new TiXmlElement("cast_shadows");
  2033. extraInsGeoTechNode->LinkEndChild(castShadowsNode);
  2034. castShadowsNode->SetAttribute("sid", "cast_shadows");
  2035. castShadowsNode->SetAttribute("type", "bool");
  2036. TiXmlText* castShadowsText = new TiXmlText("1");
  2037. castShadowsNode->LinkEndChild(castShadowsText);
  2038. //-----------------------------
  2039. TiXmlElement* receiveShadowsNode = new TiXmlElement("receive_shadows");
  2040. extraInsGeoTechNode->LinkEndChild(receiveShadowsNode);
  2041. receiveShadowsNode->SetAttribute("sid", "receive_shadows");
  2042. receiveShadowsNode->SetAttribute("type", "bool");
  2043. TiXmlText* receiveShadowsText = new TiXmlText("1");
  2044. receiveShadowsNode->LinkEndChild(receiveShadowsText);
  2045. //-----------------------------
  2046. TiXmlElement* primaryVisibiltyNode = new TiXmlElement("primary_visibility");
  2047. extraInsGeoTechNode->LinkEndChild(primaryVisibiltyNode);
  2048. primaryVisibiltyNode->SetAttribute("sid", "primary_visibility");
  2049. primaryVisibiltyNode->SetAttribute("type", "int");
  2050. TiXmlText* primaryVisibiltyText = new TiXmlText("1");
  2051. primaryVisibiltyNode->LinkEndChild(primaryVisibiltyText);
  2052. //-----------------------------
  2053. TiXmlElement* secondaryVisibilityNode = new TiXmlElement("secondary_visibility");
  2054. extraInsGeoTechNode->LinkEndChild(secondaryVisibilityNode);
  2055. secondaryVisibilityNode->SetAttribute("sid", "secondary_visibility");
  2056. secondaryVisibilityNode->SetAttribute("type", "int");
  2057. TiXmlText* secondaryVisibilityText = new TiXmlText("1");
  2058. secondaryVisibilityNode->LinkEndChild(secondaryVisibilityText);
  2059. // Extra info useful for COLLADAMaya importer (OpenCOLLADA)
  2060. TiXmlElement* extra2InsGeoNode = new TiXmlElement("extra");
  2061. nodeNode->LinkEndChild(extra2InsGeoNode);
  2062. TiXmlElement* extra2InsGeoTechNode = new TiXmlElement("technique");
  2063. extra2InsGeoNode->LinkEndChild(extra2InsGeoTechNode);
  2064. extra2InsGeoTechNode->SetAttribute("profile", "OpenCOLLADAMaya");
  2065. TiXmlElement* mayaNodeId = new TiXmlElement("originalMayaNodeId");
  2066. extra2InsGeoTechNode->LinkEndChild(mayaNodeId);
  2067. mayaNodeId->SetAttribute("sid", "originalMayaNodeId");
  2068. mayaNodeId->SetAttribute("type", "string");
  2069. TiXmlText* mayaNodeIdMesh = new TiXmlText(avar("%s", meshName.c_str()));
  2070. mayaNodeId->LinkEndChild(mayaNodeIdMesh);
  2071. TiXmlElement* paramExtraNode = new TiXmlElement("param");
  2072. extra2InsGeoTechNode->LinkEndChild(paramExtraNode);
  2073. paramExtraNode->SetAttribute("sid", "colladaId");
  2074. paramExtraNode->SetAttribute("type", "string");
  2075. TiXmlText* mayaParamMesh = new TiXmlText(avar("%s", meshName.c_str()));
  2076. paramExtraNode->LinkEndChild(mayaParamMesh);
  2077. //-----------------------------
  2078. TiXmlElement* sceneNode = new TiXmlElement("scene");
  2079. rootNode->LinkEndChild(sceneNode);
  2080. TiXmlElement* instVisSceneNode = new TiXmlElement("instance_visual_scene");
  2081. sceneNode->LinkEndChild(instVisSceneNode);
  2082. instVisSceneNode->SetAttribute("url", "#RootNode");
  2083. }
  2084. void ColladaUtils::exportColladaScene(TiXmlElement* rootNode, const ExportData& exportData, const String& meshName)
  2085. {
  2086. TiXmlElement* libSceneNode = new TiXmlElement("library_visual_scenes");
  2087. rootNode->LinkEndChild(libSceneNode);
  2088. TiXmlElement* visSceneNode = new TiXmlElement("visual_scene");
  2089. libSceneNode->LinkEndChild(visSceneNode);
  2090. visSceneNode->SetAttribute("id", "RootNode");
  2091. visSceneNode->SetAttribute("name", "RootNode");
  2092. for (U32 d = 0; d < exportData.detailLevels.size(); d++)
  2093. {
  2094. char lodMeshName[256];
  2095. dSprintf(lodMeshName, 256, "%s%d", meshName.c_str(), exportData.detailLevels[d].size);
  2096. TiXmlElement* nodeNode = new TiXmlElement("node");
  2097. visSceneNode->LinkEndChild(nodeNode);
  2098. nodeNode->SetAttribute("id", lodMeshName);
  2099. nodeNode->SetAttribute("name", lodMeshName);
  2100. nodeNode->SetAttribute("type", "NODE");
  2101. TiXmlElement* instanceGeomNode = new TiXmlElement("instance_geometry");
  2102. nodeNode->LinkEndChild(instanceGeomNode);
  2103. instanceGeomNode->SetAttribute("url", avar("#%s%d-mesh", meshName.c_str(), exportData.detailLevels[d].size));
  2104. instanceGeomNode->SetAttribute("name", lodMeshName);
  2105. TiXmlElement* bindMatNode = new TiXmlElement("bind_material");
  2106. instanceGeomNode->LinkEndChild(bindMatNode);
  2107. TiXmlElement* techniqueNode = new TiXmlElement("technique_common");
  2108. bindMatNode->LinkEndChild(techniqueNode);
  2109. // Bind the materials
  2110. for (U32 i = 0; i < exportData.detailLevels[d].materialRefList.size(); i++)
  2111. {
  2112. int matIdx;
  2113. exportData.detailLevels[d].materialRefList.tryGetValue(i, matIdx);
  2114. BaseMatInstance* baseInst = exportData.materials[matIdx];
  2115. Material* mat = dynamic_cast<Material*>(baseInst->getMaterial());
  2116. if (!mat)
  2117. continue;
  2118. String matName;
  2119. if (mat->getName() && mat->getName()[0])
  2120. matName = mat->mMapTo;
  2121. TiXmlElement* instMatNode = new TiXmlElement("instance_material");
  2122. techniqueNode->LinkEndChild(instMatNode);
  2123. instMatNode->SetAttribute("symbol", avar("%s-material", matName.c_str()));
  2124. instMatNode->SetAttribute("target", avar("#%s-material", matName.c_str()));
  2125. TiXmlElement* bindVertexNode = new TiXmlElement("bind_vertex_input");
  2126. instMatNode->LinkEndChild(bindVertexNode);
  2127. //bindVertexNode->SetAttribute("semantic", avar("%s-mesh-map-0", meshName.c_str()));
  2128. bindVertexNode->SetAttribute("semantic", "UVMap");
  2129. bindVertexNode->SetAttribute("input_semantic", "TEXCOORD");
  2130. bindVertexNode->SetAttribute("input_set", "0");
  2131. }
  2132. // Extra info useful for COLLADAMax importer (OpenCOLLADA)
  2133. TiXmlElement* extraInsGeoNode = new TiXmlElement("extra");
  2134. nodeNode->LinkEndChild(extraInsGeoNode);
  2135. TiXmlElement* extraInsGeoTechNode = new TiXmlElement("technique");
  2136. extraInsGeoNode->LinkEndChild(extraInsGeoTechNode);
  2137. extraInsGeoTechNode->SetAttribute("profile", "OpenCOLLADA");
  2138. TiXmlElement* castShadowsNode = new TiXmlElement("cast_shadows");
  2139. extraInsGeoTechNode->LinkEndChild(castShadowsNode);
  2140. castShadowsNode->SetAttribute("sid", "cast_shadows");
  2141. castShadowsNode->SetAttribute("type", "bool");
  2142. TiXmlText* castShadowsText = new TiXmlText("1");
  2143. castShadowsNode->LinkEndChild(castShadowsText);
  2144. //-----------------------------
  2145. TiXmlElement* receiveShadowsNode = new TiXmlElement("receive_shadows");
  2146. extraInsGeoTechNode->LinkEndChild(receiveShadowsNode);
  2147. receiveShadowsNode->SetAttribute("sid", "receive_shadows");
  2148. receiveShadowsNode->SetAttribute("type", "bool");
  2149. TiXmlText* receiveShadowsText = new TiXmlText("1");
  2150. receiveShadowsNode->LinkEndChild(receiveShadowsText);
  2151. //-----------------------------
  2152. TiXmlElement* primaryVisibiltyNode = new TiXmlElement("primary_visibility");
  2153. extraInsGeoTechNode->LinkEndChild(primaryVisibiltyNode);
  2154. primaryVisibiltyNode->SetAttribute("sid", "primary_visibility");
  2155. primaryVisibiltyNode->SetAttribute("type", "int");
  2156. TiXmlText* primaryVisibiltyText = new TiXmlText("1");
  2157. primaryVisibiltyNode->LinkEndChild(primaryVisibiltyText);
  2158. //-----------------------------
  2159. TiXmlElement* secondaryVisibilityNode = new TiXmlElement("secondary_visibility");
  2160. extraInsGeoTechNode->LinkEndChild(secondaryVisibilityNode);
  2161. secondaryVisibilityNode->SetAttribute("sid", "secondary_visibility");
  2162. secondaryVisibilityNode->SetAttribute("type", "int");
  2163. TiXmlText* secondaryVisibilityText = new TiXmlText("1");
  2164. secondaryVisibilityNode->LinkEndChild(secondaryVisibilityText);
  2165. // Extra info useful for COLLADAMaya importer (OpenCOLLADA)
  2166. TiXmlElement* extra2InsGeoNode = new TiXmlElement("extra");
  2167. nodeNode->LinkEndChild(extra2InsGeoNode);
  2168. TiXmlElement* extra2InsGeoTechNode = new TiXmlElement("technique");
  2169. extra2InsGeoNode->LinkEndChild(extra2InsGeoTechNode);
  2170. extra2InsGeoTechNode->SetAttribute("profile", "OpenCOLLADAMaya");
  2171. TiXmlElement* mayaNodeId = new TiXmlElement("originalMayaNodeId");
  2172. extra2InsGeoTechNode->LinkEndChild(mayaNodeId);
  2173. mayaNodeId->SetAttribute("sid", "originalMayaNodeId");
  2174. mayaNodeId->SetAttribute("type", "string");
  2175. TiXmlText* mayaNodeIdMesh = new TiXmlText(lodMeshName);
  2176. mayaNodeId->LinkEndChild(mayaNodeIdMesh);
  2177. TiXmlElement* paramExtraNode = new TiXmlElement("param");
  2178. extra2InsGeoTechNode->LinkEndChild(paramExtraNode);
  2179. paramExtraNode->SetAttribute("sid", "colladaId");
  2180. paramExtraNode->SetAttribute("type", "string");
  2181. TiXmlText* mayaParamMesh = new TiXmlText(lodMeshName);
  2182. paramExtraNode->LinkEndChild(mayaParamMesh);
  2183. }
  2184. //Collisions
  2185. for (U32 d = 0; d < exportData.colMeshes.size(); d++)
  2186. {
  2187. const char* colMeshName = exportData.colMeshes[d].colMeshName;
  2188. TiXmlElement* nodeNode = new TiXmlElement("node");
  2189. visSceneNode->LinkEndChild(nodeNode);
  2190. nodeNode->SetAttribute("id", colMeshName);
  2191. nodeNode->SetAttribute("name", colMeshName);
  2192. nodeNode->SetAttribute("type", "NODE");
  2193. TiXmlElement* instanceGeomNode = new TiXmlElement("instance_geometry");
  2194. nodeNode->LinkEndChild(instanceGeomNode);
  2195. instanceGeomNode->SetAttribute("url", avar("#%s-mesh", colMeshName));
  2196. instanceGeomNode->SetAttribute("name", colMeshName);
  2197. TiXmlElement* bindMatNode = new TiXmlElement("bind_material");
  2198. instanceGeomNode->LinkEndChild(bindMatNode);
  2199. TiXmlElement* techniqueNode = new TiXmlElement("technique_common");
  2200. bindMatNode->LinkEndChild(techniqueNode);
  2201. TiXmlElement* instMatNode = new TiXmlElement("instance_material");
  2202. techniqueNode->LinkEndChild(instMatNode);
  2203. instMatNode->SetAttribute("symbol", avar("%s-material", colMeshName));
  2204. instMatNode->SetAttribute("target", avar("#%s-material", colMeshName));
  2205. TiXmlElement* bindVertexNode = new TiXmlElement("bind_vertex_input");
  2206. instMatNode->LinkEndChild(bindVertexNode);
  2207. //bindVertexNode->SetAttribute("semantic", avar("%s-mesh-map-0", meshName.c_str()));
  2208. bindVertexNode->SetAttribute("semantic", "UVMap");
  2209. bindVertexNode->SetAttribute("input_semantic", "TEXCOORD");
  2210. bindVertexNode->SetAttribute("input_set", "0");
  2211. // Extra info useful for COLLADAMax importer (OpenCOLLADA)
  2212. TiXmlElement* extraInsGeoNode = new TiXmlElement("extra");
  2213. nodeNode->LinkEndChild(extraInsGeoNode);
  2214. TiXmlElement* extraInsGeoTechNode = new TiXmlElement("technique");
  2215. extraInsGeoNode->LinkEndChild(extraInsGeoTechNode);
  2216. extraInsGeoTechNode->SetAttribute("profile", "OpenCOLLADA");
  2217. TiXmlElement* castShadowsNode = new TiXmlElement("cast_shadows");
  2218. extraInsGeoTechNode->LinkEndChild(castShadowsNode);
  2219. castShadowsNode->SetAttribute("sid", "cast_shadows");
  2220. castShadowsNode->SetAttribute("type", "bool");
  2221. TiXmlText* castShadowsText = new TiXmlText("1");
  2222. castShadowsNode->LinkEndChild(castShadowsText);
  2223. //-----------------------------
  2224. TiXmlElement* receiveShadowsNode = new TiXmlElement("receive_shadows");
  2225. extraInsGeoTechNode->LinkEndChild(receiveShadowsNode);
  2226. receiveShadowsNode->SetAttribute("sid", "receive_shadows");
  2227. receiveShadowsNode->SetAttribute("type", "bool");
  2228. TiXmlText* receiveShadowsText = new TiXmlText("1");
  2229. receiveShadowsNode->LinkEndChild(receiveShadowsText);
  2230. //-----------------------------
  2231. TiXmlElement* primaryVisibiltyNode = new TiXmlElement("primary_visibility");
  2232. extraInsGeoTechNode->LinkEndChild(primaryVisibiltyNode);
  2233. primaryVisibiltyNode->SetAttribute("sid", "primary_visibility");
  2234. primaryVisibiltyNode->SetAttribute("type", "int");
  2235. TiXmlText* primaryVisibiltyText = new TiXmlText("1");
  2236. primaryVisibiltyNode->LinkEndChild(primaryVisibiltyText);
  2237. //-----------------------------
  2238. TiXmlElement* secondaryVisibilityNode = new TiXmlElement("secondary_visibility");
  2239. extraInsGeoTechNode->LinkEndChild(secondaryVisibilityNode);
  2240. secondaryVisibilityNode->SetAttribute("sid", "secondary_visibility");
  2241. secondaryVisibilityNode->SetAttribute("type", "int");
  2242. TiXmlText* secondaryVisibilityText = new TiXmlText("1");
  2243. secondaryVisibilityNode->LinkEndChild(secondaryVisibilityText);
  2244. // Extra info useful for COLLADAMaya importer (OpenCOLLADA)
  2245. TiXmlElement* extra2InsGeoNode = new TiXmlElement("extra");
  2246. nodeNode->LinkEndChild(extra2InsGeoNode);
  2247. TiXmlElement* extra2InsGeoTechNode = new TiXmlElement("technique");
  2248. extra2InsGeoNode->LinkEndChild(extra2InsGeoTechNode);
  2249. extra2InsGeoTechNode->SetAttribute("profile", "OpenCOLLADAMaya");
  2250. TiXmlElement* mayaNodeId = new TiXmlElement("originalMayaNodeId");
  2251. extra2InsGeoTechNode->LinkEndChild(mayaNodeId);
  2252. mayaNodeId->SetAttribute("sid", "originalMayaNodeId");
  2253. mayaNodeId->SetAttribute("type", "string");
  2254. TiXmlText* mayaNodeIdMesh = new TiXmlText(colMeshName);
  2255. mayaNodeId->LinkEndChild(mayaNodeIdMesh);
  2256. TiXmlElement* paramExtraNode = new TiXmlElement("param");
  2257. extra2InsGeoTechNode->LinkEndChild(paramExtraNode);
  2258. paramExtraNode->SetAttribute("sid", "colladaId");
  2259. paramExtraNode->SetAttribute("type", "string");
  2260. TiXmlText* mayaParamMesh = new TiXmlText(colMeshName);
  2261. paramExtraNode->LinkEndChild(mayaParamMesh);
  2262. }
  2263. //-----------------------------
  2264. TiXmlElement* sceneNode = new TiXmlElement("scene");
  2265. rootNode->LinkEndChild(sceneNode);
  2266. TiXmlElement* instVisSceneNode = new TiXmlElement("instance_visual_scene");
  2267. sceneNode->LinkEndChild(instVisSceneNode);
  2268. instVisSceneNode->SetAttribute("url", "#RootNode");
  2269. }
  2270. void ColladaUtils::exportToCollada(const Torque::Path& colladaFile, const OptimizedPolyList& mesh, const String& meshName)
  2271. {
  2272. // Get the mesh name
  2273. String outMeshName = meshName;
  2274. if (outMeshName.isEmpty())
  2275. outMeshName = colladaFile.getFileName();
  2276. // The XML document that will hold all of our data
  2277. TiXmlDocument doc;
  2278. // Add a standard XML declaration to the top
  2279. TiXmlDeclaration* xmlDecl = new TiXmlDeclaration("1.0", "utf-8", "");
  2280. doc.LinkEndChild(xmlDecl);
  2281. // Create our Collada root node and populate a couple standard attributes
  2282. TiXmlElement* rootNode = new TiXmlElement("COLLADA");
  2283. rootNode->SetAttribute("xmlns", "http://www.collada.org/2005/11/COLLADASchema");
  2284. rootNode->SetAttribute("version", "1.4.1");
  2285. //rootNode->SetAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); //T3D Collada loader complaint about this.
  2286. // Add the root node to the document
  2287. doc.LinkEndChild(rootNode);
  2288. // Save out our header info
  2289. exportColladaHeader(rootNode);
  2290. // Save out the materials
  2291. Vector<String> mapNames;
  2292. exportColladaMaterials(rootNode, mesh, mapNames, colladaFile);
  2293. S32 suffix;
  2294. String baseMeshName = String::GetTrailingNumber(outMeshName, suffix);
  2295. // Save out our geometry
  2296. exportColladaMesh(rootNode, mesh, baseMeshName, mapNames);
  2297. // Save out our scene nodes
  2298. exportColladaScene(rootNode, baseMeshName, mapNames);
  2299. // Write out the actual Collada file
  2300. char fullPath[MAX_PATH_LENGTH];
  2301. Platform::makeFullPathName(colladaFile.getFullPath(), fullPath, MAX_PATH_LENGTH);
  2302. if (!doc.SaveFile(fullPath))
  2303. Con::errorf("ColladaUtils::exportToCollada(): Unable to export to %s", fullPath);
  2304. }
  2305. void ColladaUtils::exportToCollada(const Torque::Path& colladaFile, const ExportData& exportData)
  2306. {
  2307. // Get the mesh name
  2308. String outMeshName = colladaFile.getFileName();
  2309. // The XML document that will hold all of our data
  2310. TiXmlDocument doc;
  2311. // Add a standard XML declaration to the top
  2312. TiXmlDeclaration* xmlDecl = new TiXmlDeclaration("1.0", "utf-8", "");
  2313. doc.LinkEndChild(xmlDecl);
  2314. // Create our Collada root node and populate a couple standard attributes
  2315. TiXmlElement* rootNode = new TiXmlElement("COLLADA");
  2316. rootNode->SetAttribute("xmlns", "http://www.collada.org/2005/11/COLLADASchema");
  2317. rootNode->SetAttribute("version", "1.4.1");
  2318. //rootNode->SetAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); //T3D Collada loader complaint about this.
  2319. // Add the root node to the document
  2320. doc.LinkEndChild(rootNode);
  2321. // Save out our header info
  2322. exportColladaHeader(rootNode);
  2323. // Save out the materials
  2324. Vector<String> mapNames;
  2325. exportColladaMaterials(rootNode, exportData, colladaFile);
  2326. S32 suffix;
  2327. String baseMeshName = String::GetTrailingNumber(outMeshName, suffix);
  2328. // Save out our geometry
  2329. exportColladaMesh(rootNode, exportData, baseMeshName);
  2330. // Save out our scene nodes
  2331. exportColladaScene(rootNode, exportData, baseMeshName);
  2332. // Write out the actual Collada file
  2333. char fullPath[MAX_PATH_LENGTH];
  2334. Platform::makeFullPathName(colladaFile.getFullPath(), fullPath, MAX_PATH_LENGTH);
  2335. if (!doc.SaveFile(fullPath))
  2336. Con::errorf("ColladaUtils::exportToCollada(): Unable to export to %s", fullPath);
  2337. }
  2338. void ColladaUtils::ExportData::processData()
  2339. {
  2340. //This pref dictates if we 'backfill' lower LODs with higher ones if any given mesh being exported lacks that level.
  2341. //For example, if there are 2 meshes, and one has 500, 200, 100 and the other has 500 and 200 - if this setting is on, the second mesh
  2342. //will backfill the 200 to the 100 so it has all levels filled. If it's off, the second mesh will not render at the 100 level
  2343. bool fillLowDetailLevels = dAtob(Con::getVariable("$exportMesh::fillLowDetailLevels", "1"));
  2344. S32 numDetailLevels = numberOfDetailLevels();
  2345. detailLevels.clear();
  2346. detailLevels.setSize(numDetailLevels);
  2347. for (U32 meshNum = 0; meshNum < meshData.size(); ++meshNum)
  2348. {
  2349. for (U32 i = 0; i < numDetailLevels; ++i)
  2350. {
  2351. //Get our target size
  2352. S32 targetDetailLevelSize = getDetailLevelSize(i);
  2353. //alright, step through each meshdata and propagate the polyList info 'up' to fill
  2354. detailLevel* curDetail = &detailLevels[i];
  2355. curDetail->size = targetDetailLevelSize;
  2356. //Do we have a detail level for this?
  2357. S32 detailLevelIdx = -1;
  2358. for (S32 mdl = i; mdl >= 0; mdl--)
  2359. {
  2360. //walk backwards as needed to find our first valid detail level for this mesh. if we find none, just move on
  2361. S32 testDetailLevelSize = getDetailLevelSize(mdl);
  2362. detailLevelIdx = meshData[meshNum].hasDetailLevel(testDetailLevelSize);
  2363. if (detailLevelIdx != -1)
  2364. break;
  2365. }
  2366. if (detailLevelIdx == -1)
  2367. {
  2368. //found nothing backwards, so lets check if we're configured to back-fill the first detail levels
  2369. if (fillLowDetailLevels)
  2370. {
  2371. //if so, search forward, find the first valid detail and fill it in
  2372. for (S32 mdl = 0; mdl < numDetailLevels; mdl++)
  2373. {
  2374. //walk backwards as needed to find our first valid detail level for this mesh. if we find none, just move on
  2375. S32 testDetailLevelSize = getDetailLevelSize(mdl);
  2376. detailLevelIdx = meshData[meshNum].hasDetailLevel(testDetailLevelSize);
  2377. if (detailLevelIdx != -1)
  2378. break;
  2379. }
  2380. }
  2381. }
  2382. //If we found the detail level index, go ahead and build out the data for it
  2383. if (detailLevelIdx != -1)
  2384. {
  2385. curDetail->mesh.setTransform(&meshData[meshNum].meshTransform, meshData[meshNum].scale);
  2386. curDetail->mesh.setObject(meshData[meshNum].originatingObject);
  2387. if (meshData[meshNum].shapeInst != nullptr)
  2388. {
  2389. if (!meshData[meshNum].shapeInst->buildPolyList(&curDetail->mesh, detailLevelIdx))
  2390. {
  2391. Con::errorf("TSStatic::buildExportPolyList - failed to build polylist for LOD %i", i);
  2392. continue;
  2393. }
  2394. }
  2395. else
  2396. {
  2397. //special handling classes
  2398. ConvexShape* convexShp = dynamic_cast<ConvexShape*>(meshData[meshNum].originatingObject);
  2399. if (convexShp != nullptr)
  2400. {
  2401. if (!convexShp->buildPolyList(PLC_Export, &curDetail->mesh, meshData[meshNum].originatingObject->getWorldBox(), meshData[meshNum].originatingObject->getWorldSphere()))
  2402. {
  2403. Con::errorf("TSStatic::buildExportPolyList - failed to build ConvexShape polylist for LOD %i", i);
  2404. continue;
  2405. }
  2406. }
  2407. }
  2408. //lastly, get material
  2409. for (U32 matNum = 0; matNum < curDetail->mesh.mMaterialList.size(); matNum++)
  2410. {
  2411. S32 matIdx = hasMaterialInstance(curDetail->mesh.mMaterialList[matNum]);
  2412. if (matIdx == -1)
  2413. {
  2414. //cool, haven't already got this material, so lets store it out
  2415. materials.push_back(curDetail->mesh.mMaterialList[matNum]);
  2416. curDetail->materialRefList.insert(matNum, materials.size() - 1);
  2417. }
  2418. else
  2419. {
  2420. curDetail->materialRefList.insert(matNum, matIdx);
  2421. }
  2422. }
  2423. }
  2424. }
  2425. }
  2426. }