msl.cpp 73 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399
  1. //-------------------------------------------------------------------------------
  2. //
  3. // Multiple TG Shape Layer
  4. //
  5. //---------------------------------------------------------------------------//
  6. // Copyright (C) Microsoft Corporation. All rights reserved. //
  7. //===========================================================================//
  8. // Replace MLR for a myriad number of reasons.
  9. //
  10. // Started 4/16/99
  11. //
  12. // FFS
  13. //
  14. //-------------------------------------------------------------------------------
  15. //-------------------------------------------------------------------------------
  16. // Include Files
  17. #ifndef MSL_H
  18. #include "msl.h"
  19. #endif
  20. #ifndef CIDENT_H
  21. #include "cident.h"
  22. #endif
  23. #ifndef PATHS_H
  24. #include "paths.h"
  25. #endif
  26. #ifndef MATHFUNC_H
  27. #include "mathfunc.h"
  28. #endif
  29. #ifndef CAMERA_H
  30. #include "camera.h"
  31. #endif
  32. #ifndef CELINE_H
  33. #include "celine.h"
  34. #endif
  35. #ifndef DBASEGUI_H
  36. #include "dbasegui.h"
  37. #endif
  38. #ifndef TIMING_H
  39. #include "timing.h"
  40. #endif
  41. #include <toolOS.hpp>
  42. #include "../ARM/Microsoft.Xna.Arm.h"
  43. using namespace Microsoft::Xna::Arm;
  44. //-------------------------------------------------------------------------------
  45. extern void GetNumberData (char *rawData, char *result);
  46. extern void GetNameData (char *rawData, char *result);
  47. extern void GetWordData (char *rawData, char *result);
  48. extern long ObjectTextureSize;
  49. #define CURRENT_SHAPE_VERSION 0xBAFDECAF
  50. #define CURRENT_ANIM_VERSION 0xBADDECAF
  51. #define MAX_PATH 256
  52. //-------------------------------------------------------------------------------
  53. void GetNextLine (char *rawData, char *result)
  54. {
  55. long startIndex = 0;
  56. long endIndex = 0;
  57. while ( (rawData[startIndex] != '\n') )
  58. {
  59. startIndex++;
  60. }
  61. startIndex++;
  62. endIndex = startIndex;
  63. while ( (rawData[endIndex] != '\n') )
  64. {
  65. endIndex++;
  66. }
  67. strncpy(result,&rawData[startIndex],endIndex - startIndex);
  68. result[endIndex-startIndex] = 0;
  69. }
  70. //-------------------------------------------------------------------------------
  71. bool useSlerping = false;
  72. extern bool useVertexLighting;
  73. extern bool useFaceLighting;
  74. bool useShadows = true;
  75. extern bool silentMode; //Used for automated builds to keep errors from popping up.
  76. //-------------------------------------------------------------------------------
  77. // TG_TypeMultiShape
  78. void *TG_TypeMultiShape::operator new (size_t mySize)
  79. {
  80. void *result = TG_Shape::tglHeap->Malloc(mySize);
  81. return result;
  82. }
  83. //-------------------------------------------------------------------------------
  84. void TG_TypeMultiShape::operator delete (void *us)
  85. {
  86. TG_Shape::tglHeap->Free(us);
  87. }
  88. //-------------------------------------------------------------------------------
  89. // TG_MultiShape & TG_TypeMultiShape
  90. //This function copies the entire multi-shape to the new pointer.
  91. //It does malloc and the newShape is a completely independant copy
  92. //That must be destroyed or memory will leak!
  93. TG_MultiShapePtr TG_TypeMultiShape::CreateFrom (void)
  94. {
  95. TG_MultiShapePtr newShape = NULL;
  96. newShape = new TG_MultiShape;
  97. gosASSERT(newShape != NULL);
  98. #ifdef _DEBUG
  99. if (numTG_TypeShapes == 0)
  100. STOP(("Tried to create a shape with no data Named %s",shapeName));
  101. #endif
  102. //listOfShapes
  103. newShape->numTG_Shapes = numTG_TypeShapes;
  104. newShape->listOfShapes = (TG_ShapeRecPtr)TG_Shape::tglHeap->Malloc(sizeof(TG_ShapeRec) * numTG_TypeShapes);
  105. gosASSERT(newShape->listOfShapes != NULL);
  106. memset(newShape->listOfShapes,0,sizeof(TG_ShapeRec) * numTG_TypeShapes);
  107. for (long i=0;i<numTG_TypeShapes;i++)
  108. {
  109. newShape->listOfShapes[i].node = listOfTypeShapes[i]->CreateFrom();
  110. }
  111. //Setup Heirarchy again because pointers are not valid!
  112. for (i=0;i<numTG_TypeShapes;i++)
  113. {
  114. newShape->listOfShapes[i].parentNode = NULL;
  115. newShape->listOfShapes[i].currentAnimation = NULL;
  116. newShape->listOfShapes[i].shapeToWorld = Stuff::LinearMatrix4D::Identity;
  117. newShape->listOfShapes[i].worldToShape = Stuff::LinearMatrix4D::Identity;
  118. newShape->listOfShapes[i].calcedThisFrame = -1;
  119. newShape->listOfShapes[i].processMe = true;
  120. newShape->listOfShapes[i].baseRotation.w = 1.0f;
  121. newShape->listOfShapes[i].baseRotation.x =
  122. newShape->listOfShapes[i].baseRotation.y =
  123. newShape->listOfShapes[i].baseRotation.z = 0.0f;
  124. //----------------------------------------------------------------------------------
  125. // For each shape, look for another node whose NodeId matches this shape's parentId
  126. for (long j=0;j<numTG_TypeShapes;j++)
  127. {
  128. if (strcmp(newShape->listOfShapes[i].node->myType->getParentId(),newShape->listOfShapes[j].node->myType->getNodeId()) == 0)
  129. {
  130. //-------------------------------
  131. // Found it!
  132. newShape->listOfShapes[i].parentNode = &(newShape->listOfShapes[j]);
  133. break;
  134. }
  135. }
  136. //----------------------------------------------------------------------------
  137. // Do NOT need to reset nodeCenters as they are correct for each node copied!
  138. }
  139. newShape->frameNum = 0.0f;
  140. newShape->myMultiType = this;
  141. newShape->isHudElement = false;
  142. return newShape;
  143. }
  144. //-------------------------------------------------------------------------------
  145. long TG_TypeMultiShape::LoadBinaryCopy (char *fileName)
  146. {
  147. File binFile;
  148. long result = binFile.open(fileName);
  149. if (result != NO_ERR)
  150. return -1;
  151. DWORD version = binFile.readLong();
  152. if (version == CURRENT_SHAPE_VERSION)
  153. {
  154. numTG_TypeShapes = binFile.readLong();
  155. numTextures = binFile.readLong();
  156. //ListOfTextures
  157. if (numTextures)
  158. {
  159. listOfTextures = (TG_TexturePtr)TG_Shape::tglHeap->Malloc(sizeof(TG_Texture) * numTextures);
  160. gosASSERT(listOfTextures != NULL);
  161. binFile.read((MemoryPtr)listOfTextures,sizeof(TG_Texture) * numTextures);
  162. }
  163. else
  164. {
  165. listOfTextures = NULL;
  166. }
  167. //listOfShapes
  168. listOfTypeShapes = (TG_TypeNodePtr *)TG_Shape::tglHeap->Malloc(sizeof(TG_TypeNodePtr) * numTG_TypeShapes);
  169. gosASSERT(listOfTypeShapes != NULL);
  170. memset(listOfTypeShapes,0,sizeof(TG_TypeNodePtr) * numTG_TypeShapes);
  171. for (long i=0;i<numTG_TypeShapes;i++)
  172. {
  173. long nodeType = binFile.readLong();
  174. if (nodeType == SHAPE_NODE)
  175. {
  176. listOfTypeShapes[i] = new TG_TypeShape;
  177. listOfTypeShapes[i]->init();
  178. listOfTypeShapes[i]->LoadBinaryCopy(binFile);
  179. }
  180. else if (nodeType == TYPE_NODE)
  181. {
  182. listOfTypeShapes[i] = new TG_TypeNode;
  183. listOfTypeShapes[i]->init();
  184. listOfTypeShapes[i]->LoadBinaryCopy(binFile);
  185. }
  186. }
  187. //Setup Heirarchy again because pointers are not valid!
  188. for (i=0;i<numTG_TypeShapes;i++)
  189. {
  190. //----------------------------------------------------------------------------
  191. // Do NOT need to reset nodeCenters as they are correct for each node copied!
  192. //--------------------------------------------------------
  193. //ONLY use nodes which are not spotlight or _PAB or LOS_
  194. if ((strnicmp(listOfTypeShapes[i]->getNodeId(),"_PAB",4) != 0) &&
  195. (strnicmp(listOfTypeShapes[i]->getNodeId(),"LOS_",4) != 0) &&
  196. (strnicmp(listOfTypeShapes[i]->getNodeId(),"SpotLight",9) != 0))
  197. {
  198. //------------------------------------------------------------------
  199. // Scan list of vertices and create minBox, maxBox and extentRadius
  200. for (long j=0;j<listOfTypeShapes[i]->GetNumTypeVertices();j++)
  201. {
  202. Stuff::Vector3D relNodeCenter;
  203. relNodeCenter = listOfTypeShapes[i]->GetRelativeNodeCenter();
  204. TG_TypeShapePtr typeShape = (TG_TypeShapePtr)listOfTypeShapes[i];
  205. if (minBox.x > typeShape->listOfTypeVertices[j].position.x + relNodeCenter.x)
  206. minBox.x = typeShape->listOfTypeVertices[j].position.x + relNodeCenter.x;
  207. if (maxBox.x < typeShape->listOfTypeVertices[j].position.x + relNodeCenter.x)
  208. maxBox.x = typeShape->listOfTypeVertices[j].position.x + relNodeCenter.x;
  209. if (minBox.y > typeShape->listOfTypeVertices[j].position.y + relNodeCenter.y)
  210. minBox.y = typeShape->listOfTypeVertices[j].position.y + relNodeCenter.y;
  211. if (maxBox.y < typeShape->listOfTypeVertices[j].position.y + relNodeCenter.y)
  212. maxBox.y = typeShape->listOfTypeVertices[j].position.y + relNodeCenter.y;
  213. if (minBox.z > typeShape->listOfTypeVertices[j].position.z + relNodeCenter.z)
  214. minBox.z = typeShape->listOfTypeVertices[j].position.z + relNodeCenter.z;
  215. if (maxBox.z < typeShape->listOfTypeVertices[j].position.z + relNodeCenter.z)
  216. maxBox.z = typeShape->listOfTypeVertices[j].position.z + relNodeCenter.z;
  217. }
  218. }
  219. }
  220. float minBoxLength = minBox.GetLength();
  221. float maxBoxLength = maxBox.GetLength();
  222. if (minBoxLength > extentRadius)
  223. extentRadius = minBoxLength;
  224. if (maxBoxLength > extentRadius)
  225. extentRadius = maxBoxLength;
  226. }
  227. else
  228. {
  229. return -1;
  230. }
  231. return 0;
  232. }
  233. //-------------------------------------------------------------------------------
  234. void TG_TypeMultiShape::SaveBinaryCopy (char *fileName)
  235. {
  236. File binFile;
  237. binFile.create(fileName);
  238. binFile.writeLong(CURRENT_SHAPE_VERSION);
  239. binFile.writeLong(numTG_TypeShapes);
  240. binFile.writeLong(numTextures);
  241. //ListOfTextures
  242. if (numTextures)
  243. {
  244. binFile.write((MemoryPtr)listOfTextures,sizeof(TG_Texture) * numTextures);
  245. }
  246. //listOfShapes
  247. for (long i=0;i<numTG_TypeShapes;i++)
  248. {
  249. listOfTypeShapes[i]->SaveBinaryCopy(binFile);
  250. }
  251. }
  252. //-------------------------------------------------------------------------------
  253. void TG_TypeMultiShape::destroy (void)
  254. {
  255. for (long i=0;i<numTG_TypeShapes;i++)
  256. {
  257. if (listOfTypeShapes[i])
  258. {
  259. listOfTypeShapes[i]->destroy();
  260. delete listOfTypeShapes[i];
  261. listOfTypeShapes[i] = NULL;
  262. }
  263. }
  264. if (listOfTypeShapes)
  265. TG_Shape::tglHeap->Free(listOfTypeShapes);
  266. listOfTypeShapes = NULL;
  267. if (listOfTextures)
  268. TG_Shape::tglHeap->Free(listOfTextures);
  269. listOfTextures= NULL;
  270. numTextures = 0;
  271. numTG_TypeShapes = 0;
  272. #ifdef _DEBUG
  273. if (shapeName)
  274. {
  275. free(shapeName);
  276. shapeName = NULL;
  277. }
  278. #endif
  279. }
  280. //-------------------------------------------------------------------------------
  281. void TG_MultiShape::destroy (void)
  282. {
  283. for (long i=0;i<numTG_Shapes;i++)
  284. {
  285. if (listOfShapes[i].node)
  286. {
  287. listOfShapes[i].node->destroy();
  288. TG_Shape::tglHeap->Free(listOfShapes[i].node);
  289. }
  290. }
  291. if (listOfShapes)
  292. TG_Shape::tglHeap->Free(listOfShapes);
  293. listOfShapes = NULL;
  294. numTG_Shapes = 0;
  295. }
  296. //-------------------------------------------------------------------------------
  297. //Function returns 0 if OK. -1 if file not found or file not ASE Format.
  298. //Function runs through each piece of ASE file and creates a separate
  299. //TG_Shape for each one. First pass is count number of GEOMOBJECTS.
  300. //Second pass is load each one.
  301. long TG_TypeMultiShape::LoadTGMultiShapeFromASE (char *fileName, bool forceMakeBinary, IProviderEngine* armProvider)
  302. {
  303. //-----------------------------------------------------
  304. // Fully loads and parses an ASE File. These files are
  305. // output by 3D Studio MAX's ASCII Scene Exporter.
  306. //------------------------------------------------------
  307. // New! Checks for Binary file to load instead.
  308. //
  309. // If Binary is older or equal to ASE, re-parses ASE and
  310. // saves binary.
  311. //
  312. // If Binary does not exist, does the above, too!
  313. //
  314. // If Binary exists and is newer, just loads that.
  315. // MUCH FASTER!
  316. //
  317. bool makeBinary = false;
  318. char drive[MAX_PATH];
  319. char dir[MAX_PATH];
  320. char name[MAX_PATH];
  321. char ext[MAX_PATH];
  322. _splitpath(fileName,drive,dir,name,ext);
  323. #ifdef _DEBUG
  324. shapeName = (char *)malloc(strlen(name) + 1);
  325. strcpy(shapeName,name);
  326. #endif
  327. FullPathFileName binaryFileName;
  328. binaryFileName.init(tglPath,name,".tgl");
  329. //Load Table is as follows:
  330. // ASE TGL FST Result:
  331. // 0 0 0 STOP
  332. // 0 0 1 OK to load if Shape version good, STOp Otherwise
  333. // 0 1 0 Same as above
  334. // 0 1 1 Same as above
  335. // 1 0 0 Set MakeBinary true.
  336. // 1 0 1 Set MakeBinary true.
  337. // 1 1 0 If TGL older then ase, set Make Bindary true.
  338. // 1 1 1 Same as above.
  339. if( !forceMakeBinary)
  340. {
  341. if (!fileExists(fileName) && !fileExists(binaryFileName)) //Line 0
  342. {
  343. #ifdef _DEBUG
  344. // if (!silentMode)
  345. // PAUSE(("Unable to locate shape data for %s. No ASE or TGL File",fileName));
  346. #endif
  347. makeBinary = true;
  348. }
  349. else if (!fileExists(fileName) && fileExists(binaryFileName)) //Line 1-3
  350. {
  351. File binFile;
  352. long result = binFile.open(binaryFileName);
  353. if (result != NO_ERR)
  354. {
  355. if (!silentMode)
  356. STOP(("Unable to locate shape data for %s. TGL File BAD Format",fileName));
  357. }
  358. else
  359. {
  360. long versionId = binFile.readLong();
  361. if (versionId != CURRENT_SHAPE_VERSION)
  362. {
  363. if (!silentMode)
  364. STOP(("Unable to locate shape data for %s. TGL File BAD Format",fileName));
  365. }
  366. }
  367. }
  368. else if (fileExists(fileName) && (!fileExists(binaryFileName) || (fileExists(binaryFileName) == 2))) //Line 4-5
  369. {
  370. makeBinary = true;
  371. }
  372. else if (fileExists(fileName) && ((fileExists(binaryFileName) == 1) && file1OlderThan2(binaryFileName,fileName))) //Line 6-7
  373. {
  374. makeBinary = true;
  375. }
  376. }
  377. else
  378. {
  379. makeBinary = true;
  380. }
  381. if (!makeBinary)
  382. {
  383. return (LoadBinaryCopy(binaryFileName));
  384. }
  385. else
  386. {
  387. //------------------------------------------
  388. // Check if exists by getting size
  389. long aseFileSize = gos_FileSize(fileName);
  390. if (aseFileSize <= 0)
  391. return(-1);
  392. //---------------------------------------
  393. // Create Buffer to read entire file into
  394. BYTE *aseContents = (BYTE *)malloc(aseFileSize+1);
  395. gosASSERT(aseContents != NULL);
  396. //---------------------------------------
  397. // Open File and read it and close it
  398. HGOSFILE aseFile;
  399. gos_OpenFile(&aseFile,fileName,READONLY);
  400. #ifdef _DEBUG
  401. long dataRead =
  402. #endif
  403. gos_ReadFile(aseFile,aseContents,aseFileSize);
  404. gosASSERT(dataRead == aseFileSize);
  405. gos_CloseFile(aseFile);
  406. aseContents[aseFileSize] = 0;
  407. //----------------------------------------
  408. // Check for valid ASE Header data.
  409. if (strnicmp(ASE_HEADER,(char *)aseContents,strlen(ASE_HEADER)) != 0)
  410. return(-1);
  411. //---------------------------------------
  412. // Texture Data Next.
  413. //If the Material Class is Standard, ONLY one texture possible.
  414. //If the Material Class is Sub-Object, Multiple textures possible.
  415. char textureId[256];
  416. char *textureData;
  417. char numberData[256];
  418. sprintf(textureId,ASE_MATERIAL_COUNT);
  419. textureData = strstr((char *)aseContents,textureId);
  420. if (!textureData)
  421. return(-1);
  422. textureData += strlen(ASE_MATERIAL_COUNT)+1;
  423. GetNumberData(textureData,numberData);
  424. long numMaterials = atol(numberData);
  425. numTextures = 0;
  426. unsigned char *aseBuffer = aseContents;
  427. for (long nmt=0;nmt<numMaterials;nmt++)
  428. {
  429. sprintf(textureId,ASE_MATERIAL_CLASS);
  430. textureData = strstr((char *)aseBuffer,textureId);
  431. if (!textureData)
  432. return(-1);
  433. textureData += strlen(ASE_MATERIAL_CLASS)+1;
  434. GetWordData(textureData,numberData);
  435. if (strstr(numberData,"Standard"))
  436. {
  437. numTextures++;
  438. }
  439. else if (strstr(numberData,"Multi"))
  440. {
  441. //----------------------------------------------------
  442. //NOT SUPPORTED YET! Multiple Textures per building!
  443. // Support NOW! Must have trees!
  444. textureData = strstr(textureData,ASE_SUBMATERIAL_COUNT);
  445. gosASSERT(textureData != NULL);
  446. textureData += strlen(ASE_SUBMATERIAL_COUNT);
  447. GetNumberData(textureData,numberData);
  448. numTextures += atol(numberData);
  449. }
  450. aseBuffer = (unsigned char *)textureData;
  451. }
  452. IProviderAssetPtr armAssetPtr = NULL;
  453. if (armProvider)
  454. {
  455. armAssetPtr = armProvider->OpenAsset(fileName,
  456. AssetType_Physical, ProviderType_Primary);
  457. armAssetPtr->AddProperty("Type", "Shape");
  458. }
  459. if (numTextures)
  460. {
  461. numTextures *= 2;
  462. listOfTextures = (TG_TexturePtr)TG_Shape::tglHeap->Malloc(sizeof(TG_Texture) * numTextures);
  463. gosASSERT(listOfTextures != NULL);
  464. memset(listOfTextures,0x0,sizeof(TG_Texture) * numTextures);
  465. char *txmData = (char *)aseContents;
  466. for (long i=0;i<(numTextures/2);i++)
  467. {
  468. //-------------------------------------------------------------------------------
  469. // Get and store texture Name. Will need multiple for Multi-Sub if implemented
  470. char textId[256];
  471. sprintf(textId,"%s",ASE_MATERIAL_BITMAP_ID,i);
  472. char *txmTemp = txmData;
  473. txmData = strstr(txmData,textId);
  474. if (txmData == NULL)
  475. {
  476. #ifdef _DEBUG
  477. if (!silentMode)
  478. PAUSE(("WARNING: Material ID %d in Shape %s has no Texture Bitmap!!",(i+1),fileName));
  479. #endif
  480. txmData = txmTemp;
  481. strcpy(listOfTextures[i].textureName,"NULLTXM");
  482. }
  483. else
  484. {
  485. txmData += strlen(textId);
  486. GetNameData(txmData,listOfTextures[i].textureName);
  487. }
  488. if (listOfTextures[i].textureName[0] == 0)
  489. {
  490. strcpy(listOfTextures[i].textureName,"NULLTXM");
  491. }
  492. // ARM
  493. if (armAssetPtr && strcmp(listOfTextures[i].textureName, "NULLTXM") != 0)
  494. {
  495. // The filenames refer to art files on some share (\\aas1), just get the base filename
  496. // and assume it's in the "Data\TGL\128\" directory
  497. char * baseFilename = strrchr(listOfTextures[i].textureName, '\\');
  498. if (baseFilename)
  499. {
  500. char localFilename[1024] = "Data\\TGL\\128\\";
  501. strcat(localFilename, baseFilename+1);
  502. armAssetPtr->AddRelationship("Texture", localFilename);
  503. }
  504. else
  505. {
  506. armAssetPtr->AddRelationship("Texture", listOfTextures[i].textureName);
  507. }
  508. }
  509. listOfTextures[i].mcTextureNodeIndex = 0xffffffff;
  510. listOfTextures[i].gosTextureHandle = 0xffffffff;
  511. listOfTextures[i].textureAlpha = false;
  512. }
  513. for (i=(numTextures/2);i<numTextures;i++)
  514. {
  515. //-------------------------------------------------------------------------------
  516. // add the word Shadow the texture name so we can load shadows if we need to!
  517. strncpy(listOfTextures[i].textureName,listOfTextures[i-(numTextures/2)].textureName,strlen(listOfTextures[i-(numTextures/2)].textureName)-4);
  518. strcat(listOfTextures[i].textureName,"X.tga");
  519. listOfTextures[i].mcTextureNodeIndex = 0xffffffff;
  520. listOfTextures[i].gosTextureHandle = 0xffffffff;
  521. listOfTextures[i].textureAlpha = true;
  522. }
  523. for (i=0;i<numTextures;i++)
  524. {
  525. // Try to touch all of the textures we need.
  526. char txmName[1024];
  527. GetTextureName(i,txmName,256);
  528. char texturePath[1024];
  529. sprintf(texturePath,"%s%d\\",tglPath,ObjectTextureSize);
  530. FullPathFileName textureName;
  531. textureName.init(texturePath,txmName,"");
  532. if( fileExists(textureName) == 1 )
  533. {
  534. File *touchTexture = new File();
  535. touchTexture->open(textureName);
  536. touchTexture->close();
  537. delete touchTexture;
  538. }
  539. }
  540. }
  541. else
  542. listOfTextures = NULL;
  543. //------------------------------------------------------------
  544. // FIRST PASS. Count number of GEOMObjects & HelperObjects
  545. numTG_TypeShapes = 0;
  546. char *aseScan = (char *)aseContents;
  547. aseScan = strstr(aseScan,ASE_OBJECT);
  548. while (aseScan != NULL)
  549. {
  550. numTG_TypeShapes++;
  551. aseScan += strlen(ASE_OBJECT)+1;
  552. aseScan = strstr(aseScan,ASE_OBJECT);
  553. }
  554. aseScan = (char *)aseContents;
  555. aseScan = strstr(aseScan,ASE_HELP_OBJECT);
  556. while (aseScan != NULL)
  557. {
  558. //--------------------------------------------------------
  559. // Check if NodeName is handle_ or WORLD. These are bad!
  560. // Do not count them!
  561. aseScan = strstr(aseScan,ASE_NODE_NAME);
  562. gosASSERT(aseScan != NULL); //Node must have a NAME, right?
  563. aseScan += strlen(ASE_NODE_NAME)+1;
  564. char chkWord[512];
  565. GetWordData(aseScan,chkWord);
  566. if (strstr(chkWord,"handle_") == NULL && strstr(chkWord,"World") == NULL)
  567. {
  568. numTG_TypeShapes++;
  569. }
  570. aseScan += strlen(ASE_HELP_OBJECT)+1;
  571. aseScan = strstr(aseScan,ASE_HELP_OBJECT);
  572. }
  573. listOfTypeShapes = (TG_TypeNodePtr *)TG_Shape::tglHeap->Malloc(sizeof(TG_TypeNodePtr) * (numTG_TypeShapes+1));
  574. gosASSERT(listOfTypeShapes != NULL);
  575. memset(listOfTypeShapes,0,sizeof(TG_TypeNodePtr) * (numTG_TypeShapes+1));
  576. //------------------------------------------------------------
  577. // SECOND PASS. Load HelperObjects.
  578. long startIndex = 0;
  579. aseScan = (char *)aseContents;
  580. aseScan = strstr(aseScan,ASE_HELP_OBJECT);
  581. while (aseScan != NULL)
  582. {
  583. listOfTypeShapes[startIndex] = new TG_TypeNode;
  584. listOfTypeShapes[startIndex]->init();
  585. //---------------------------------------------------
  586. // Calling from top will load just first HELPEROBJECT!
  587. // We now make the "top" the start of each HELPEROBJECT!
  588. // DO NOT LOAD handle_ helpers and WORLD halpers.
  589. // Decrement number of shapes accordingly.
  590. char *aseEnd = aseScan + strlen(ASE_HELP_OBJECT)+1;
  591. aseEnd = strstr(aseEnd,ASE_HELP_OBJECT);
  592. if (aseEnd)
  593. {
  594. char *aseData = (char *)malloc(aseFileSize+1);
  595. ZeroMemory(aseData, aseFileSize+1);
  596. memcpy(aseData,aseScan,aseEnd - aseScan);
  597. //--------------------------------------------------------
  598. // Check if NodeName is handle_ or WORLD. These are bad!
  599. // Do not count them!
  600. aseScan = strstr(aseScan,ASE_NODE_NAME);
  601. gosASSERT(aseScan != NULL); //Node must have a NAME, right?
  602. aseScan += strlen(ASE_NODE_NAME)+1;
  603. char chkWord[512];
  604. GetWordData(aseScan,chkWord);
  605. //-------------------------------------------------------------------
  606. // Is this a forbidden helper object?
  607. if ((strstr(chkWord,"handle") == NULL) && (strstr(chkWord,"World") == NULL))
  608. {
  609. long parseResult = listOfTypeShapes[startIndex]->MakeFromHelper((unsigned char *)aseData,fileName);
  610. if (parseResult != 0)
  611. return(parseResult);
  612. startIndex++;
  613. }
  614. free(aseData);
  615. }
  616. else
  617. {
  618. //--------------------------------------------------------
  619. // Check if NodeName is handle_ or WORLD. These are bad!
  620. // Do not count them!
  621. char *scanStart = aseScan;
  622. scanStart = strstr(scanStart,ASE_NODE_NAME);
  623. gosASSERT(scanStart != NULL); //Node must have a NAME, right?
  624. scanStart += strlen(ASE_NODE_NAME)+1;
  625. char chkWord[512];
  626. GetWordData(scanStart,chkWord);
  627. //-------------------------------------------------------------------
  628. // Is this a forbidden helper object?
  629. if ((strstr(chkWord,"handle") == NULL) && (strstr(chkWord,"World") == NULL))
  630. {
  631. //-------------------------------------------------------------------
  632. long parseResult = listOfTypeShapes[startIndex]->MakeFromHelper((unsigned char *)aseScan,fileName);
  633. if (parseResult != 0)
  634. return(parseResult);
  635. startIndex++;
  636. }
  637. }
  638. aseScan += strlen(ASE_HELP_OBJECT);
  639. aseScan = strstr(aseScan,ASE_HELP_OBJECT);
  640. }
  641. //------------------------------------------------------------
  642. // THIRD PASS. Load GeomObjects.
  643. aseScan = (char *)aseContents;
  644. aseScan = strstr(aseScan,ASE_OBJECT);
  645. while (aseScan != NULL)
  646. {
  647. listOfTypeShapes[startIndex] = new TG_TypeShape;
  648. listOfTypeShapes[startIndex]->init();
  649. listOfTypeShapes[startIndex]->CreateListOfTextures(listOfTextures,numTextures);
  650. //---------------------------------------------------
  651. // Calling from top will load just first GEOMOBJECT!
  652. // We now make the "top" the start of each GEOMOBJECT!
  653. char *aseEnd = aseScan + strlen(ASE_OBJECT)+1;
  654. aseEnd = strstr(aseEnd,ASE_OBJECT);
  655. if (aseEnd)
  656. {
  657. char *aseData = (char *)malloc(aseFileSize+1);
  658. ZeroMemory(aseData, aseFileSize+1);
  659. memcpy(aseData,aseScan,aseEnd - aseScan);
  660. long parseResult = listOfTypeShapes[startIndex]->ParseASEFile((unsigned char *)aseData,fileName);
  661. if (parseResult != 0)
  662. return(parseResult);
  663. free(aseData);
  664. }
  665. else
  666. {
  667. long parseResult = listOfTypeShapes[startIndex]->ParseASEFile((unsigned char *)aseScan,fileName);
  668. if (parseResult != 0)
  669. return(parseResult);
  670. }
  671. startIndex++;
  672. aseScan += strlen(ASE_OBJECT)+1;
  673. aseScan = strstr(aseScan,ASE_OBJECT);
  674. }
  675. //------------------------------------------------------------------
  676. // FOURTH PASS. Setup Heirarchy ALWAYS or NO Shape BOUNDS!!!
  677. {
  678. aseScan = (char *)aseContents;
  679. for (long i=0;i<numTG_TypeShapes;i++)
  680. {
  681. //----------------------------------------------------------------------------------
  682. // For each shape, look for another node whose NodeId matches this shape's parentId
  683. TG_TypeNodePtr parentNode = NULL;
  684. for (long j=0;j<numTG_TypeShapes;j++)
  685. {
  686. if (strcmp(listOfTypeShapes[i]->getParentId(),listOfTypeShapes[j]->getNodeId()) == 0)
  687. {
  688. parentNode = listOfTypeShapes[j];
  689. break;
  690. }
  691. }
  692. listOfTypeShapes[i]->movePosRelativeCenterNode();
  693. if (parentNode)
  694. listOfTypeShapes[i]->MoveNodeCenterRelative(parentNode->GetNodeCenter());
  695. //--------------------------------------------------------
  696. //ONLY use nodes which are not spotlight or _PAB or LOS_
  697. if ((strnicmp(listOfTypeShapes[i]->getNodeId(),"_PAB",4) != 0) &&
  698. (strnicmp(listOfTypeShapes[i]->getNodeId(),"LOS_",4) != 0) &&
  699. (strnicmp(listOfTypeShapes[i]->getNodeId(),"SpotLight",9) != 0))
  700. {
  701. //------------------------------------------------------------------
  702. // Scan list of vertices and create minBox, maxBox and extentRadius
  703. for (j=0;j<listOfTypeShapes[i]->GetNumTypeVertices();j++)
  704. {
  705. Stuff::Vector3D relNodeCenter;
  706. relNodeCenter = listOfTypeShapes[i]->GetRelativeNodeCenter();
  707. TG_TypeShapePtr typeShape = (TG_TypeShapePtr)listOfTypeShapes[i];
  708. if (minBox.x > typeShape->listOfTypeVertices[j].position.x + relNodeCenter.x)
  709. minBox.x = typeShape->listOfTypeVertices[j].position.x + relNodeCenter.x;
  710. if (maxBox.x < typeShape->listOfTypeVertices[j].position.x + relNodeCenter.x)
  711. maxBox.x = typeShape->listOfTypeVertices[j].position.x + relNodeCenter.x;
  712. if (minBox.y > typeShape->listOfTypeVertices[j].position.y + relNodeCenter.y)
  713. minBox.y = typeShape->listOfTypeVertices[j].position.y + relNodeCenter.y;
  714. if (maxBox.y < typeShape->listOfTypeVertices[j].position.y + relNodeCenter.y)
  715. maxBox.y = typeShape->listOfTypeVertices[j].position.y + relNodeCenter.y;
  716. if (minBox.z > typeShape->listOfTypeVertices[j].position.z + relNodeCenter.z)
  717. minBox.z = typeShape->listOfTypeVertices[j].position.z + relNodeCenter.z;
  718. if (maxBox.z < typeShape->listOfTypeVertices[j].position.z + relNodeCenter.z)
  719. maxBox.z = typeShape->listOfTypeVertices[j].position.z + relNodeCenter.z;
  720. }
  721. }
  722. }
  723. float minBoxLength = minBox.GetLength();
  724. float maxBoxLength = maxBox.GetLength();
  725. if (minBoxLength > extentRadius)
  726. extentRadius = minBoxLength;
  727. if (maxBoxLength > extentRadius)
  728. extentRadius = maxBoxLength;
  729. }
  730. if (armAssetPtr != NULL)
  731. {
  732. armAssetPtr->Close();
  733. }
  734. free(aseContents);
  735. aseContents = NULL;
  736. SaveBinaryCopy(binaryFileName);
  737. }
  738. return(0);
  739. }
  740. //-------------------------------------------------------------------------------
  741. // TG_TypeMultiShape
  742. void *TG_MultiShape::operator new (size_t mySize)
  743. {
  744. void *result = TG_Shape::tglHeap->Malloc(mySize);
  745. return result;
  746. }
  747. //-------------------------------------------------------------------------------
  748. void TG_MultiShape::operator delete (void *us)
  749. {
  750. TG_Shape::tglHeap->Free(us);
  751. }
  752. //-------------------------------------------------------------------------------
  753. //Function returns 0 if OK. realLength if textureName is longer then nameLength-1.
  754. //Returns -1 if texture requested is out of range.
  755. //This function digs the texture name(s) out of the ASE file so that the
  756. //User can load and manage them anyway they want to.
  757. long TG_TypeMultiShape::GetTextureName (DWORD textureNum, char *tName, long nameLength)
  758. {
  759. if (textureNum >= numTextures)
  760. return(-1);
  761. char baseName[512];
  762. char extension[256];
  763. _splitpath(listOfTextures[textureNum].textureName,NULL,NULL,baseName,extension);
  764. char basePath[1024];
  765. sprintf(basePath,"%s%s",baseName,extension);
  766. if (nameLength < (strlen(basePath)+1))
  767. return(strlen(basePath)+1);
  768. strcpy(tName,basePath);
  769. return(0);
  770. }
  771. //-------------------------------------------------------------------------------
  772. //Function returns 0 if OK. -1 if textureNum is out of range of numTextures.
  773. // Assigns a MCTextureNodeIndex to this NOT a GOS handle anymore. Must go through
  774. // cache in case of too many handles.
  775. long TG_TypeMultiShape::SetTextureHandle (DWORD textureNum, DWORD gosTextureHandle)
  776. {
  777. if (textureNum >= numTextures)
  778. return(-1);
  779. listOfTextures[textureNum].mcTextureNodeIndex = gosTextureHandle;
  780. listOfTextures[textureNum].gosTextureHandle = 0xffffffff;
  781. return(0);
  782. }
  783. //-------------------------------------------------------------------------------
  784. //Function returns 0 if OK. -1 if textureNum is out of range of numTextures.
  785. //This function takes the gosTextureHandle passed in and assigns it to the
  786. //textureNum entry of the listOfTextures;
  787. long TG_TypeMultiShape::SetTextureAlpha (DWORD textureNum, bool alphaFlag)
  788. {
  789. if (textureNum >= numTextures)
  790. return(-1);
  791. listOfTextures[textureNum].textureAlpha = alphaFlag;
  792. return(0);
  793. }
  794. //-------------------------------------------------------------------------------
  795. //This function rotates the heirarchy from this node down. Used for torso twists, arms, etc.
  796. long TG_MultiShape::SetNodeRotation (char *nodeName, Stuff::UnitQuaternion *rot)
  797. {
  798. for (long i=0;i<numTG_Shapes;i++)
  799. {
  800. if (stricmp(listOfShapes[i].node->myType->getNodeId(),nodeName) == 0)
  801. {
  802. //-------------------------------
  803. // Found it!
  804. listOfShapes[i].baseRotation = *rot;
  805. return i;
  806. }
  807. }
  808. return -1;
  809. }
  810. //----------------------------------------------------------------------------------------------------
  811. //This function returns the world translated position of the vertex asked for with rotation applied.
  812. Stuff::Vector3D TG_MultiShape::GetShapeVertexInEditor(long shapeNum, long vertexNum, float rotation)
  813. {
  814. Stuff::Vector3D result;
  815. result.x = result.y = result.z = 0.0f;
  816. if ((shapeNum >= 0) && (shapeNum < numTG_Shapes) &&
  817. (vertexNum >= 0) && (vertexNum < myMultiType->listOfTypeShapes[shapeNum]->GetNumTypeVertices()))
  818. {
  819. //-------------------------------
  820. // Get the vertex in question.
  821. Stuff::Vector3D vertexPos;
  822. TG_TypeShapePtr typeShape = (TG_TypeShapePtr)myMultiType->listOfTypeShapes[shapeNum];
  823. vertexPos.x = -(typeShape->listOfTypeVertices[vertexNum].position.x + typeShape->GetRelativeNodeCenter().x + GetRootNodeCenter().x);
  824. vertexPos.z = typeShape->listOfTypeVertices[vertexNum].position.y + typeShape->GetRelativeNodeCenter().y + GetRootNodeCenter().y;
  825. vertexPos.y = typeShape->listOfTypeVertices[vertexNum].position.z + typeShape->GetRelativeNodeCenter().z + GetRootNodeCenter().z;
  826. //---------------------------------------
  827. // Rotate vertex if rotation is NON-zero
  828. if (rotation != 0.0f)
  829. {
  830. Rotate(vertexPos,rotation);
  831. }
  832. result = vertexPos;
  833. }
  834. return result;
  835. }
  836. //----------------------------------------------------------------------------------------------------
  837. //This function returns the world translated position of the vertex asked for with rotation applied.
  838. Stuff::Vector3D TG_MultiShape::GetShapeVertexInWorld(long shapeNum, long vertexNum, float rotation)
  839. {
  840. Stuff::Vector3D result;
  841. result.x = result.y = result.z = 0.0f;
  842. if ((shapeNum >= 0) && (shapeNum < numTG_Shapes) &&
  843. (vertexNum >= 0) && (vertexNum < myMultiType->listOfTypeShapes[shapeNum]->GetNumTypeVertices()))
  844. {
  845. //-------------------------------
  846. // Get the vertex in question.
  847. Stuff::Point3D vertexPos;
  848. TG_TypeShapePtr typeShape = (TG_TypeShapePtr)myMultiType->listOfTypeShapes[shapeNum];
  849. vertexPos.Multiply(typeShape->listOfTypeVertices[vertexNum].position,listOfShapes[shapeNum].shapeToWorld);
  850. result.x = -vertexPos.x;
  851. result.y = vertexPos.z;
  852. result.z = vertexPos.y;
  853. //---------------------------------------
  854. // Rotate vertex if rotation is NON-zero
  855. if (rotation != 0.0f)
  856. {
  857. Rotate(result,rotation);
  858. }
  859. }
  860. return result;
  861. }
  862. //-------------------------------------------------------------------------------
  863. //This function sets the fog values for the shape. Straight fog right now.
  864. void TG_MultiShape::SetFogRGB (DWORD fRGB)
  865. {
  866. for (long i=0;i<numTG_Shapes;i++)
  867. {
  868. listOfShapes[i].node->SetFogRGB(fRGB);
  869. }
  870. }
  871. //-------------------------------------------------------------------------------
  872. //This function sets the list of lights used by the TransformShape function
  873. //to light the shape.
  874. //Function returns 0 if lightList entries are all OK. -1 otherwise.
  875. //
  876. long TG_MultiShape::SetLightList (TG_LightPtr *lightList, DWORD nLights)
  877. {
  878. //-----------------------------------------------------
  879. // Static member of TG_Shape. Only need to call once.
  880. // NOT a static function in case lights need to change
  881. // on a shape by shape basis!
  882. return (listOfShapes[0].node->SetLightList(lightList,nLights));
  883. }
  884. //-------------------------------------------------------------------------------
  885. Stuff::Vector3D TG_MultiShape::GetTransformedNodePosition (Stuff::Point3D *pos, Stuff::UnitQuaternion *rot, char *nodeId)
  886. {
  887. Stuff::LinearMatrix4D shapeOrigin;
  888. Stuff::LinearMatrix4D localShapeOrigin;
  889. // Stuff::LinearMatrix4D invShapeOrigin;
  890. shapeOrigin.BuildRotation(*rot);
  891. shapeOrigin.BuildTranslation(*pos);
  892. // invShapeOrigin.Invert(shapeOrigin);
  893. Stuff::EulerAngles angles(*rot);
  894. long i=0;
  895. Stuff::Vector3D result;
  896. result.x = result.y = result.z = 0.0f;
  897. for (i=0;i<numTG_Shapes;i++)
  898. {
  899. //-----------------------------------------------------------------
  900. // Scan through the list of shapes and dig out the number needed.
  901. // DO NOT UPDATE THE HEIRARCHY!!!!
  902. // This thing may not have updated itself this turn yet!!!
  903. if (stricmp(listOfShapes[i].node->myType->getNodeId(),nodeId) == 0)
  904. {
  905. result.x = -listOfShapes[i].shapeToWorld.entries[3];
  906. result.z = listOfShapes[i].shapeToWorld.entries[7];
  907. result.y = listOfShapes[i].shapeToWorld.entries[11];
  908. return result;
  909. }
  910. }
  911. return result;
  912. }
  913. //-------------------------------------------------------------------------------
  914. Stuff::Vector3D TG_MultiShape::GetTransformedNodePosition (Stuff::Point3D *pos, Stuff::UnitQuaternion *rot, long nodeId)
  915. {
  916. Stuff::LinearMatrix4D shapeOrigin;
  917. Stuff::LinearMatrix4D localShapeOrigin;
  918. // Stuff::LinearMatrix4D invShapeOrigin;
  919. shapeOrigin.BuildRotation(*rot);
  920. shapeOrigin.BuildTranslation(*pos);
  921. // invShapeOrigin.Invert(shapeOrigin);
  922. Stuff::EulerAngles angles(*rot);
  923. Stuff::Vector3D result;
  924. result.x = result.y = result.z = 0.0f;
  925. if ((nodeId >= 0) && (nodeId < numTG_Shapes))
  926. {
  927. result.x = -listOfShapes[nodeId].shapeToWorld.entries[3];
  928. result.z = listOfShapes[nodeId].shapeToWorld.entries[7];
  929. result.y = listOfShapes[nodeId].shapeToWorld.entries[11];
  930. return result;
  931. }
  932. return result;
  933. }
  934. Stuff::UnitQuaternion moveem;
  935. //-------------------------------------------------------------------------------
  936. //This function does the actual transform math, clip checks and lighting math.
  937. //The matrices passed in are the translation/rotation matrix for the shape and
  938. //Its inverse. Also will animate.
  939. //Function returns -1 if all vertex screen positions are off screen.
  940. //Function returns 0 if any one vertex screen position is off screen.
  941. //Function returns 1 is all vertex screen positions are on screen.
  942. // NOTE: THIS IS NOT A RIGOROUS CLIP!!!!!!!!!
  943. float yawRotation = 0.0f;
  944. #ifdef LAB_ONLY
  945. __int64 MCTimeTransformandLight = 0;
  946. __int64 MCTimeAnimationandMatrix = 0;
  947. __int64 MCTimePerShapeTransform = 0;
  948. #endif
  949. long TG_MultiShape::TransformMultiShape (Stuff::Point3D *pos, Stuff::UnitQuaternion *rot)
  950. {
  951. //Profile T&L so I can break out GameLogic from T&L
  952. #ifdef LAB_ONLY
  953. __int64 x;
  954. x=GetCycles();
  955. #endif
  956. Stuff::LinearMatrix4D shapeOrigin;
  957. Stuff::LinearMatrix4D shadowOrigin;
  958. Stuff::LinearMatrix4D localShapeOrigin;
  959. shapeOrigin.BuildRotation(*rot);
  960. shapeOrigin.BuildTranslation(*pos);
  961. Stuff::EulerAngles angles(*rot);
  962. yawRotation = angles.yaw;
  963. shadowOrigin.BuildRotation(Stuff::EulerAngles(-angles.pitch,0.0f,0.0f));
  964. shadowOrigin.BuildTranslation(*pos);
  965. long i=0;
  966. Stuff::Point3D camPosition;
  967. camPosition = *TG_Shape::cameraOrigin;
  968. Stuff::Matrix4D shapeToClip, rootShapeToClip;
  969. Stuff::Point3D backFacePoint;
  970. TG_ShapeRecPtr childChain[MAX_NODES];
  971. for (i=0;i<numTG_Shapes;i++)
  972. {
  973. //----------------------------------------------
  974. // Must set each transform! Animating Textures!
  975. for (long j=0;j<myMultiType->numTextures;j++)
  976. {
  977. listOfShapes[i].node->myType->SetTextureHandle(j,myMultiType->listOfTextures[j].mcTextureNodeIndex);
  978. listOfShapes[i].node->myType->SetTextureAlpha(j,myMultiType->listOfTextures[j].textureAlpha);
  979. }
  980. //-----------------------------------------------------------------
  981. // Heirarchy Animation Code.
  982. //
  983. // Simple, really. For each shape in list, traverse back UP
  984. // the heirarchy and store the traversal pointers in a temp list.
  985. // Starting at the TOP of the heirarchy and for each shape,
  986. // check if matrix set for that shape. If so, next node down. If
  987. // not, copy above matrix into node and apply animation data.
  988. // Do this until at end of this heirarchy.
  989. long curChild = 0;
  990. childChain[curChild] = &listOfShapes[i];
  991. while (childChain[curChild]->parentNode)
  992. {
  993. curChild++;
  994. gosASSERT(curChild < MAX_NODES);
  995. childChain[curChild] = childChain[curChild-1]->parentNode;
  996. }
  997. long fNum = float2long(frameNum);
  998. Stuff::Point3D zero;
  999. zero.x = zero.y = zero.z = 0.0f;
  1000. for (j=curChild;j>=0;j--)
  1001. {
  1002. if (childChain[j]->calcedThisFrame != turn)
  1003. {
  1004. if (j == curChild) //This is the ROOT Node.
  1005. {
  1006. //----------------------------------------------------
  1007. // Top O the hierarchy. Used passed in shapeMatrices
  1008. // Apply any animation data, if data is non-NULL
  1009. if (childChain[j]->currentAnimation)
  1010. {
  1011. //--------------------------------------
  1012. // Slerp between current and next frame
  1013. Stuff::UnitQuaternion slerpQuat;
  1014. slerpQuat.x = slerpQuat.y = slerpQuat.z = 0.0f;
  1015. slerpQuat.w = 1.0f;
  1016. if (childChain[j]->currentAnimation->quat)
  1017. slerpQuat = childChain[j]->currentAnimation->quat[fNum];
  1018. //--------------------------------------
  1019. //First Apply Animation to this local piece of heirarchy.
  1020. // If piece had base rotation, apply it. Otherwise, no.
  1021. Stuff::UnitQuaternion totalRotation = slerpQuat;
  1022. if ((childChain[j]->baseRotation.w == 1.0f) &&
  1023. (childChain[j]->baseRotation.x == 0.0f) &&
  1024. (childChain[j]->baseRotation.y == 0.0f) &&
  1025. (childChain[j]->baseRotation.z == 0.0f))
  1026. {
  1027. }
  1028. else
  1029. {
  1030. totalRotation.Multiply(slerpQuat,childChain[j]->baseRotation);
  1031. totalRotation.Normalize();
  1032. }
  1033. localShapeOrigin.BuildRotation(totalRotation);
  1034. if (childChain[j]->currentAnimation->pos)
  1035. localShapeOrigin.BuildTranslation(childChain[j]->currentAnimation->pos[fNum]); //SPECIAL. ROOT HAS ITS OWN OFFSETS!
  1036. else
  1037. localShapeOrigin.BuildTranslation(childChain[j]->node->myType->GetNodeCenter());
  1038. childChain[j]->localShapeToWorld = localShapeOrigin;
  1039. //------------------------------------------------------------------
  1040. //Then move the piece of the heirarchy into the frame of the parent
  1041. childChain[j]->shapeToWorld.Multiply(childChain[j]->localShapeToWorld,shapeOrigin);
  1042. childChain[j]->worldToShape.Invert(childChain[j]->shapeToWorld);
  1043. childChain[j]->calcedThisFrame = turn;
  1044. }
  1045. else
  1046. {
  1047. localShapeOrigin.BuildRotation(Stuff::EulerAngles(0.0f,0.0f,0.0f));
  1048. localShapeOrigin.BuildTranslation(childChain[j]->node->myType->GetNodeCenter());
  1049. childChain[j]->localShapeToWorld = localShapeOrigin;
  1050. childChain[j]->shapeToWorld.Multiply(childChain[j]->localShapeToWorld,shapeOrigin);
  1051. childChain[j]->worldToShape.Invert(childChain[j]->shapeToWorld);
  1052. childChain[j]->calcedThisFrame = turn;
  1053. }
  1054. }
  1055. else
  1056. {
  1057. //----------------------------------------------------------------------
  1058. // Not Top O the Heirarchy. Figure out matrix based on Animation data.
  1059. if (childChain[j]->currentAnimation)
  1060. {
  1061. //--------------------------------------
  1062. // Slerp between current and next frame
  1063. Stuff::UnitQuaternion slerpQuat;
  1064. slerpQuat.x = slerpQuat.y = slerpQuat.z = 0.0f;
  1065. slerpQuat.w = 1.0f;
  1066. if (childChain[j]->currentAnimation->quat)
  1067. slerpQuat = childChain[j]->currentAnimation->quat[fNum];
  1068. //--------------------------------------
  1069. //First Apply Animation to this local piece of heirarchy.
  1070. // If piece had base rotation, apply it. Otherwise, no.
  1071. Stuff::UnitQuaternion totalRotation = slerpQuat;
  1072. if ((childChain[j]->baseRotation.w == 1.0f) &&
  1073. (childChain[j]->baseRotation.x == 0.0f) &&
  1074. (childChain[j]->baseRotation.y == 0.0f) &&
  1075. (childChain[j]->baseRotation.z == 0.0f))
  1076. {
  1077. }
  1078. else
  1079. {
  1080. totalRotation.Multiply(slerpQuat,childChain[j]->baseRotation);
  1081. totalRotation.Normalize();
  1082. }
  1083. localShapeOrigin.BuildRotation(totalRotation);
  1084. if (childChain[j]->currentAnimation->pos)
  1085. localShapeOrigin.BuildTranslation(childChain[j]->currentAnimation->pos[fNum]);
  1086. else
  1087. localShapeOrigin.BuildTranslation(childChain[j]->node->myType->GetRelativeNodeCenter());
  1088. childChain[j]->localShapeToWorld = localShapeOrigin;
  1089. //------------------------------------------------------------------
  1090. //Then move the piece of the heirarchy into the frame of the parent
  1091. childChain[j]->localShapeToWorld.Multiply(localShapeOrigin,childChain[j+1]->localShapeToWorld);
  1092. //------------------------------------------------------------------
  1093. // Then deal with global translation.
  1094. childChain[j]->shapeToWorld.Multiply(childChain[j]->localShapeToWorld,shapeOrigin);
  1095. childChain[j]->worldToShape.Invert(childChain[j]->shapeToWorld);
  1096. childChain[j]->calcedThisFrame = turn;
  1097. }
  1098. else
  1099. {
  1100. //--------------------------------------
  1101. // NO Animation if we are here.
  1102. //
  1103. // Apply Base Rotation. If it is Zero, no problem!
  1104. Stuff::UnitQuaternion totalRotation = childChain[j]->baseRotation;
  1105. localShapeOrigin.BuildRotation(totalRotation);
  1106. localShapeOrigin.BuildTranslation(childChain[j]->node->myType->GetRelativeNodeCenter());
  1107. childChain[j]->localShapeToWorld = localShapeOrigin;
  1108. //------------------------------------------------------------------
  1109. //Then move the piece of the heirarchy into the frame of the parent
  1110. localShapeOrigin = childChain[j]->localShapeToWorld;
  1111. childChain[j]->localShapeToWorld.Multiply(localShapeOrigin,childChain[j+1]->localShapeToWorld);
  1112. //------------------------------------------------------------------
  1113. // Then deal with global translation.
  1114. childChain[j]->shapeToWorld.Multiply(childChain[j]->localShapeToWorld,shapeOrigin);
  1115. childChain[j]->worldToShape.Invert(childChain[j]->shapeToWorld);
  1116. childChain[j]->calcedThisFrame = turn;
  1117. }
  1118. }
  1119. }
  1120. }
  1121. if (useFaceLighting || useVertexLighting)
  1122. {
  1123. //----------------------------------------------------
  1124. // Setup Lighting here.
  1125. if (Environment.Renderer != 3)
  1126. {
  1127. for (long iLight=0;iLight<TG_Shape::numLights;iLight++)
  1128. {
  1129. if ((TG_Shape::listOfLights[iLight] != NULL) && (TG_Shape::listOfLights[iLight]->active))
  1130. {
  1131. switch (TG_Shape::listOfLights[iLight]->lightType)
  1132. {
  1133. case TG_LIGHT_AMBIENT:
  1134. {
  1135. //No Setup needed for Ambient light
  1136. }
  1137. break;
  1138. case TG_LIGHT_INFINITE:
  1139. {
  1140. if (TG_Shape::listOfLights[iLight] != NULL)
  1141. {
  1142. TG_Shape::lightToShape[iLight].Multiply(TG_Shape::listOfLights[iLight]->lightToWorld,listOfShapes[i].worldToShape);
  1143. Stuff::UnitVector3D uVec;
  1144. TG_Shape::lightToShape[iLight].GetLocalForwardInWorld(&uVec);
  1145. TG_Shape::lightDir[iLight] = uVec;
  1146. if (listOfShapes[i].parentNode == NULL)
  1147. {
  1148. TG_Shape::rootLightDir[iLight] = TG_Shape::lightDir[iLight];
  1149. //if (angles.yaw != 0.0f )
  1150. // RotateLight(TG_Shape::rootLightDir[iLight],-angles.yaw);
  1151. }
  1152. }
  1153. }
  1154. break;
  1155. case TG_LIGHT_INFINITEWITHFALLOFF:
  1156. {
  1157. if (TG_Shape::listOfLights[iLight] != NULL)
  1158. {
  1159. TG_Shape::lightToShape[iLight].Multiply(TG_Shape::listOfLights[iLight]->lightToWorld,listOfShapes[i].worldToShape);
  1160. Stuff::UnitVector3D uVec;
  1161. TG_Shape::lightToShape[iLight].GetLocalForwardInWorld(&uVec);
  1162. TG_Shape::lightDir[iLight] = uVec;
  1163. if (listOfShapes[i].parentNode == NULL)
  1164. {
  1165. TG_Shape::rootLightDir[iLight] = TG_Shape::lightDir[iLight];
  1166. }
  1167. }
  1168. }
  1169. break;
  1170. case TG_LIGHT_POINT:
  1171. {
  1172. if (TG_Shape::listOfLights[iLight] != NULL)
  1173. {
  1174. Stuff::Point3D lightPos;
  1175. lightPos = TG_Shape::listOfLights[iLight]->direction;
  1176. Stuff::Point3D shapePosition;
  1177. shapePosition = listOfShapes[i].shapeToWorld;
  1178. shapePosition -= lightPos;
  1179. shapePosition.y = 0.0f;
  1180. TG_Shape::lightDir[iLight] = shapePosition;
  1181. //if (angles.yaw != 0.0f )
  1182. // RotateLight(TG_Shape::lightDir[iLight],-angles.yaw);
  1183. }
  1184. if (listOfShapes[i].parentNode == NULL)
  1185. {
  1186. TG_Shape::rootLightDir[iLight] = TG_Shape::lightDir[iLight];
  1187. }
  1188. }
  1189. break;
  1190. case TG_LIGHT_TERRAIN:
  1191. {
  1192. if (TG_Shape::listOfLights[iLight] != NULL)
  1193. {
  1194. Stuff::Point3D lightPos;
  1195. lightPos = TG_Shape::listOfLights[iLight]->direction;
  1196. Stuff::Point3D shapePosition;
  1197. shapePosition = listOfShapes[i].shapeToWorld;
  1198. shapePosition -= lightPos;
  1199. shapePosition.y = 0.0f;
  1200. TG_Shape::lightDir[iLight] = shapePosition;
  1201. }
  1202. if (listOfShapes[i].parentNode == NULL)
  1203. {
  1204. TG_Shape::rootLightDir[iLight] = TG_Shape::lightDir[iLight];
  1205. }
  1206. }
  1207. break;
  1208. case TG_LIGHT_SPOT:
  1209. {
  1210. if (TG_Shape::listOfLights[iLight] != NULL)
  1211. {
  1212. Stuff::Point3D lightPos;
  1213. lightPos = TG_Shape::listOfLights[iLight]->direction;
  1214. Stuff::Point3D shapePosition;
  1215. shapePosition = listOfShapes[i].shapeToWorld;
  1216. shapePosition -= lightPos;
  1217. shapePosition.y = 0.0f;
  1218. TG_Shape::lightDir[iLight] = shapePosition;
  1219. //if (angles.yaw != 0.0f )
  1220. // RotateLight(TG_Shape::lightDir[iLight],-angles.yaw);
  1221. lightPos = TG_Shape::listOfLights[iLight]->spotDir;
  1222. shapePosition = listOfShapes[i].shapeToWorld;
  1223. shapePosition -= lightPos;
  1224. shapePosition.y = 0.0f;
  1225. TG_Shape::spotDir[iLight] = shapePosition;
  1226. //if (angles.yaw != 0.0f )
  1227. // RotateLight(TG_Shape::spotDir[iLight],-angles.yaw);
  1228. if (listOfShapes[i].parentNode == NULL)
  1229. {
  1230. TG_Shape::rootLightDir[iLight] = TG_Shape::spotDir[iLight];
  1231. }
  1232. }
  1233. }
  1234. break;
  1235. }
  1236. }
  1237. }
  1238. }
  1239. }
  1240. shapeToClip.Multiply(listOfShapes[i].shapeToWorld,TG_Shape::worldToClip);
  1241. backFacePoint.Multiply(camPosition,listOfShapes[i].worldToShape);
  1242. #ifdef LAB_ONLY
  1243. x=GetCycles()-x;
  1244. MCTimeAnimationandMatrix += x;
  1245. x=GetCycles();
  1246. #endif
  1247. listOfShapes[i].node->MultiTransformShape(&shapeToClip,&backFacePoint,listOfShapes[i].parentNode,isHudElement,alphaValue,isClamped);
  1248. if (useShadows && d_useShadows)
  1249. {
  1250. listOfShapes[i].node->MultiTransformShadows(pos, &(listOfShapes[i].shapeToWorld),yawRotation);
  1251. }
  1252. #ifdef LAB_ONLY
  1253. x=GetCycles()-x;
  1254. MCTimePerShapeTransform += x;
  1255. x=GetCycles();
  1256. #endif
  1257. }
  1258. #ifdef LAB_ONLY
  1259. MCTimeTransformandLight = MCTimeAnimationandMatrix + MCTimePerShapeTransform;
  1260. #endif
  1261. return(0);
  1262. }
  1263. //-------------------------------------------------------------------------------
  1264. //This function takes the current listOfVisibleFaces and draws them using
  1265. //gos_DrawTriangle.
  1266. void TG_MultiShape::Render (bool refreshTextures, float forceZ)
  1267. {
  1268. for (long i=0;i<numTG_Shapes;i++)
  1269. {
  1270. if (listOfShapes[i].processMe && listOfShapes[i].node)
  1271. {
  1272. //-------------------------------------------------------
  1273. // Only need to due for unique instance items like mechs
  1274. if (refreshTextures)
  1275. {
  1276. for (long j=0;j<myMultiType->numTextures;j++)
  1277. {
  1278. listOfShapes[i].node->myType->SetTextureHandle(j,myMultiType->listOfTextures[j].mcTextureNodeIndex);
  1279. listOfShapes[i].node->myType->SetTextureAlpha(j,myMultiType->listOfTextures[j].textureAlpha);
  1280. }
  1281. }
  1282. listOfShapes[i].node->Render(forceZ,isHudElement,alphaValue,isClamped);
  1283. }
  1284. }
  1285. }
  1286. //-------------------------------------------------------------------------------
  1287. //This function takes the current listOfVisibleFaces and draws them using
  1288. //gos_DrawTriangle.
  1289. void TG_MultiShape::RenderShadows (bool refreshTextures)
  1290. {
  1291. long start = 0;
  1292. for (long i=0;i<numTG_Shapes;i++)
  1293. {
  1294. if (listOfShapes[i].processMe && listOfShapes[i].node)
  1295. {
  1296. //-------------------------------------------------------
  1297. // Only need to due for unique instance items like mechs
  1298. if (refreshTextures)
  1299. {
  1300. for (long j=0;j<myMultiType->numTextures;j++)
  1301. {
  1302. listOfShapes[i].node->myType->SetTextureHandle(j,myMultiType->listOfTextures[j].mcTextureNodeIndex);
  1303. listOfShapes[i].node->myType->SetTextureAlpha(j,myMultiType->listOfTextures[j].textureAlpha);
  1304. }
  1305. }
  1306. start = listOfShapes[i].node->RenderShadows(start);
  1307. }
  1308. }
  1309. }
  1310. //-------------------------------------------------------------------------------
  1311. // This function takes the shape named nodeName and all of its children and stops processing
  1312. // them forever. Since we can never re-attach a mech arm in the field, this is OK!
  1313. // However, should we want this functionality, it is easy to add!
  1314. void TG_MultiShape::StopUsing (char *nodeName)
  1315. {
  1316. //First, find all shapes which are children of nodeName, including nodeName!
  1317. TG_ShapeRecPtr childChain[MAX_NODES];
  1318. TG_ShapeRecPtr detachables[MAX_NODES];
  1319. long curShape = 0;
  1320. long i=0;
  1321. for (i=0;i<numTG_Shapes;i++)
  1322. {
  1323. //----------------------------------------------
  1324. long curChild = 0;
  1325. childChain[curChild] = &listOfShapes[i];
  1326. while (childChain[curChild]->parentNode)
  1327. {
  1328. curChild++;
  1329. gosASSERT(curChild < MAX_NODES);
  1330. childChain[curChild] = childChain[curChild-1]->parentNode;
  1331. }
  1332. Stuff::Point3D zero;
  1333. zero.x = zero.y = zero.z = 0.0f;
  1334. for (long j=curChild;j>=0;j--)
  1335. {
  1336. if (stricmp(childChain[j]->node->getNodeName(),nodeName) == 0)
  1337. {
  1338. detachables[curShape] = childChain[0];
  1339. curShape++;
  1340. break;
  1341. }
  1342. }
  1343. }
  1344. //Then, mark all of the shapes found with a "don't process me" flag
  1345. for (i=0;i<curShape;i++)
  1346. {
  1347. //Keep the joint_xUARM so that the shoulder sparks work.
  1348. if (stricmp(detachables[i]->node->getNodeName(),nodeName) != 0)
  1349. detachables[i]->processMe = false;
  1350. }
  1351. }
  1352. //-------------------------------------------------------------------------------
  1353. // This function takes the shape named nodeName and all of its children, detaches them
  1354. // from the current heirarchy and stuffs them into a new MultiShape which it passes back
  1355. // Uses are endless but for now limited to blowing the arms off of the mechs!
  1356. TG_MultiShapePtr TG_MultiShape::Detach (char *nodeName)
  1357. {
  1358. //First, find all shapes which are children of nodeName, including nodeName!
  1359. TG_ShapeRecPtr childChain[MAX_NODES];
  1360. TG_ShapeRecPtr detachables[MAX_NODES];
  1361. long curShape = 0;
  1362. long i=0;
  1363. for (i=0;i<numTG_Shapes;i++)
  1364. {
  1365. //----------------------------------------------
  1366. long curChild = 0;
  1367. childChain[curChild] = &listOfShapes[i];
  1368. while (childChain[curChild]->parentNode)
  1369. {
  1370. curChild++;
  1371. gosASSERT(curChild < MAX_NODES);
  1372. childChain[curChild] = childChain[curChild-1]->parentNode;
  1373. }
  1374. Stuff::Point3D zero;
  1375. zero.x = zero.y = zero.z = 0.0f;
  1376. for (long j=curChild;j>=0;j--)
  1377. {
  1378. if (stricmp(childChain[j]->node->getNodeName(),nodeName) == 0)
  1379. {
  1380. detachables[curShape] = childChain[0];
  1381. curShape++;
  1382. break;
  1383. }
  1384. }
  1385. }
  1386. if (!curShape)
  1387. return NULL;
  1388. //OK to return no shape now.
  1389. //STOP(("Unable to detach %s from shape",nodeName));
  1390. //Then, create a new TG_MultiShape and stuff it with the shapes found.
  1391. TG_MultiShapePtr resultShape = new TG_MultiShape;
  1392. resultShape->myMultiType = myMultiType;
  1393. resultShape->numTG_Shapes = curShape;
  1394. resultShape->listOfShapes = (TG_ShapeRecPtr)TG_Shape::tglHeap->Malloc(sizeof(TG_ShapeRec) * curShape);
  1395. gosASSERT(resultShape->listOfShapes != NULL);
  1396. memset(resultShape->listOfShapes,0,sizeof(TG_ShapeRec) * curShape);
  1397. resultShape->frameNum = 0;
  1398. for (i=0;i<curShape;i++)
  1399. {
  1400. resultShape->listOfShapes[i] = *detachables[i];
  1401. if (stricmp(resultShape->listOfShapes[i].node->getNodeName(),nodeName) == 0)
  1402. resultShape->listOfShapes[i].parentNode = NULL; //Set new top O heirarchy.
  1403. for (long j=0;j<numTG_Shapes;j++)
  1404. {
  1405. if (&listOfShapes[j] == detachables[i])
  1406. {
  1407. //Mark this shape as removable from the previous heirarchy
  1408. listOfShapes[j].node = NULL;
  1409. listOfShapes[j].parentNode = NULL;
  1410. }
  1411. }
  1412. }
  1413. //Rebuild resultShape parent node pointers!
  1414. for (i=0;i<resultShape->numTG_Shapes;i++)
  1415. {
  1416. //----------------------------------------------------------------------------------
  1417. // For each shape, look for another node whose NodeId matches this shape's parentId
  1418. for (long j=0;j<resultShape->numTG_Shapes;j++)
  1419. {
  1420. if (strcmp(resultShape->listOfShapes[i].node->myType->getParentId(),resultShape->listOfShapes[j].node->myType->getNodeId()) == 0)
  1421. {
  1422. //-------------------------------
  1423. // Found it!
  1424. resultShape->listOfShapes[i].parentNode = &(resultShape->listOfShapes[j]);
  1425. break;
  1426. }
  1427. }
  1428. }
  1429. //-------------------------------------------------------------
  1430. // Rebuild the currentShape heirarchy to reflect removed things
  1431. TG_ShapeRecPtr newListOfShapes = (TG_ShapeRecPtr)TG_Shape::tglHeap->Malloc(sizeof(TG_ShapeRec) * (numTG_Shapes - curShape));
  1432. gosASSERT(newListOfShapes != NULL);
  1433. memset(newListOfShapes,0,sizeof(TG_ShapeRec) * (numTG_Shapes - curShape));
  1434. long newShapeIndex = 0;
  1435. for (i=0;i<numTG_Shapes;i++)
  1436. {
  1437. if (listOfShapes[i].node != NULL)
  1438. {
  1439. newListOfShapes[newShapeIndex] = listOfShapes[i];
  1440. newShapeIndex++;
  1441. }
  1442. }
  1443. //-------------------------------------------------------------
  1444. // Move the new list over the old list.
  1445. if (listOfShapes)
  1446. TG_Shape::tglHeap->Free(listOfShapes);
  1447. listOfShapes = newListOfShapes;
  1448. numTG_Shapes -= curShape;
  1449. //Rebuild parent node pointers!
  1450. for (i=0;i<numTG_Shapes;i++)
  1451. {
  1452. //----------------------------------------------------------------------------------
  1453. // For each shape, look for another node whose NodeId matches this shape's parentId
  1454. for (long j=0;j<numTG_Shapes;j++)
  1455. {
  1456. if (strcmp(listOfShapes[i].node->myType->getParentId(),listOfShapes[j].node->myType->getNodeId()) == 0)
  1457. {
  1458. //-------------------------------
  1459. // Found it!
  1460. listOfShapes[i].parentNode = &(listOfShapes[j]);
  1461. break;
  1462. }
  1463. }
  1464. }
  1465. return resultShape;
  1466. }
  1467. //-------------------------------------------------------------------------------
  1468. // Tells me if the passed in nodeName is a child of the parentName.
  1469. bool TG_MultiShape::isChildOf (char *nodeName, char* parentName)
  1470. {
  1471. //First, find all shapes which are children of nodeName, including nodeName!
  1472. TG_ShapeRecPtr childChain[MAX_NODES];
  1473. TG_ShapeRecPtr detachables[MAX_NODES];
  1474. long curShape = 0;
  1475. long i=0;
  1476. for (i=0;i<numTG_Shapes;i++)
  1477. {
  1478. //----------------------------------------------
  1479. long curChild = 0;
  1480. childChain[curChild] = &listOfShapes[i];
  1481. while (childChain[curChild]->parentNode)
  1482. {
  1483. curChild++;
  1484. gosASSERT(curChild < MAX_NODES);
  1485. childChain[curChild] = childChain[curChild-1]->parentNode;
  1486. }
  1487. Stuff::Point3D zero;
  1488. zero.x = zero.y = zero.z = 0.0f;
  1489. for (long j=curChild;j>=0;j--)
  1490. {
  1491. if (stricmp(childChain[j]->node->getNodeName(),parentName) == 0)
  1492. {
  1493. detachables[curShape] = childChain[0];
  1494. curShape++;
  1495. break;
  1496. }
  1497. }
  1498. }
  1499. if (!curShape)
  1500. return false;
  1501. for (i=0;i<curShape;i++)
  1502. {
  1503. if (stricmp(detachables[i]->node->getNodeName(), nodeName) == 0)
  1504. return true;
  1505. }
  1506. return false;
  1507. }
  1508. //-------------------------------------------------------------------------------
  1509. // class TG_AnimateShape
  1510. //-------------------------------------------------------------------------------
  1511. void *TG_AnimateShape::operator new (size_t mySize)
  1512. {
  1513. void *result = TG_Shape::tglHeap->Malloc(mySize);
  1514. return result;
  1515. }
  1516. //-------------------------------------------------------------------------------
  1517. void TG_AnimateShape::operator delete (void *us)
  1518. {
  1519. TG_Shape::tglHeap->Free(us);
  1520. }
  1521. //-------------------------------------------------------------------------------
  1522. void _TG_Animation::SaveBinaryCopy (File *binFile)
  1523. {
  1524. if (stricmp(nodeId,"NONE") != 0)
  1525. {
  1526. binFile->write((MemoryPtr)nodeId,TG_NODE_ID);
  1527. binFile->writeLong(-1); //ShapeIds ALWAYS start with -1. We will scan on frame 1 please!
  1528. binFile->writeLong(numFrames);
  1529. binFile->writeFloat(frameRate);
  1530. binFile->writeFloat(tickRate);
  1531. if (quat)
  1532. binFile->writeLong(sizeof(Stuff::UnitQuaternion) * numFrames);
  1533. else
  1534. binFile->writeLong(0);
  1535. if (pos)
  1536. binFile->writeLong(sizeof(Stuff::Point3D) * numFrames);
  1537. else
  1538. binFile->writeLong(0);
  1539. if (quat)
  1540. binFile->write((MemoryPtr)quat,sizeof(Stuff::UnitQuaternion) * numFrames);
  1541. if (pos)
  1542. binFile->write((MemoryPtr)pos,sizeof(Stuff::Point3D) * numFrames);
  1543. }
  1544. }
  1545. //-------------------------------------------------------------------------------
  1546. void _TG_Animation::LoadBinaryCopy (File *binFile)
  1547. {
  1548. binFile->read((MemoryPtr)nodeId,TG_NODE_ID);
  1549. shapeId = binFile->readLong();
  1550. numFrames = binFile->readLong();
  1551. frameRate = binFile->readFloat();
  1552. tickRate = binFile->readFloat();
  1553. long quatRAM = binFile->readLong();
  1554. long posRAM = binFile->readLong();
  1555. if (quatRAM)
  1556. {
  1557. quat = (Stuff::UnitQuaternion *)TG_Shape::tglHeap->Malloc(sizeof(Stuff::UnitQuaternion) * numFrames);
  1558. binFile->read((MemoryPtr)quat,quatRAM);
  1559. }
  1560. else
  1561. quat = NULL;
  1562. if (posRAM)
  1563. {
  1564. pos = (Stuff::Point3D *)TG_Shape::tglHeap->Malloc(sizeof(Stuff::Point3D) * numFrames);
  1565. binFile->read((MemoryPtr)pos,posRAM);
  1566. }
  1567. else
  1568. pos = NULL;
  1569. }
  1570. //-------------------------------------------------------------------------------
  1571. long TG_AnimateShape::LoadBinaryCopy (char *fileName)
  1572. {
  1573. File binFile;
  1574. long result = binFile.open(fileName);
  1575. if (result != NO_ERR)
  1576. return -1;
  1577. long animFileVersion = binFile.readLong();
  1578. if (animFileVersion == CURRENT_ANIM_VERSION)
  1579. {
  1580. count = binFile.readLong();
  1581. if (count)
  1582. {
  1583. listOfAnimation = (TG_AnimationPtr)TG_Shape::tglHeap->Malloc(sizeof(TG_Animation) * count);
  1584. gosASSERT(listOfAnimation != NULL);
  1585. for (long i=0;i<count;i++)
  1586. listOfAnimation[i].LoadBinaryCopy(&binFile);
  1587. }
  1588. else
  1589. listOfAnimation = NULL;
  1590. }
  1591. else
  1592. {
  1593. return -1;
  1594. }
  1595. return 0;
  1596. }
  1597. //-------------------------------------------------------------------------------
  1598. void TG_AnimateShape::SaveBinaryCopy (char *fileName)
  1599. {
  1600. File binFile;
  1601. binFile.create(fileName);
  1602. binFile.writeLong(CURRENT_ANIM_VERSION);
  1603. //ListOfAnimations
  1604. actualCount = 0;
  1605. if (count)
  1606. {
  1607. for (long i=0;i<count;i++)
  1608. {
  1609. if (stricmp(listOfAnimation[i].nodeId,"NONE") != 0)
  1610. actualCount++;
  1611. }
  1612. }
  1613. binFile.writeLong(actualCount);
  1614. //ListOfAnimations
  1615. if (count)
  1616. {
  1617. for (long i=0;i<count;i++)
  1618. listOfAnimation[i].SaveBinaryCopy(&binFile);
  1619. }
  1620. }
  1621. //-------------------------------------------------------------------------------
  1622. //This function frees all of the RAM allocated by this class and resets vars to initial state.
  1623. void TG_AnimateShape::destroy (void)
  1624. {
  1625. if (listOfAnimation)
  1626. {
  1627. for ( int i = 0; i < count; ++i )
  1628. {
  1629. TG_Shape::tglHeap->Free( listOfAnimation[i].pos );
  1630. listOfAnimation[i].pos = NULL;
  1631. TG_Shape::tglHeap->Free( listOfAnimation[i].quat );
  1632. listOfAnimation[i].quat = NULL;
  1633. }
  1634. if (listOfAnimation)
  1635. TG_Shape::tglHeap->Free(listOfAnimation);
  1636. listOfAnimation = NULL;
  1637. }
  1638. }
  1639. FilePtr tglLogFile = (FilePtr)NULL;
  1640. //-------------------------------------------------------------------------------
  1641. //This function loads the animation data contained in the file passed in.
  1642. //It sets up a pointer to the multi-shape so that animation data for each
  1643. //Node in the Multi-Shape can be loaded.
  1644. //It mallocs memory.
  1645. long TG_AnimateShape::LoadTGMultiShapeAnimationFromASE (char *fileName, TG_TypeMultiShapePtr shape, bool skipIfBinary, bool forceMakeBinary)
  1646. {
  1647. //------------------------------------------------------
  1648. // New! Checks for Binary file to load instead.
  1649. //
  1650. // If Binary is older or equal to ASE, re-parses ASE and
  1651. // saves binary.
  1652. //
  1653. // If Binary does not exist, does the above, too!
  1654. //
  1655. // If Binary exists and is newer, just loads that.
  1656. // MUCH FASTER!
  1657. //
  1658. bool makeBinary = false;
  1659. char drive[MAX_PATH];
  1660. char dir[MAX_PATH];
  1661. char name[MAX_PATH];
  1662. char ext[MAX_PATH];
  1663. _splitpath(fileName,drive,dir,name,ext);
  1664. FullPathFileName binaryFileName;
  1665. binaryFileName.init(tglPath,name,".agl");
  1666. if( !forceMakeBinary )
  1667. {
  1668. if (fileExists(binaryFileName) && !fileExists(fileName))
  1669. {
  1670. File binFile;
  1671. long result = binFile.open(binaryFileName);
  1672. if (result != NO_ERR)
  1673. {
  1674. makeBinary = true;
  1675. }
  1676. else
  1677. {
  1678. long versionId = binFile.readLong();
  1679. if (versionId != CURRENT_ANIM_VERSION)
  1680. makeBinary = true;
  1681. }
  1682. }
  1683. else
  1684. {
  1685. makeBinary = true;
  1686. }
  1687. }
  1688. else
  1689. {
  1690. makeBinary = true;
  1691. }
  1692. if (!makeBinary)
  1693. {
  1694. if (!skipIfBinary)
  1695. return (LoadBinaryCopy(binaryFileName));
  1696. else
  1697. return 0;
  1698. }
  1699. else
  1700. {
  1701. //-----------------------------------------------------
  1702. // Fully loads and parses an ASE File. These files are
  1703. // output by 3D Studio MAX's ASCII Scene Exporter.
  1704. //
  1705. shapeIdsSet = false;
  1706. //------------------------------------------
  1707. // Check if exists by getting size
  1708. long aseFileSize = gos_FileSize(fileName);
  1709. if (aseFileSize <= 0)
  1710. return(-1);
  1711. //---------------------------------------
  1712. // Create Buffer to read entire file into
  1713. BYTE *aseContents = (BYTE *)malloc(aseFileSize+1);
  1714. gosASSERT(aseContents != NULL);
  1715. //---------------------------------------
  1716. // Open File and read it and close it
  1717. HGOSFILE aseFile;
  1718. gos_OpenFile(&aseFile,fileName,READONLY);
  1719. #ifdef _DEBUG
  1720. long dataRead =
  1721. #endif
  1722. gos_ReadFile(aseFile,aseContents,aseFileSize);
  1723. gosASSERT(dataRead == aseFileSize);
  1724. gos_CloseFile(aseFile);
  1725. aseContents[aseFileSize] = 0;
  1726. //----------------------------------------
  1727. // Check for valid ASE Header data.
  1728. if (strnicmp(ASE_HEADER,(char *)aseContents,strlen(ASE_HEADER)) != 0)
  1729. return(-1);
  1730. //------------------------------------------
  1731. // Get first frame of animation from header
  1732. long firstFrame, lastFrame;
  1733. char *frameId = strstr((char *)aseContents,ASE_ANIM_FIRST_FRAME);
  1734. gosASSERT(frameId != NULL);
  1735. frameId += strlen(ASE_ANIM_FIRST_FRAME)+1;
  1736. char numData[512];
  1737. GetNumberData(frameId,numData);
  1738. firstFrame = atol(numData);
  1739. frameId = strstr((char *)aseContents,ASE_ANIM_LAST_FRAME);
  1740. gosASSERT(frameId != NULL);
  1741. frameId += strlen(ASE_ANIM_LAST_FRAME)+1;
  1742. GetNumberData(frameId,numData);
  1743. lastFrame = atol(numData);
  1744. //gosASSERT(firstFrame == 0);
  1745. gosASSERT(firstFrame <= lastFrame);
  1746. //if (firstFrame == lastFrame)
  1747. //No Animation data at all. Possible?
  1748. long numFrames = (lastFrame - firstFrame) + 1;
  1749. frameId = strstr((char *)aseContents,ASE_ANIM_FRAME_SPEED);
  1750. gosASSERT(frameId != NULL);
  1751. frameId += strlen(ASE_ANIM_FRAME_SPEED)+1;
  1752. GetNumberData(frameId,numData);
  1753. float frameRate = (float)atof(numData);
  1754. frameId = strstr((char *)aseContents,ASE_ANIM_TICKS_FRAME);
  1755. gosASSERT(frameId != NULL);
  1756. frameId += strlen(ASE_ANIM_TICKS_FRAME)+1;
  1757. GetNumberData(frameId,numData);
  1758. float tickRate = (float)atof(numData);
  1759. //----------------------------------------------------------------------------
  1760. // For each TG_Shape in MultiShape passed in, find any and all animation Data
  1761. count = shape->GetNumShapes();
  1762. listOfAnimation = (TG_AnimationPtr)TG_Shape::tglHeap->Malloc(sizeof(TG_Animation) * shape->GetNumShapes());
  1763. gosASSERT(listOfAnimation != NULL);
  1764. //----------------------------------------------------------------------------
  1765. // Scan the Nodes.
  1766. actualCount = 0;
  1767. bool countUp = false;
  1768. for (long i=0;i<count;i++)
  1769. {
  1770. char *nodeId = shape->GetNodeId(i);
  1771. gosASSERT(nodeId != NULL);
  1772. char *animScan = (char *)aseContents;
  1773. animScan = strstr(animScan,ASE_ANIMATION);
  1774. char nodeName[512];
  1775. sprintf(nodeName,"*NODE_NAME \"%s\"",nodeId);
  1776. while (animScan != NULL)
  1777. {
  1778. animScan += strlen(ASE_ANIMATION)+1;
  1779. //------------------------------------------------------
  1780. // We found a TM_ANIMATION Section.
  1781. // Check if the VERY NEXT LINE is the correct NodeName
  1782. char nextLine[1024];
  1783. GetNextLine(animScan,nextLine);
  1784. if (strstr(nextLine,nodeName) == NULL)
  1785. {
  1786. animScan = strstr(animScan,ASE_ANIMATION);
  1787. }
  1788. else
  1789. {
  1790. animScan += strlen(nodeName)+1;
  1791. break;
  1792. }
  1793. }
  1794. if (animScan == NULL)
  1795. {
  1796. //No Animation Data for this Node.
  1797. strcpy(listOfAnimation[i].nodeId,"NONE");
  1798. listOfAnimation[i].numFrames = numFrames;
  1799. listOfAnimation[i].frameRate = frameRate;
  1800. listOfAnimation[i].tickRate = tickRate;
  1801. listOfAnimation[i].quat = NULL;
  1802. listOfAnimation[i].pos = NULL;
  1803. listOfAnimation[i].shapeId = 0xffffffff;
  1804. }
  1805. else
  1806. {
  1807. //Start with No Animation Data for this Node.
  1808. strcpy(listOfAnimation[i].nodeId,"NONE");
  1809. listOfAnimation[i].numFrames = numFrames;
  1810. listOfAnimation[i].frameRate = frameRate;
  1811. listOfAnimation[i].tickRate = tickRate;
  1812. listOfAnimation[i].quat = NULL;
  1813. listOfAnimation[i].pos = NULL;
  1814. listOfAnimation[i].shapeId = 0xffffffff;
  1815. //---------------------------------
  1816. // Check for positional data first!
  1817. char* scanStart = animScan;
  1818. char numData[512];
  1819. char nextLine[1024];
  1820. float timeStamp = firstFrame * tickRate;
  1821. //----------------------------------------------------
  1822. // Then the very NEXT LINE most be POS_TRACK data OR
  1823. // there is ONLY rotational Data for this node.
  1824. GetNextLine(animScan,nextLine);
  1825. if (strstr(nextLine,ASE_ANIM_POS_HEADER) != NULL)
  1826. {
  1827. animScan = strstr(animScan,ASE_ANIM_POS_HEADER);
  1828. if (animScan)
  1829. {
  1830. countUp = true;
  1831. actualCount++;
  1832. animScan += strlen(ASE_ANIM_POS_HEADER);
  1833. //-----------------------------------------------------------
  1834. // We have positional data at least. Store everything off.
  1835. listOfAnimation[i].pos = (Stuff::Point3D *)TG_Shape::tglHeap->Malloc(sizeof(Stuff::Point3D) * numFrames);
  1836. strcpy(listOfAnimation[i].nodeId,nodeId);
  1837. listOfAnimation[i].numFrames = numFrames;
  1838. listOfAnimation[i].frameRate = frameRate;
  1839. listOfAnimation[i].tickRate = tickRate;
  1840. listOfAnimation[i].shapeId = 0xffffffff;
  1841. Stuff::Point3D thisOffset = shape->GetNodeCenter(i);
  1842. char LineData[1024];
  1843. GetNextLine(animScan,LineData);
  1844. animScan += strlen(LineData)+1;
  1845. for (long j=0;j<listOfAnimation[i].numFrames;j++)
  1846. {
  1847. char *scanData;
  1848. sprintf(nodeName,"%s %d",ASE_ANIM_POS_SAMPLE,(long)timeStamp);
  1849. scanData = strstr(LineData,nodeName);
  1850. if (scanData)
  1851. {
  1852. scanData += strlen(nodeName)+1;
  1853. GetNumberData(scanData,numData);
  1854. thisOffset.x = -(float)atof(numData);
  1855. scanData += strlen(numData)+1;
  1856. GetNumberData(scanData,numData);
  1857. thisOffset.z = (float)atof(numData);
  1858. scanData += strlen(numData)+1;
  1859. GetNumberData(scanData,numData);
  1860. thisOffset.y = (float)atof(numData);
  1861. scanData += strlen(numData)+1;
  1862. GetNextLine(animScan,LineData);
  1863. animScan += strlen(LineData)+1;
  1864. }
  1865. else
  1866. {
  1867. //Otherwise Node Center did not move. Use last Node Center
  1868. }
  1869. listOfAnimation[i].pos[j] = thisOffset;
  1870. timeStamp += tickRate;
  1871. }
  1872. }
  1873. }
  1874. //-------------------------------------------------------------
  1875. // Check for rotational data. Again, use nextLine.
  1876. //----------------------------------------------------
  1877. // Then the very NEXT LINE most be POS_TRACK data OR
  1878. // there is ONLY rotational Data for this node.
  1879. GetNextLine(animScan,nextLine);
  1880. if (strstr(nextLine,ASE_ANIM_ROT_HEADER) != NULL)
  1881. {
  1882. animScan = scanStart;
  1883. timeStamp = firstFrame * tickRate;
  1884. animScan = strstr(animScan,ASE_ANIM_ROT_HEADER);
  1885. if (animScan)
  1886. {
  1887. countUp = true;
  1888. actualCount++;
  1889. animScan += strlen(ASE_ANIM_ROT_HEADER);
  1890. //-----------------------------------------------------------
  1891. // We have rotational data at least. Store everything off.
  1892. listOfAnimation[i].quat = (Stuff::UnitQuaternion *)TG_Shape::tglHeap->Malloc(sizeof(Stuff::UnitQuaternion) * numFrames);
  1893. gosASSERT(listOfAnimation[i].quat != NULL);
  1894. //-------------------------------------------
  1895. // Setup basic variables. May do this twice.
  1896. strcpy(listOfAnimation[i].nodeId,nodeId);
  1897. listOfAnimation[i].numFrames = numFrames;
  1898. listOfAnimation[i].frameRate = frameRate;
  1899. listOfAnimation[i].tickRate = tickRate;
  1900. char LineData[1024];
  1901. GetNextLine(animScan,LineData);
  1902. animScan += strlen(LineData)+1;
  1903. for (long j=0;j<listOfAnimation[i].numFrames;j++)
  1904. {
  1905. char *scanData;
  1906. sprintf(nodeName,"%s %d",ASE_ANIM_ROT_SAMPLE,(long)timeStamp);
  1907. scanData = strstr(LineData,nodeName);
  1908. Stuff::UnitQuaternion thisFrame;
  1909. float b=0.0f,c=0.0f,d=0.0f,phi=0.0f;
  1910. if (scanData)
  1911. {
  1912. scanData += strlen(nodeName)+1;
  1913. GetNumberData(scanData,numData);
  1914. b = (float)atof(numData);
  1915. scanData += strlen(numData)+1;
  1916. GetNumberData(scanData,numData);
  1917. c = (float)atof(numData);
  1918. scanData += strlen(numData)+1;
  1919. GetNumberData(scanData,numData);
  1920. d = (float)atof(numData);
  1921. scanData += strlen(numData)+1;
  1922. GetNumberData(scanData,numData);
  1923. phi = (float)atof(numData);
  1924. GetNextLine(animScan,LineData);
  1925. animScan += strlen(LineData)+1;
  1926. //--------------------------------------------
  1927. // MAX Writes out Quaternions as Angle, Axis.
  1928. // Must Convert to real quaternion here.
  1929. thisFrame.w = (float)cos(phi / 2.0f);
  1930. thisFrame.x = b * (float)sin(phi / 2.0f);
  1931. thisFrame.y = d * (float)sin(-phi / 2.0f);
  1932. thisFrame.z = c * (float)sin(-phi / 2.0f);
  1933. }
  1934. else
  1935. {
  1936. //Otherwise rotation is 0.
  1937. thisFrame.w = 1.0f;
  1938. thisFrame.x = 0.0f;
  1939. thisFrame.y = 0.0f;
  1940. thisFrame.z = 0.0f;
  1941. }
  1942. if (!j)
  1943. {
  1944. thisFrame.Normalize();
  1945. listOfAnimation[i].quat[j] = thisFrame;
  1946. }
  1947. else
  1948. {
  1949. thisFrame.Normalize();
  1950. listOfAnimation[i].quat[j].Multiply(listOfAnimation[i].quat[j-1],thisFrame);
  1951. listOfAnimation[i].quat[j].Normalize();
  1952. }
  1953. timeStamp += tickRate;
  1954. }
  1955. }
  1956. }
  1957. countUp = false;
  1958. }
  1959. }
  1960. free(aseContents);
  1961. aseContents = NULL;
  1962. SaveBinaryCopy(binaryFileName);
  1963. }
  1964. return(0);
  1965. }
  1966. //-------------------------------------------------------------------------------
  1967. //This function copies the pointers to the animation data in this class to the
  1968. //TG_MultiShape being drawn. Nothing else happens.
  1969. void TG_AnimateShape::SetAnimationState (TG_MultiShapePtr shape)
  1970. {
  1971. long i=0;
  1972. shape->ClearAnimation();
  1973. if (!shapeIdsSet)
  1974. {
  1975. for (long j=0;j<count;j++)
  1976. {
  1977. bool foundNode = false;
  1978. for (i=0;i<shape->GetNumShapes();i++)
  1979. {
  1980. if (stricmp(listOfAnimation[j].nodeId,shape->GetNodeId(i)) == 0)
  1981. {
  1982. shape->SetCurrentAnimation(i,&listOfAnimation[j]);
  1983. listOfAnimation[j].shapeId = i;
  1984. foundNode = true;
  1985. break;
  1986. }
  1987. }
  1988. if (!foundNode)
  1989. listOfAnimation[j].shapeId = -1; //This node is missing. Probably an arm off!
  1990. }
  1991. shapeIdsSet = true;
  1992. }
  1993. else
  1994. {
  1995. for (long j=0;j<count;j++)
  1996. {
  1997. if (listOfAnimation[j].shapeId != 0xffffffff)
  1998. shape->SetCurrentAnimation(listOfAnimation[j].shapeId,&listOfAnimation[j]);
  1999. }
  2000. }
  2001. }
  2002. //-------------------------------------------------------------------------------