Gvactor.cpp 84 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906
  1. //---------------------------------------------------------------------------
  2. //
  3. // gvactor.cpp - This file contains the code for the Ground Vehicle Actor class
  4. //
  5. // MechCommander 2
  6. //
  7. //---------------------------------------------------------------------------//
  8. // Copyright (C) Microsoft Corporation. All rights reserved. //
  9. //===========================================================================//
  10. #ifndef GVACTOR_H
  11. #include "gvactor.h"
  12. #endif
  13. #ifndef CAMERA_H
  14. #include "camera.h"
  15. #endif
  16. #ifndef DBASEGUI_H
  17. #include "dbasegui.h"
  18. #endif
  19. #ifndef MECH3D_H
  20. #include "mech3d.h"
  21. #endif
  22. #ifndef OBJSTATUS_H
  23. #include "objstatus.h"
  24. #endif
  25. #ifndef CIDENT_H
  26. #include "cident.h"
  27. #endif
  28. #ifndef PATHS_H
  29. #include "paths.h"
  30. #endif
  31. #ifndef USERINPUT_H
  32. #include "userinput.h"
  33. #endif
  34. #ifndef TIMING_H
  35. #include "timing.h"
  36. #endif
  37. #ifndef UTILITIES_H
  38. #include "utilities.h"
  39. #endif
  40. #ifndef CEVFX_H
  41. #include "cevfx.h"
  42. #endif
  43. #ifndef TXMMGR_H
  44. #include "txmmgr.h"
  45. #endif
  46. #ifndef ERR_H
  47. #include "err.h"
  48. #endif
  49. #ifndef WEAPONFX_H
  50. #include "weaponfx.h"
  51. #endif
  52. #ifndef MOVE_H
  53. #include "move.h"
  54. #endif
  55. //******************************************************************************************
  56. extern float worldUnitsPerMeter;
  57. extern bool drawTerrainGrid;
  58. extern bool useFog;
  59. extern long mechRGBLookup[];
  60. extern long mechRGBLookup2[];
  61. extern bool useShadows;
  62. extern long ObjectTextureSize;
  63. TG_TypeMultiShapePtr GVAppearanceType::SensorTriangleShape = NULL;
  64. TG_TypeMultiShapePtr GVAppearanceType::SensorCircleShape = NULL;
  65. extern bool reloadBounds;
  66. #define SPIN_RATE 90.0f
  67. #define EXPAND_FACTOR (1.25f)
  68. #define MAX_SMOKE_NODES 2
  69. #define MAX_WEAPON_NODES 4
  70. #define MAX_FOOT_NODES 2
  71. extern MidLevelRenderer::MLRClipper * theClipper;
  72. extern bool MLRVertexLimitReached;
  73. extern bool InEditor;
  74. extern bool useNonWeaponEffects;
  75. extern bool useHighObjectDetail;
  76. //-----------------------------------------------------------------------------
  77. // class GVAppearanceType
  78. void GVAppearanceType::init (char * fileName)
  79. {
  80. AppearanceType::init(fileName);
  81. //----------------------------------------------
  82. FullPathFileName iniName;
  83. iniName.init(tglPath,fileName,".ini");
  84. FitIniFile iniFile;
  85. long result = iniFile.open(iniName);
  86. if (result != NO_ERR)
  87. Fatal(result,"Could not find vehicle appearance INI file");
  88. result = iniFile.seekBlock("TGLData");
  89. if (result != NO_ERR)
  90. Fatal(result,"Could not find block in vehicle appearance INI file");
  91. char aseFileName[512];
  92. result = iniFile.readIdString("FileName",aseFileName,511);
  93. if (result != NO_ERR)
  94. {
  95. //Check for LOD filenames instead
  96. for (long i=0;i<MAX_LODS;i++)
  97. {
  98. char baseName[256];
  99. char baseLODDist[256];
  100. sprintf(baseName,"FileName%d",i);
  101. sprintf(baseLODDist,"Distance%d",i);
  102. result = iniFile.readIdString(baseName,aseFileName,511);
  103. if (result == NO_ERR)
  104. {
  105. result = iniFile.readIdFloat(baseLODDist,lodDistance[i]);
  106. if (result != NO_ERR)
  107. STOP(("LOD %d has no distance value in file %s",i,fileName));
  108. //----------------------------------------------
  109. // Base LOD shape. In stand Pose by default.
  110. gvShape[i] = new TG_TypeMultiShape;
  111. gosASSERT(gvShape[i] != NULL);
  112. FullPathFileName gvName;
  113. gvName.init(tglPath,aseFileName,".ase");
  114. gvShape[i]->LoadTGMultiShapeFromASE(gvName);
  115. }
  116. else if (!i)
  117. {
  118. STOP(("No base LOD for shape %s",fileName));
  119. }
  120. }
  121. }
  122. else
  123. {
  124. //----------------------------------------------
  125. // Base shape. In stand Pose by default.
  126. gvShape[0] = new TG_TypeMultiShape;
  127. gosASSERT(gvShape[0] != NULL);
  128. FullPathFileName gvName;
  129. gvName.init(tglPath,aseFileName,".ase");
  130. gvShape[0]->LoadTGMultiShapeFromASE(gvName);
  131. }
  132. result = iniFile.readIdString("ShadowName",aseFileName,511);
  133. if (result == NO_ERR)
  134. {
  135. //----------------------------------------------
  136. // Base Shadow shape.
  137. gvShadowShape = new TG_TypeMultiShape;
  138. gosASSERT(gvShadowShape != NULL);
  139. FullPathFileName gvName;
  140. gvName.init(tglPath,aseFileName,".ase");
  141. gvShadowShape->LoadTGMultiShapeFromASE(gvName);
  142. }
  143. result = iniFile.seekBlock("TGLDamage");
  144. if (result == NO_ERR)
  145. {
  146. result = iniFile.readIdString("FileName",aseFileName,511);
  147. if (result != NO_ERR)
  148. Fatal(result,"Could not find ASE FileName in building appearance INI file");
  149. FullPathFileName dmgName;
  150. dmgName.init(tglPath,aseFileName,".ase");
  151. gvDmgShape = new TG_TypeMultiShape;
  152. gosASSERT(gvDmgShape != NULL);
  153. gvDmgShape->LoadTGMultiShapeFromASE(dmgName);
  154. if (!gvDmgShape->GetNumShapes())
  155. {
  156. delete gvDmgShape;
  157. gvDmgShape = NULL;
  158. }
  159. }
  160. else
  161. {
  162. gvDmgShape = NULL;
  163. }
  164. result = iniFile.seekBlock("TGLDestructEffect");
  165. if (result == NO_ERR)
  166. {
  167. result = iniFile.readIdString("FileName",destructEffect,59);
  168. if (result != NO_ERR)
  169. STOP(("Could not Find DestructEffectName in building appearance INI file"));
  170. }
  171. else
  172. {
  173. destructEffect[0] = 0;
  174. }
  175. //--------------------------------------------------------------------
  176. // Load Animation Information.
  177. // We can load up to 10 Animation States.
  178. for (long i=0;i<MAX_GV_ANIMATIONS;i++)
  179. {
  180. char blockId[512];
  181. sprintf(blockId,"Animation:%d",i);
  182. result = iniFile.seekBlock(blockId);
  183. if (result == NO_ERR)
  184. {
  185. char animName[512];
  186. result = iniFile.readIdString("AnimationName",animName,511);
  187. gosASSERT(result == NO_ERR);
  188. result = iniFile.readIdBoolean("LoopAnimation",gvAnimLoop[i]);
  189. gosASSERT(result == NO_ERR);
  190. result = iniFile.readIdBoolean("Reverse",gvReverse[i]);
  191. gosASSERT(result == NO_ERR);
  192. result = iniFile.readIdBoolean("Random",gvRandom[i]);
  193. gosASSERT(result == NO_ERR);
  194. result = iniFile.readIdLong("StartFrame",gvStartF[i]);
  195. if (result != NO_ERR)
  196. gvStartF[i] = 0;
  197. //-------------------------------
  198. // We have an animation to load.
  199. FullPathFileName animPath;
  200. animPath.init(tglPath,animName,".ase");
  201. FullPathFileName otherPath;
  202. otherPath.init(tglPath,animName,".agl");
  203. if (fileExists(animPath) || fileExists(otherPath))
  204. {
  205. gvAnimData[i] = new TG_AnimateShape;
  206. gosASSERT(gvAnimData[i] != NULL);
  207. //--------------------------------------------------------
  208. // If this animation does not exist, it is not a problem!
  209. // Building will simply freeze until animation is "over"
  210. gvAnimData[i]->LoadTGMultiShapeAnimationFromASE(animPath,gvShape[0]);
  211. }
  212. else
  213. gvAnimData[i] = NULL;
  214. }
  215. else
  216. {
  217. gvAnimData[i] = NULL;
  218. }
  219. }
  220. //--------------------------------------------------------------------
  221. // We can also load the node to yaw for vehicles with turrets.
  222. result = iniFile.seekBlock("AnimationNode");
  223. if (result == NO_ERR)
  224. {
  225. result = iniFile.readIdString("AnimationNodeId",rotationalNodeId,24);
  226. gosASSERT(result == NO_ERR);
  227. }
  228. else
  229. {
  230. strcpy(rotationalNodeId,"NONE");
  231. }
  232. //-----------------------------------------------
  233. // Load up the Node Data.
  234. // Automatic for vehicles now.
  235. numSmokeNodes = MAX_SMOKE_NODES;
  236. numWeaponNodes = MAX_WEAPON_NODES;
  237. numFootNodes = MAX_FOOT_NODES;
  238. nodeData = (NodeData *)AppearanceTypeList::appearanceHeap->Malloc(sizeof(NodeData)*(numWeaponNodes+numSmokeNodes+numFootNodes));
  239. gosASSERT(nodeData != NULL);
  240. memset(nodeData,0,sizeof(NodeData)*(numWeaponNodes+numSmokeNodes+numFootNodes));
  241. for (i=1;i<=numSmokeNodes;i++)
  242. {
  243. char blockId[512];
  244. sprintf(blockId,"Smoke_%02d",i);
  245. nodeData[i-1].nodeId = (char *)AppearanceTypeList::appearanceHeap->Malloc(strlen(blockId)+1);
  246. gosASSERT(nodeData[i-1].nodeId != NULL);
  247. strcpy(nodeData[i-1].nodeId,blockId);
  248. nodeData[i-1].weaponType = MECH3D_WEAPONTYPE_NONE;
  249. }
  250. for (i=1;i<=numWeaponNodes;i++)
  251. {
  252. char blockId[512];
  253. sprintf(blockId,"Weapon_%02d",i);
  254. nodeData[(i-1)+numSmokeNodes].nodeId = (char *)AppearanceTypeList::appearanceHeap->Malloc(strlen(blockId)+1);
  255. gosASSERT(nodeData[(i-1)+numSmokeNodes].nodeId != NULL);
  256. strcpy(nodeData[(i-1)+numSmokeNodes].nodeId,blockId);
  257. nodeData[(i-1)+numSmokeNodes].weaponType = MECH3D_WEAPONTYPE_ANY;
  258. }
  259. for (i=1;i<=numFootNodes;i++)
  260. {
  261. char blockId[512];
  262. sprintf(blockId,"FootNode_%02d",i);
  263. nodeData[(i-1)+numSmokeNodes+numWeaponNodes].nodeId = (char *)AppearanceTypeList::appearanceHeap->Malloc(strlen(blockId)+1);
  264. gosASSERT(nodeData[(i-1)+numSmokeNodes+numWeaponNodes].nodeId != NULL);
  265. strcpy(nodeData[(i-1)+numSmokeNodes+numWeaponNodes].nodeId,blockId);
  266. nodeData[(i-1)+numSmokeNodes+numWeaponNodes].weaponType = MECH3D_WEAPONTYPE_NONE;
  267. }
  268. //----------------------------------------------
  269. // Load up sensor Shape if not yet defined.
  270. if (SensorCircleShape == NULL)
  271. {
  272. FullPathFileName sensorName;
  273. sensorName.init(tglPath,"circularcontact",".ase");
  274. SensorCircleShape = new TG_TypeMultiShape;
  275. gosASSERT(SensorCircleShape != NULL);
  276. SensorCircleShape->LoadTGMultiShapeFromASE(sensorName);
  277. }
  278. if (SensorTriangleShape == NULL)
  279. {
  280. FullPathFileName sensorName;
  281. sensorName.init(tglPath,"trianglecontact",".ase");
  282. SensorTriangleShape = new TG_TypeMultiShape;
  283. gosASSERT(SensorCircleShape != NULL);
  284. SensorTriangleShape->LoadTGMultiShapeFromASE(sensorName);
  285. }
  286. }
  287. //----------------------------------------------------------------------------
  288. void GVAppearanceType::destroy (void)
  289. {
  290. AppearanceType::destroy();
  291. for (long i=0;i<MAX_LODS;i++)
  292. {
  293. if (gvShape[i])
  294. {
  295. delete gvShape[i];
  296. gvShape[i] = NULL;
  297. }
  298. }
  299. if (gvShadowShape)
  300. {
  301. delete gvShadowShape;
  302. gvShadowShape = NULL;
  303. }
  304. if (gvDmgShape)
  305. {
  306. delete gvDmgShape;
  307. gvDmgShape = NULL;
  308. }
  309. for (i=0;i<MAX_GV_ANIMATIONS;i++)
  310. {
  311. delete gvAnimData[i];
  312. gvAnimData[i] = NULL;
  313. }
  314. if (nodeData)
  315. {
  316. for (i=0;i<getTotalNodes();i++)
  317. {
  318. AppearanceTypeList::appearanceHeap->Free(nodeData[i].nodeId);
  319. nodeData[i].nodeId = NULL;
  320. }
  321. AppearanceTypeList::appearanceHeap->Free(nodeData);
  322. nodeData = NULL;
  323. }
  324. }
  325. //-----------------------------------------------------------------------------
  326. void GVAppearanceType::setAnimation (TG_MultiShapePtr shape, DWORD animationNum)
  327. {
  328. gosASSERT(shape != NULL);
  329. gosASSERT(animationNum != 0xffffffff);
  330. gosASSERT(animationNum < MAX_GV_ANIMATIONS);
  331. if (gvAnimData[animationNum])
  332. gvAnimData[animationNum]->SetAnimationState(shape);
  333. else
  334. shape->ClearAnimation();
  335. }
  336. //-----------------------------------------------------------------------------
  337. Stuff::Vector3D debugGVActorPosition;
  338. float vehicleDebugAngle = 0.0;
  339. float turretDebugAngle = 0.0;
  340. float debugVelMag = 0.0;
  341. #define BASE_NODE_RECYCLE_TIME 0.25f
  342. //-----------------------------------------------------------------------------
  343. // class GVAppearance
  344. void GVAppearance::setWeaponNodeUsed (long weaponNode)
  345. {
  346. weaponNode -= appearType->numSmokeNodes;
  347. if ((weaponNode >= 0) && (weaponNode < appearType->numWeaponNodes))
  348. {
  349. nodeUsed[weaponNode]++;
  350. nodeRecycle[weaponNode] = BASE_NODE_RECYCLE_TIME;
  351. }
  352. }
  353. //-----------------------------------------------------------------------------
  354. Stuff::Vector3D GVAppearance::getWeaponNodePosition (long nodeId)
  355. {
  356. Stuff::Vector3D result = position;
  357. if ((nodeId < appearType->numSmokeNodes) || (nodeId >= (appearType->numSmokeNodes+appearType->numWeaponNodes)))
  358. return result;
  359. if (!inView)
  360. return result;
  361. //We already know we are using this node. Do NOT increment recycle or nodeUsed!
  362. //-------------------------------------------
  363. // Create Matrix to conform to.
  364. Stuff::UnitQuaternion qRotation;
  365. float yaw = rotation * DEGREES_TO_RADS;
  366. qRotation = Stuff::EulerAngles(0.0f, yaw, 0.0f);
  367. Stuff::Point3D xlatPosition;
  368. xlatPosition.x = -position.x;
  369. xlatPosition.y = position.z;
  370. xlatPosition.z = position.y;
  371. Stuff::UnitQuaternion torsoRot;
  372. torsoRot = Stuff::EulerAngles(0.0f,(turretRotation * DEGREES_TO_RADS),0.0f);
  373. if (rotationalNodeIndex == -1)
  374. rotationalNodeIndex = gvShape->SetNodeRotation(appearType->rotationalNodeId,&torsoRot);
  375. gvShape->SetNodeRotation(rotationalNodeIndex,&torsoRot);
  376. if (weaponNodeId[nodeId - appearType->numSmokeNodes] == -1)
  377. weaponNodeId[nodeId - appearType->numSmokeNodes] = gvShape->GetNodeNameId(appearType->nodeData[nodeId].nodeId);
  378. //If its STILL -1, we don't really have four weapon nodes.
  379. // Mark it with -2 to let us know to ignore it from now on.
  380. if (weaponNodeId[nodeId - appearType->numSmokeNodes] == -1)
  381. weaponNodeId[nodeId - appearType->numSmokeNodes] = -2;
  382. if (weaponNodeId[nodeId - appearType->numSmokeNodes] >= 0)
  383. result = gvShape->GetTransformedNodePosition(&xlatPosition,&qRotation,weaponNodeId[nodeId - appearType->numSmokeNodes]);
  384. if ((result.x == 0.0f) &&
  385. (result.y == 0.0f) &&
  386. (result.z == 0.0f))
  387. result = position;
  388. return result;
  389. }
  390. //-----------------------------------------------------------------------------
  391. Stuff::Vector3D GVAppearance::getSmokeNodePosition (long nodeId)
  392. {
  393. Stuff::Vector3D result = position;
  394. if ((nodeId < 0) || (nodeId >= appearType->numSmokeNodes))
  395. return result;
  396. if (!inView)
  397. return result;
  398. //-------------------------------------------
  399. // Create Matrix to conform to.
  400. Stuff::UnitQuaternion qRotation;
  401. float yaw = rotation * DEGREES_TO_RADS;
  402. qRotation = Stuff::EulerAngles(0.0f, yaw, 0.0f);
  403. Stuff::Point3D xlatPosition;
  404. xlatPosition.x = -position.x;
  405. xlatPosition.y = position.z;
  406. xlatPosition.z = position.y;
  407. Stuff::UnitQuaternion torsoRot;
  408. torsoRot = Stuff::EulerAngles(0.0f,(turretRotation * DEGREES_TO_RADS),0.0f);
  409. if (rotationalNodeIndex == -1)
  410. rotationalNodeIndex = gvShape->SetNodeRotation(appearType->rotationalNodeId,&torsoRot);
  411. gvShape->SetNodeRotation(rotationalNodeIndex,&torsoRot);
  412. result = gvShape->GetTransformedNodePosition(&xlatPosition,&qRotation,appearType->nodeData[nodeId].nodeId);
  413. return result;
  414. }
  415. //-----------------------------------------------------------------------------
  416. Stuff::Vector3D GVAppearance::getDustNodePosition (long nodeId)
  417. {
  418. Stuff::Vector3D result = position;
  419. if ((nodeId < 0) || (nodeId >= appearType->numFootNodes))
  420. return result;
  421. if (!inView)
  422. return result;
  423. //-------------------------------------------
  424. // Create Matrix to conform to.
  425. Stuff::UnitQuaternion qRotation;
  426. float yaw = rotation * DEGREES_TO_RADS;
  427. qRotation = Stuff::EulerAngles(0.0f, yaw, 0.0f);
  428. Stuff::Point3D xlatPosition;
  429. xlatPosition.x = -position.x;
  430. xlatPosition.y = position.z;
  431. xlatPosition.z = position.y;
  432. Stuff::UnitQuaternion torsoRot;
  433. torsoRot = Stuff::EulerAngles(0.0f,(turretRotation * DEGREES_TO_RADS),0.0f);
  434. if (rotationalNodeIndex == -1)
  435. rotationalNodeIndex = gvShape->SetNodeRotation(appearType->rotationalNodeId,&torsoRot);
  436. gvShape->SetNodeRotation(rotationalNodeIndex,&torsoRot);
  437. result = gvShape->GetTransformedNodePosition(&xlatPosition,&qRotation,appearType->nodeData[nodeId+appearType->numWeaponNodes+appearType->numSmokeNodes].nodeId);
  438. return result;
  439. }
  440. //-----------------------------------------------------------------------------
  441. long GVAppearance::getLowestWeaponNode (void)
  442. {
  443. //------------------------------------------------
  444. // Scan all weapon nodes and find least used one.
  445. long bestNode = -1;
  446. float lowestPosZ;
  447. long numSmokeNodes = appearType->numSmokeNodes;
  448. lowestPosZ = 9999999999999.0f;
  449. for (long i=0;i<appearType->numWeaponNodes;i++)
  450. {
  451. Stuff::Vector3D nodePosition = getWeaponNodePosition(i+numSmokeNodes);
  452. if (((nodePosition.z - position.z) < lowestPosZ) && (nodePosition.z != position.z))
  453. {
  454. lowestPosZ = nodePosition.z - position.z;
  455. bestNode = i+numSmokeNodes;
  456. }
  457. }
  458. if ((lowestPosZ == 0.0f) || (bestNode < 0) || (bestNode >= appearType->getTotalNodes()))
  459. return -1;
  460. return bestNode;
  461. }
  462. //-----------------------------------------------------------------------------
  463. long GVAppearance::getWeaponNode (long weaponType)
  464. {
  465. //------------------------------------------------
  466. // Scan all weapon nodes and find least used one.
  467. long leastUsed = 999999999;
  468. long bestNode = -1;
  469. long numSmokeNodes = appearType->numSmokeNodes;
  470. for (long i=0;i<appearType->numWeaponNodes;i++)
  471. {
  472. //This weaponNode does not exist if its -2
  473. if (weaponNodeId[i] == -2)
  474. continue;
  475. switch (weaponType)
  476. {
  477. case MECH3D_WEAPONTYPE_MISSILE:
  478. if ((appearType->nodeData[numSmokeNodes+i].weaponType == weaponType) ||
  479. (appearType->nodeData[numSmokeNodes+i].weaponType == MECH3D_WEAPONTYPE_ANY) ||
  480. (appearType->nodeData[numSmokeNodes+i].weaponType == MECH3D_WEAPONTYPE_NONENERGY))
  481. {
  482. // if (getWeaponNodePosition(i + numSmokeNodes).z != position.z)
  483. // {
  484. if (nodeUsed[i] < leastUsed)
  485. {
  486. leastUsed = nodeUsed[i];
  487. bestNode = i + numSmokeNodes;
  488. }
  489. // }
  490. }
  491. break;
  492. case MECH3D_WEAPONTYPE_BALLISTIC:
  493. if ((appearType->nodeData[numSmokeNodes+i].weaponType == weaponType) ||
  494. (appearType->nodeData[numSmokeNodes+i].weaponType == MECH3D_WEAPONTYPE_ANY) ||
  495. (appearType->nodeData[numSmokeNodes+i].weaponType == MECH3D_WEAPONTYPE_NONENERGY))
  496. {
  497. // if (getWeaponNodePosition(i + numSmokeNodes).z != position.z)
  498. // {
  499. if (nodeUsed[i] < leastUsed)
  500. {
  501. leastUsed = nodeUsed[i];
  502. bestNode = i + numSmokeNodes;
  503. }
  504. // }
  505. }
  506. break;
  507. case MECH3D_WEAPONTYPE_ENERGY:
  508. if ((appearType->nodeData[numSmokeNodes+i].weaponType == weaponType) ||
  509. (appearType->nodeData[numSmokeNodes+i].weaponType == MECH3D_WEAPONTYPE_ANY))
  510. {
  511. // if (getWeaponNodePosition(i + numSmokeNodes).z != position.z)
  512. // {
  513. if (nodeUsed[i] < leastUsed)
  514. {
  515. leastUsed = nodeUsed[i];
  516. bestNode = i + numSmokeNodes;
  517. }
  518. // }
  519. }
  520. break;
  521. case MECH3D_WEAPONTYPE_ANY:
  522. // if (getWeaponNodePosition(i + numSmokeNodes).z != position.z)
  523. // {
  524. if (nodeUsed[i] < leastUsed)
  525. {
  526. leastUsed = nodeUsed[i];
  527. bestNode = i + numSmokeNodes;
  528. }
  529. // }
  530. break;
  531. default:
  532. STOP(("Sent down a bad weapon type %d",weaponType));
  533. }
  534. }
  535. if ((bestNode < 0) || (bestNode >= appearType->getTotalNodes()))
  536. return -1;
  537. return bestNode;
  538. }
  539. //-----------------------------------------------------------------------------
  540. float GVAppearance::getWeaponNodeRecycle (long node)
  541. {
  542. node -= appearType->numSmokeNodes;
  543. if ((node >=0) && (node < appearType->numWeaponNodes))
  544. return nodeRecycle[node];
  545. return 9999.0f; //NOT a weapon node. Never recycled!!
  546. }
  547. //-----------------------------------------------------------------------------
  548. void GVAppearance::init (AppearanceTypePtr tree, GameObjectPtr obj)
  549. {
  550. Appearance::init(tree,obj);
  551. appearType = (GVAppearanceType *)tree;
  552. shapeMin.x = shapeMin.y = -25;
  553. shapeMax.x = shapeMax.y = 50;
  554. paintScheme = -1;
  555. objectNameId = 30862;
  556. pilotNameID = -1;
  557. hazeFactor = 0.0f;
  558. currentFlash = duration = flashDuration = 0.0f;
  559. flashColor = 0x00000000;
  560. drawFlash = false;
  561. rotationalNodeIndex = -1;
  562. dustNodeIndex = activityNodeIndex = hitNodeId = weaponNodeId[0] = weaponNodeId[1] = weaponNodeId[2] = weaponNodeId[3] = -1;
  563. screenPos.x = screenPos.y = screenPos.z = screenPos.w = -999.0f;
  564. position.Zero();
  565. rotation = 0.0;;
  566. turretRotation= 0.0;
  567. selected = 0;
  568. teamId = -1;
  569. homeTeamRelationship = 0;
  570. actualRotation = rotation;
  571. actualTurretRotation = turretRotation;
  572. inDebugMoveMode = false;
  573. sensorLevel = 0;
  574. destructFX = NULL;
  575. status = 0;
  576. roll = pitch = 0.0f;
  577. currentLOD = 0;
  578. OBBRadius = 0.0f;
  579. sensorSpin = 0.0f;
  580. gvAnimationState =-1;
  581. currentFrame = 0.0f;
  582. gvFrameRate = 0.0f;
  583. isReversed = false;
  584. isLooping = false;
  585. setFirstFrame = false;
  586. canTransition = true;
  587. localTextureHandle = 0xffffffff;
  588. nodeUsed = NULL;
  589. nodeRecycle = NULL;
  590. waterWake = NULL;
  591. dustCloud = NULL;
  592. activity = NULL;
  593. isWaking = NULL;
  594. movedThisFrame = false;
  595. dustCloudStart = false;
  596. isActivitying = false;
  597. if (appearType)
  598. {
  599. gvShape = appearType->gvShape[0]->CreateFrom();
  600. //-------------------------------------------------
  601. // Load the texture and store its handle.
  602. for (long i=0;i<gvShape->GetNumTextures();i++)
  603. {
  604. char txmName[1024];
  605. gvShape->GetTextureName(i,txmName,256);
  606. char texturePath[1024];
  607. sprintf(texturePath,"%s%d\\",tglPath,ObjectTextureSize);
  608. FullPathFileName textureName;
  609. textureName.init(texturePath,txmName,"");
  610. if (fileExists(textureName))
  611. {
  612. if (strnicmp(txmName,"a_",2) == 0)
  613. {
  614. DWORD gosTextureHandle = 0;
  615. if (!i)
  616. {
  617. localTextureHandle = mcTextureManager->loadTexture(textureName,gos_Texture_Alpha,gosHint_DisableMipmap | gosHint_DontShrink,true);
  618. gvShape->SetTextureHandle(i,localTextureHandle);
  619. gvShape->SetTextureAlpha(i,true);
  620. }
  621. else
  622. {
  623. gosTextureHandle = mcTextureManager->loadTexture(textureName,gos_Texture_Alpha,gosHint_DisableMipmap | gosHint_DontShrink);
  624. gvShape->SetTextureHandle(i,gosTextureHandle);
  625. gvShape->SetTextureAlpha(i,true);
  626. }
  627. }
  628. else
  629. {
  630. DWORD gosTextureHandle = 0;
  631. if (!i)
  632. {
  633. localTextureHandle = mcTextureManager->loadTexture(textureName,gos_Texture_Solid,gosHint_DisableMipmap | gosHint_DontShrink,true);
  634. gvShape->SetTextureHandle(i,localTextureHandle);
  635. gvShape->SetTextureAlpha(i,false);
  636. }
  637. else
  638. {
  639. gosTextureHandle = mcTextureManager->loadTexture(textureName,gos_Texture_Solid,gosHint_DisableMipmap | gosHint_DontShrink);
  640. gvShape->SetTextureHandle(i,gosTextureHandle);
  641. gvShape->SetTextureAlpha(i,false);
  642. }
  643. }
  644. }
  645. else
  646. {
  647. //PAUSE(("Warning: %s texture name not found",textureName));
  648. gvShape->SetTextureHandle(i,0xffffffff);
  649. }
  650. }
  651. if (appearType->gvShadowShape)
  652. {
  653. gvShadowShape = appearType->gvShadowShape->CreateFrom();
  654. //-------------------------------------------------
  655. // Load the texture and store its handle.
  656. for (long i=0;i<gvShadowShape->GetNumTextures();i++)
  657. {
  658. char txmName[1024];
  659. gvShadowShape->GetTextureName(i,txmName,256);
  660. char texturePath[1024];
  661. sprintf(texturePath,"%s%d\\",tglPath,ObjectTextureSize);
  662. FullPathFileName textureName;
  663. textureName.init(texturePath,txmName,"");
  664. if (fileExists(textureName))
  665. {
  666. if (strnicmp(txmName,"a_",2) == 0)
  667. {
  668. DWORD gosTextureHandle = mcTextureManager->loadTexture(textureName,gos_Texture_Alpha,gosHint_DisableMipmap | gosHint_DontShrink);
  669. gosASSERT(gosTextureHandle != 0xffffffff);
  670. gvShadowShape->SetTextureHandle(i,gosTextureHandle);
  671. gvShadowShape->SetTextureAlpha(i,true);
  672. }
  673. else
  674. {
  675. DWORD gosTextureHandle = mcTextureManager->loadTexture(textureName,gos_Texture_Solid,gosHint_DisableMipmap | gosHint_DontShrink);
  676. gosASSERT(gosTextureHandle != 0xffffffff);
  677. gvShadowShape->SetTextureHandle(i,gosTextureHandle);
  678. gvShadowShape->SetTextureAlpha(i,false);
  679. }
  680. }
  681. else
  682. {
  683. gvShadowShape->SetTextureHandle(i,0xffffffff);
  684. }
  685. }
  686. }
  687. else
  688. {
  689. gvShadowShape = NULL;
  690. }
  691. sensorTriangleShape = GVAppearanceType::SensorTriangleShape->CreateFrom();
  692. //-------------------------------------------------
  693. // Load the texture and store its handle.
  694. for (i=0;i<sensorTriangleShape->GetNumTextures();i++)
  695. {
  696. char txmName[1024];
  697. sensorTriangleShape->GetTextureName(i,txmName,256);
  698. char texturePath[1024];
  699. sprintf(texturePath,"%s%d\\",tglPath,ObjectTextureSize);
  700. FullPathFileName textureName;
  701. textureName.init(texturePath,txmName,"");
  702. if (fileExists(textureName))
  703. {
  704. if (strnicmp(txmName,"a_",2) == 0)
  705. {
  706. DWORD gosTextureHandle = mcTextureManager->loadTexture(textureName,gos_Texture_Alpha,gosHint_DisableMipmap | gosHint_DontShrink);
  707. sensorTriangleShape->SetTextureHandle(i,gosTextureHandle);
  708. sensorTriangleShape->SetTextureAlpha(i,true);
  709. }
  710. else
  711. {
  712. DWORD gosTextureHandle = mcTextureManager->loadTexture(textureName,gos_Texture_Solid,gosHint_DisableMipmap | gosHint_DontShrink);
  713. sensorTriangleShape->SetTextureHandle(i,gosTextureHandle);
  714. sensorTriangleShape->SetTextureAlpha(i,false);
  715. }
  716. }
  717. else
  718. {
  719. //PAUSE(("Warning: %s texture name not found",textureName));
  720. sensorTriangleShape->SetTextureHandle(i,0xffffffff);
  721. }
  722. }
  723. sensorCircleShape = GVAppearanceType::SensorCircleShape->CreateFrom();
  724. //-------------------------------------------------
  725. // Load the texture and store its handle.
  726. for (i=0;i<sensorCircleShape->GetNumTextures();i++)
  727. {
  728. char txmName[1024];
  729. sensorCircleShape->GetTextureName(i,txmName,256);
  730. char texturePath[1024];
  731. sprintf(texturePath,"%s%d\\",tglPath,ObjectTextureSize);
  732. FullPathFileName textureName;
  733. textureName.init(texturePath,txmName,"");
  734. if (fileExists(textureName))
  735. {
  736. if (strnicmp(txmName,"a_",2) == 0)
  737. {
  738. DWORD gosTextureHandle = mcTextureManager->loadTexture(textureName,gos_Texture_Alpha,gosHint_DisableMipmap | gosHint_DontShrink);
  739. sensorCircleShape->SetTextureHandle(i,gosTextureHandle);
  740. sensorCircleShape->SetTextureAlpha(i,true);
  741. }
  742. else
  743. {
  744. DWORD gosTextureHandle = mcTextureManager->loadTexture(textureName,gos_Texture_Solid,gosHint_DisableMipmap | gosHint_DontShrink);
  745. sensorCircleShape->SetTextureHandle(i,gosTextureHandle);
  746. sensorCircleShape->SetTextureAlpha(i,false);
  747. }
  748. }
  749. else
  750. {
  751. //PAUSE(("Warning: %s texture name not found",textureName));
  752. sensorCircleShape->SetTextureHandle(i,0xffffffff);
  753. }
  754. }
  755. Stuff::Vector3D boxCoords[8];
  756. Stuff::Vector3D nodeCenter = gvShape->GetRootNodeCenter();
  757. boxCoords[0].x = position.x + gvShape->GetMinBox().x + nodeCenter.x;
  758. boxCoords[0].y = position.y + gvShape->GetMinBox().z + nodeCenter.z;
  759. boxCoords[0].z = position.z + gvShape->GetMaxBox().y + nodeCenter.y;
  760. boxCoords[1].x = position.x + gvShape->GetMinBox().x + nodeCenter.x;
  761. boxCoords[1].y = position.y + gvShape->GetMaxBox().z + nodeCenter.z;
  762. boxCoords[1].z = position.z + gvShape->GetMaxBox().y + nodeCenter.y;
  763. boxCoords[2].x = position.x + gvShape->GetMaxBox().x + nodeCenter.x;
  764. boxCoords[2].y = position.y + gvShape->GetMaxBox().z + nodeCenter.z;
  765. boxCoords[2].z = position.z + gvShape->GetMaxBox().y + nodeCenter.y;
  766. boxCoords[3].x = position.x + gvShape->GetMaxBox().x + nodeCenter.x;
  767. boxCoords[3].y = position.y + gvShape->GetMinBox().z + nodeCenter.z;
  768. boxCoords[3].z = position.z + gvShape->GetMaxBox().y + nodeCenter.y;
  769. boxCoords[4].x = position.x + gvShape->GetMinBox().x + nodeCenter.x;
  770. boxCoords[4].y = position.y + gvShape->GetMinBox().z + nodeCenter.z;
  771. boxCoords[4].z = position.z + gvShape->GetMinBox().y + nodeCenter.y;
  772. boxCoords[5].x = position.x + gvShape->GetMaxBox().x + nodeCenter.x;
  773. boxCoords[5].y = position.y + gvShape->GetMinBox().z + nodeCenter.z;
  774. boxCoords[5].z = position.z + gvShape->GetMinBox().y + nodeCenter.y;
  775. boxCoords[6].x = position.x + gvShape->GetMaxBox().x + nodeCenter.x;
  776. boxCoords[6].y = position.y + gvShape->GetMaxBox().z + nodeCenter.z;
  777. boxCoords[6].z = position.z + gvShape->GetMinBox().y + nodeCenter.y;
  778. boxCoords[7].x = position.x + gvShape->GetMinBox().x + nodeCenter.x;
  779. boxCoords[7].y = position.y + gvShape->GetMaxBox().z + nodeCenter.z;
  780. boxCoords[7].z = position.z + gvShape->GetMinBox().y + nodeCenter.y;
  781. float testRadius = 0.0;
  782. for (i=0;i<8;i++)
  783. {
  784. testRadius = boxCoords[i].GetLength();
  785. if (OBBRadius < testRadius)
  786. OBBRadius = testRadius;
  787. }
  788. appearType->boundsUpperLeftX = (-OBBRadius * 2.0);
  789. appearType->boundsUpperLeftY = (-OBBRadius * 2.0);
  790. appearType->boundsLowerRightX = (OBBRadius * 2.0);
  791. appearType->boundsLowerRightY = (OBBRadius);
  792. if (!appearType->getDesignerTypeBounds())
  793. {
  794. appearType->typeUpperLeft = gvShape->GetMinBox();
  795. appearType->typeLowerRight = gvShape->GetMaxBox();
  796. //Now expand box by some percentage to make selection easier.
  797. appearType->typeUpperLeft.x *= EXPAND_FACTOR;
  798. appearType->typeUpperLeft.y *= EXPAND_FACTOR;
  799. appearType->typeUpperLeft.z *= EXPAND_FACTOR;
  800. appearType->typeLowerRight.x *= EXPAND_FACTOR;
  801. appearType->typeLowerRight.y *= EXPAND_FACTOR;
  802. appearType->typeLowerRight.z *= EXPAND_FACTOR;
  803. }
  804. if (appearType->numWeaponNodes)
  805. {
  806. nodeUsed = (long *)AppearanceTypeList::appearanceHeap->Malloc(sizeof(long) * appearType->numWeaponNodes);
  807. gosASSERT(nodeUsed != NULL);
  808. memset(nodeUsed,0,sizeof(long) * appearType->numWeaponNodes);
  809. nodeRecycle = (float *)AppearanceTypeList::appearanceHeap->Malloc(sizeof(float) * appearType->numWeaponNodes);
  810. gosASSERT(nodeRecycle != NULL);
  811. for (long i=0;i<appearType->numWeaponNodes;i++)
  812. nodeRecycle[i] = 0.0f;
  813. }
  814. if (!InEditor)
  815. {
  816. if (!dustCloud && useNonWeaponEffects)
  817. {
  818. if (strcmp(weaponEffects->GetEffectName(VEHICLE_DUST_CLOUD),"NONE") != 0)
  819. {
  820. //--------------------------------------------
  821. // Yes, load it on up.
  822. unsigned flags = gosFX::Effect::ExecuteFlag|gosFX::Effect::LoopFlag;
  823. Check_Object(gosFX::EffectLibrary::Instance);
  824. gosFX::Effect::Specification* gosEffectSpec = gosFX::EffectLibrary::Instance->Find(weaponEffects->GetEffectName(VEHICLE_DUST_CLOUD));
  825. if (gosEffectSpec)
  826. {
  827. dustCloud = gosFX::EffectLibrary::Instance->MakeEffect(gosEffectSpec->m_effectID, flags);
  828. gosASSERT(dustCloud != NULL);
  829. MidLevelRenderer::MLRTexturePool::Instance->LoadImages();
  830. }
  831. }
  832. }
  833. }
  834. }
  835. }
  836. //-----------------------------------------------------------------------------
  837. void GVAppearance::setObjStatus (long oStatus)
  838. {
  839. if (status != oStatus)
  840. {
  841. if ((oStatus == OBJECT_STATUS_DESTROYED) || (oStatus == OBJECT_STATUS_DISABLED))
  842. {
  843. if (appearType->gvDmgShape)
  844. {
  845. gvShape->ClearAnimation();
  846. delete gvShape;
  847. gvShape = NULL;
  848. gvShape = appearType->gvDmgShape->CreateFrom();
  849. }
  850. currentLOD = 0;
  851. }
  852. if (oStatus == OBJECT_STATUS_NORMAL)
  853. {
  854. if (appearType->gvShape)
  855. {
  856. delete gvShape;
  857. gvShape = NULL;
  858. gvShape = appearType->gvShape[0]->CreateFrom();
  859. }
  860. currentLOD = 0;
  861. }
  862. //-------------------------------------------------
  863. // Load the texture and store its handle.
  864. for (long i=0;i<gvShape->GetNumTextures();i++)
  865. {
  866. char txmName[1024];
  867. gvShape->GetTextureName(i,txmName,256);
  868. char texturePath[1024];
  869. sprintf(texturePath,"%s%d\\",tglPath,ObjectTextureSize);
  870. FullPathFileName textureName;
  871. textureName.init(texturePath,txmName,"");
  872. if (fileExists(textureName))
  873. {
  874. if (strnicmp(txmName,"a_",2) == 0)
  875. {
  876. DWORD gosTextureHandle = 0;
  877. if (!i)
  878. {
  879. localTextureHandle = mcTextureManager->loadTexture(textureName,gos_Texture_Alpha,gosHint_DisableMipmap | gosHint_DontShrink,true);
  880. gvShape->SetTextureHandle(i,localTextureHandle);
  881. gvShape->SetTextureAlpha(i,true);
  882. }
  883. else
  884. {
  885. gosTextureHandle = mcTextureManager->loadTexture(textureName,gos_Texture_Alpha,gosHint_DisableMipmap | gosHint_DontShrink);
  886. gvShape->SetTextureHandle(i,gosTextureHandle);
  887. gvShape->SetTextureAlpha(i,true);
  888. }
  889. }
  890. else
  891. {
  892. DWORD gosTextureHandle = 0;
  893. if (!i)
  894. {
  895. localTextureHandle = mcTextureManager->loadTexture(textureName,gos_Texture_Solid,gosHint_DisableMipmap | gosHint_DontShrink,true);
  896. gvShape->SetTextureHandle(i,localTextureHandle);
  897. gvShape->SetTextureAlpha(i,false);
  898. }
  899. else
  900. {
  901. gosTextureHandle = mcTextureManager->loadTexture(textureName,gos_Texture_Solid,gosHint_DisableMipmap | gosHint_DontShrink);
  902. gvShape->SetTextureHandle(i,gosTextureHandle);
  903. gvShape->SetTextureAlpha(i,false);
  904. }
  905. }
  906. }
  907. else
  908. {
  909. //PAUSE(("Warning: %s texture name not found",textureName));
  910. gvShape->SetTextureHandle(i,0xffffffff);
  911. }
  912. }
  913. resetPaintScheme(psRed,psGreen,psBlue);
  914. }
  915. status = oStatus;
  916. }
  917. //-----------------------------------------------------------------------------
  918. void GVAppearance::setPaintScheme (void)
  919. {
  920. //----------------------------------------------------------------------------
  921. // Simple really. Get the texture memory, apply the paint scheme, let it go!
  922. DWORD gosHandle = mcTextureManager->get_gosTextureHandle(gvShape->GetTextureHandle(0));
  923. if (gosHandle && gosHandle != 0xffffffff)
  924. {
  925. //-------------------
  926. // Lock the texture.
  927. TEXTUREPTR textureData;
  928. gos_LockTexture(gosHandle, 0, 0, &textureData);
  929. //-------------------------------------------------------
  930. DWORD *textureMemory = textureData.pTexture;
  931. for (long i=0;i<textureData.Height;i++)
  932. {
  933. for (long j=0;j<textureData.Height;j++)
  934. {
  935. //---------------------------------------------
  936. // Make Color from PaintScheme.
  937. DWORD baseColor = *textureMemory;
  938. BYTE baseColorAlpha = ((baseColor & 0xff000000)>>24);
  939. float baseColorRed = float((baseColor & 0x00ff0000)>>16);
  940. float baseColorGreen = float((baseColor & 0x0000ff00)>>8);
  941. float baseColorBlue = float(baseColor & 0x000000ff);
  942. DWORD newColor = *textureMemory; //Black by default.
  943. if ((!baseColorGreen) && (!baseColorBlue))
  944. {
  945. baseColorRed *= 0.00390625f; //Divide by 256;
  946. baseColorRed = 1.0 - baseColorRed;
  947. baseColorRed *= baseColorRed; //Log colors
  948. baseColorRed = 1.0 - baseColorRed;
  949. float newColorRed = float((psRed & 0x00ff0000)>>16);
  950. newColorRed *= baseColorRed;
  951. unsigned char red = (unsigned char)newColorRed;
  952. float newColorGreen = float((psRed & 0x0000ff00)>>8);
  953. newColorGreen *= baseColorRed;
  954. unsigned char green = (unsigned char)newColorGreen;
  955. float newColorBlue = float(psRed & 0x000000ff);
  956. newColorBlue *= baseColorRed;
  957. unsigned char blue = (unsigned char)newColorBlue;
  958. newColor = (baseColorAlpha<<24) + (red<<16) + (green<<8) + (blue);
  959. }
  960. else if ((!baseColorRed) && (!baseColorBlue))
  961. {
  962. baseColorGreen *= 0.00390625f; //Divide by 256;
  963. baseColorGreen = 1.0 - baseColorGreen;
  964. baseColorGreen *= baseColorGreen; //Log colors
  965. baseColorGreen = 1.0 - baseColorGreen;
  966. float newColorRed = float((psGreen & 0x00ff0000)>>16);
  967. newColorRed *= baseColorGreen;
  968. unsigned char red = (unsigned char)newColorRed;
  969. float newColorGreen = float((psGreen & 0x0000ff00)>>8);
  970. newColorGreen *= baseColorGreen;
  971. unsigned char green = (unsigned char)newColorGreen;
  972. float newColorBlue = float(psGreen & 0x000000ff);
  973. newColorBlue *= baseColorGreen;
  974. unsigned char blue = (unsigned char)newColorBlue;
  975. newColor = (baseColorAlpha<<24) + (red<<16) + (green<<8) + (blue);
  976. }
  977. else if ((!baseColorRed) && (!baseColorGreen))
  978. {
  979. baseColorBlue *= 0.00390625f; //Divide by 256;
  980. baseColorBlue = 1.0 - baseColorBlue;
  981. baseColorBlue *= baseColorBlue; //Log colors
  982. baseColorBlue = 1.0 - baseColorBlue;
  983. float newColorRed = float((psBlue & 0x00ff0000)>>16);
  984. newColorRed *= baseColorBlue;
  985. unsigned char red = (unsigned char)newColorRed;
  986. float newColorGreen = float((psBlue & 0x0000ff00)>>8);
  987. newColorGreen *= baseColorBlue;
  988. unsigned char green = (unsigned char)newColorGreen;
  989. float newColorBlue = float(psBlue & 0x000000ff);
  990. newColorBlue *= baseColorBlue;
  991. unsigned char blue = (unsigned char)newColorBlue;
  992. newColor = (baseColorAlpha<<24) + (red<<16) + (green<<8) + (blue);
  993. }
  994. *textureMemory = newColor;
  995. textureMemory++;
  996. }
  997. }
  998. //------------------------
  999. // Unlock the texture
  1000. gos_UnLockTexture(gosHandle);
  1001. }
  1002. }
  1003. //---------------------------------------------------------------------------
  1004. DWORD bgrTorgb (DWORD frontRGB);
  1005. //-----------------------------------------------------------------------------
  1006. void GVAppearance::setPaintScheme (DWORD mcRed, DWORD mcGreen, DWORD mcBlue)
  1007. {
  1008. #ifdef BGR
  1009. // These come into here bgr instead of RGB. CONVERT!
  1010. psRed = bgrTorgb(mcRed);
  1011. psBlue = bgrTorgb(mcBlue);
  1012. psGreen = bgrTorgb(mcGreen);
  1013. #else /*BGR*/
  1014. psRed = mcRed;
  1015. psBlue = mcBlue;
  1016. psGreen = mcGreen;
  1017. #endif /*BGR*/
  1018. setPaintScheme();
  1019. }
  1020. //-----------------------------------------------------------------------------
  1021. void GVAppearance::getPaintScheme( DWORD& red, DWORD& green, DWORD& blue )
  1022. {
  1023. #ifdef BGR
  1024. red = bgrTorgb(psRed);
  1025. blue = bgrTorgb(psBlue);
  1026. green = bgrTorgb(psGreen);
  1027. #else /*BGR*/
  1028. red = psRed;
  1029. blue = psBlue;
  1030. green = psGreen;
  1031. #endif /*BGR*/
  1032. }
  1033. //-----------------------------------------------------------------------------
  1034. void GVAppearance::resetPaintScheme (DWORD red, DWORD green, DWORD blue)
  1035. {
  1036. //---------------------------------------------------------------------------------
  1037. // Simple really. Toss the current texture, reload the RGB and reapply the colors
  1038. DWORD gosHandle = mcTextureManager->get_gosTextureHandle(localTextureHandle);
  1039. mcTextureManager->removeTexture(gosHandle);
  1040. //-------------------------------------------------
  1041. // Load the texture and store its handle.
  1042. char txmName[1024];
  1043. gvShape->GetTextureName(0,txmName,256);
  1044. char texturePath[1024];
  1045. sprintf(texturePath,"%s%d\\",tglPath,ObjectTextureSize);
  1046. FullPathFileName textureName;
  1047. textureName.init(texturePath,txmName,"");
  1048. //DWORD paintInstance = (red << 16) + (green << 8) + (blue);
  1049. /* The texture manager asks for a unique 32bit identifier for every texture instance.
  1050. However, it requires 72 bits to fully describe a mech texture (the base color (stored in
  1051. the variable "red"), highlight color1 (blue), and highlight color2 (green), each of which
  1052. is a 24bit number made up of 8bit r, g, and b components). Instead of creating a
  1053. mapping between the mech textures used (probably less than 2^32 of them) and
  1054. 32bit identifiers, for the sake of expediency I'm just taking the 3 most significant bits of
  1055. the 9 rgb components to make a 27 bit identifier. This means that two mech textures
  1056. that are close in color (i.e. all of the 3 most significant bits of the 9 rgb components are
  1057. the same) will be treated as the same texture, which is not necessarily a bad thing in
  1058. our case. */
  1059. DWORD ccbase = ((red >> 5) & 7) + (((red >> 13) & 7) << 3) + (((red >> 21) & 7) << 6);
  1060. DWORD cchighlight1 = ((green >> 5) & 7) + (((green >> 13) & 7) << 3) + (((green >> 21) & 7) << 6);
  1061. DWORD cchighlight2 = ((blue >> 5) & 7) + (((blue >> 13) & 7) << 3) + (((blue >> 21) & 7) << 6);
  1062. DWORD paintInstance = (ccbase << 18) + (cchighlight1 << 9) + (cchighlight2);
  1063. if (fileExists(textureName))
  1064. {
  1065. if (strnicmp(txmName,"a_",2) == 0)
  1066. {
  1067. DWORD textureInstanceAlreadyExists = mcTextureManager->textureInstanceExists(textureName,gos_Texture_Solid,gosHint_DisableMipmap | gosHint_DontShrink,paintInstance);
  1068. if (!textureInstanceAlreadyExists)
  1069. localTextureHandle = mcTextureManager->loadTexture(textureName,gos_Texture_Alpha,gosHint_DisableMipmap | gosHint_DontShrink,paintInstance);
  1070. else
  1071. localTextureHandle = textureInstanceAlreadyExists;
  1072. gvShape->SetTextureHandle(0,localTextureHandle);
  1073. gvShape->SetTextureAlpha(0,true);
  1074. if (textureInstanceAlreadyExists)
  1075. {
  1076. /* In this case, the texture returned should already have the paint scheme
  1077. applied. */
  1078. //Still need to store psRed/psGreen/psBlue!!!!
  1079. psRed = red;
  1080. psGreen = green;
  1081. psBlue = blue;
  1082. return;
  1083. }
  1084. }
  1085. else
  1086. {
  1087. DWORD textureInstanceAlreadyExists = mcTextureManager->textureInstanceExists(textureName,gos_Texture_Solid,gosHint_DisableMipmap | gosHint_DontShrink,paintInstance);
  1088. if (!textureInstanceAlreadyExists)
  1089. localTextureHandle = mcTextureManager->loadTexture(textureName,gos_Texture_Solid,gosHint_DisableMipmap | gosHint_DontShrink,paintInstance);
  1090. else
  1091. localTextureHandle = textureInstanceAlreadyExists;
  1092. gvShape->SetTextureHandle(0,localTextureHandle);
  1093. gvShape->SetTextureAlpha(0,false);
  1094. if (textureInstanceAlreadyExists)
  1095. {
  1096. /* In this case, the texture returned should already have the paint scheme
  1097. applied. */
  1098. //Still need to store psRed/psGreen/psBlue!!!!
  1099. psRed = red;
  1100. psGreen = green;
  1101. psBlue = blue;
  1102. return;
  1103. }
  1104. }
  1105. }
  1106. else
  1107. {
  1108. //PAUSE(("Warning: %s texture name not found",textureName));
  1109. gvShape->SetTextureHandle(0,0xffffffff);
  1110. }
  1111. setPaintScheme(red,green,blue);
  1112. }
  1113. //-----------------------------------------------------------------------------
  1114. void GVAppearance::setGesture (unsigned long gestureId)
  1115. {
  1116. //------------------------------------------------------------
  1117. // Check if state is possible.
  1118. if (gestureId >= MAX_GV_ANIMATIONS)
  1119. return;
  1120. //------------------------------------------------------------
  1121. // Check if object destroyed. If so, no animation!
  1122. if ((status == OBJECT_STATUS_DESTROYED) || (status == OBJECT_STATUS_DISABLED))
  1123. return;
  1124. //----------------------------------------------------------------------
  1125. // If state is OK, set animation data, set first frame, set loop and
  1126. // reverse flag, and start it going until you hear otherwise.
  1127. appearType->setAnimation(gvShape,gestureId);
  1128. gvAnimationState = gestureId;
  1129. currentFrame = 0.0f;
  1130. if (appearType->gvStartF[gestureId])
  1131. currentFrame = appearType->gvStartF[gestureId];
  1132. isReversed = false;
  1133. if (appearType->isReversed(gvAnimationState))
  1134. {
  1135. currentFrame = appearType->getNumFrames(gvAnimationState)-1;
  1136. isReversed = true;
  1137. }
  1138. if (appearType->isRandom(gvAnimationState))
  1139. {
  1140. currentFrame = RandomNumber(appearType->getNumFrames(gvAnimationState)-1);
  1141. }
  1142. isLooping = appearType->isLooped(gvAnimationState);
  1143. gvFrameRate = appearType->getFrameRate(gvAnimationState);
  1144. setFirstFrame = true;
  1145. canTransition = false;
  1146. }
  1147. //-----------------------------------------------------------------------------
  1148. Stuff::Vector3D GVAppearance::getHitNode (void)
  1149. {
  1150. if (hitNodeId == -1)
  1151. hitNodeId = gvShape->GetNodeNameId("hitnode");
  1152. Stuff::Vector3D result = getNodeIdPosition(hitNodeId);
  1153. return result;
  1154. }
  1155. //-----------------------------------------------------------------------------
  1156. void GVAppearance::setObjectParameters (Stuff::Vector3D &pos, float Rot, long sel, long team, long homeRelations)
  1157. {
  1158. movedThisFrame = false;
  1159. if ((rotation != Rot) || (pos != position))
  1160. movedThisFrame = true;
  1161. rotation = Rot;
  1162. turretRotation = Rot;
  1163. position = pos;
  1164. selected = sel;
  1165. actualRotation = Rot;
  1166. teamId = team;
  1167. homeTeamRelationship = homeRelations;
  1168. }
  1169. //-----------------------------------------------------------------------------
  1170. void GVAppearance::setMoverParameters (float turretRot, float lArmRot, float rArmRot, bool isAirborne)
  1171. {
  1172. turretRotation = turretRot;
  1173. pitch = lArmRot;
  1174. roll = rArmRot;
  1175. isInfantry = isAirborne;
  1176. }
  1177. //-----------------------------------------------------------------------------
  1178. void GVAppearance::debugUpdate (void)
  1179. {
  1180. if (!inDebugMoveMode)
  1181. return;
  1182. //----------------------------------------
  1183. // Adjust mechDebugAngle based on Input
  1184. if (userInput->getKeyDown(KEY_LEFT) && userInput->ctrl())
  1185. {
  1186. vehicleDebugAngle += 11.25;
  1187. if (vehicleDebugAngle > 180.0)
  1188. vehicleDebugAngle -= 360;
  1189. }
  1190. if (userInput->getKeyDown(KEY_RIGHT) && userInput->ctrl())
  1191. {
  1192. vehicleDebugAngle -= 11.25;
  1193. if (vehicleDebugAngle < -180.0)
  1194. vehicleDebugAngle += 360.0;
  1195. }
  1196. //----------------------------------------
  1197. // Adjust torsoDebugAngle based on Input
  1198. if (userInput->getKeyDown(KEY_UP) && userInput->ctrl())
  1199. {
  1200. turretDebugAngle += 11.25;
  1201. if (turretDebugAngle > 180.0)
  1202. turretDebugAngle -= 360;
  1203. }
  1204. if (userInput->getKeyDown(KEY_DOWN) && userInput->ctrl())
  1205. {
  1206. turretDebugAngle -= 11.25;
  1207. if (turretDebugAngle < -180.0)
  1208. turretDebugAngle += 360.0;
  1209. }
  1210. //------------------------------------------
  1211. // Adjust Speed Based on Input
  1212. if (userInput->getKeyDown(KEY_EQUALS) && userInput->ctrl())
  1213. {
  1214. debugVelMag += 10.0;
  1215. }
  1216. if (userInput->getKeyDown(KEY_MINUS) && userInput->ctrl())
  1217. {
  1218. debugVelMag -= 10.0;
  1219. }
  1220. if (userInput->getKeyDown(KEY_0) && userInput->ctrl())
  1221. {
  1222. debugVelMag = 0.0;
  1223. }
  1224. //------------------------------------------------------------------
  1225. // Adjust position based on vehicle Velocity which is based on gesture
  1226. Stuff::Vector3D velocity;
  1227. velocity.x = 0.7071f;
  1228. velocity.z = 0.0;
  1229. velocity.y = -0.7071f;
  1230. Rotate(velocity,-vehicleDebugAngle);
  1231. float velMag = debugVelMag;
  1232. //-----------------------------------------
  1233. // Take slope being walked on into account.
  1234. // Use for ground vehicles for sure.
  1235. Stuff::Vector3D currentNormal = land->getTerrainNormal(debugGVActorPosition);
  1236. float angle = angle_from(velocity,currentNormal);
  1237. if (angle != 90.0)
  1238. {
  1239. float hillFactor = cos(angle * DEGREES_TO_RADS) * velMag;
  1240. velMag += hillFactor;
  1241. }
  1242. velocity *= velMag * worldUnitsPerMeter;
  1243. velocity *= frameLength;
  1244. debugGVActorPosition += velocity;
  1245. debugGVActorPosition.z = land->getTerrainElevation(debugGVActorPosition);
  1246. setObjectParameters(debugGVActorPosition,vehicleDebugAngle,true,0, 0);
  1247. update();
  1248. recalcBounds();
  1249. }
  1250. //-----------------------------------------------------------------------------
  1251. bool GVAppearance::isMouseOver (float px, float py)
  1252. {
  1253. if (inView)
  1254. {
  1255. if ((px <= lowerRight.x) && (py <= lowerRight.y) &&
  1256. (px >= upperLeft.x) &&
  1257. (py >= upperLeft.y))
  1258. {
  1259. return inView;
  1260. }
  1261. else
  1262. {
  1263. return FALSE;
  1264. }
  1265. }
  1266. return(inView);
  1267. }
  1268. //-----------------------------------------------------------------------------
  1269. bool GVAppearance::recalcBounds (void)
  1270. {
  1271. Stuff::Vector4D tempPos;
  1272. inView = false;
  1273. float eyeDistance = 0.0f;
  1274. if (eye)
  1275. {
  1276. //ALWAYS need to do this or select is YAYA
  1277. eye->projectZ(position,screenPos);
  1278. //--------------------------------------------------
  1279. // First, if we are using perspective, figure out
  1280. // if object too far from camera. Far Clip Plane.
  1281. if (eye->usePerspective)
  1282. {
  1283. Stuff::Point3D Distance;
  1284. Stuff::Point3D objPosition;
  1285. Stuff::Point3D eyePosition(eye->getCameraOrigin());
  1286. objPosition.x = -position.x;
  1287. objPosition.y = position.z;
  1288. objPosition.z = position.y;
  1289. Distance.Subtract(objPosition,eyePosition);
  1290. eyeDistance = Distance.GetApproximateLength();
  1291. if (eyeDistance > Camera::MaxClipDistance)
  1292. {
  1293. hazeFactor = 1.0f;
  1294. inView = false;
  1295. }
  1296. else if (eyeDistance > Camera::MinHazeDistance)
  1297. {
  1298. Camera::HazeFactor = (eyeDistance - Camera::MinHazeDistance) * Camera::DistanceFactor;
  1299. inView = true;
  1300. }
  1301. else
  1302. {
  1303. Camera::HazeFactor = 0.0f;
  1304. inView = true;
  1305. }
  1306. //-----------------------------------------------------------------
  1307. // If inside farClip plane, check if behind camera.
  1308. // Find angle between lookVector of Camera and vector from camPos
  1309. // to Target. If angle is less then halfFOV, object is visible.
  1310. if (inView)
  1311. {
  1312. Stuff::Vector3D Distance;
  1313. Stuff::Point3D objPosition;
  1314. Stuff::Point3D eyePosition(eye->getCameraOrigin());
  1315. objPosition.x = -position.x;
  1316. objPosition.y = position.z;
  1317. objPosition.z = position.y;
  1318. Distance.Subtract(objPosition,eyePosition);
  1319. Distance.Normalize(Distance);
  1320. float cosine = Distance * eye->getLookVector();
  1321. if (cosine > eye->cosHalfFOV)
  1322. inView = true;
  1323. else
  1324. inView = false;
  1325. }
  1326. }
  1327. else
  1328. {
  1329. Camera::HazeFactor = 0.0f;
  1330. inView = true;
  1331. }
  1332. if (inView)
  1333. {
  1334. if (reloadBounds)
  1335. appearType->reinit();
  1336. appearType->boundsLowerRightY = (OBBRadius * eye->getTiltFactor() * 2.0f);
  1337. //-------------------------------------------------------------------------
  1338. // do a rough check if on screen. If no where near, do NOT do the below.
  1339. // Mighty mighty slow!!!!
  1340. // Use the original check done before all this 3D madness. Dig out sourceSafe tomorrow!
  1341. tempPos = screenPos;
  1342. upperLeft.x = tempPos.x;
  1343. upperLeft.y = tempPos.y;
  1344. lowerRight.x = tempPos.x;
  1345. lowerRight.y = tempPos.y;
  1346. upperLeft.x += (appearType->boundsUpperLeftX * eye->getScaleFactor());
  1347. upperLeft.y += (appearType->boundsUpperLeftY * eye->getScaleFactor());
  1348. lowerRight.x += (appearType->boundsLowerRightX * eye->getScaleFactor());
  1349. lowerRight.y += (appearType->boundsLowerRightY * eye->getScaleFactor());
  1350. if ((lowerRight.x >= 0) && (lowerRight.y >= 0) &&
  1351. (upperLeft.x <= eye->getScreenResX()) &&
  1352. (upperLeft.y <= eye->getScreenResY()))
  1353. {
  1354. //We are on screen. Figure out selection box.
  1355. Stuff::Vector3D boxCoords[8];
  1356. Stuff::Vector4D bcsp[8];
  1357. Stuff::Vector3D minBox;
  1358. minBox.x = -appearType->typeUpperLeft.x;
  1359. minBox.y = appearType->typeUpperLeft.z;
  1360. minBox.z = appearType->typeUpperLeft.y;
  1361. Stuff::Vector3D maxBox;
  1362. maxBox.x = -appearType->typeLowerRight.x;
  1363. maxBox.y = appearType->typeLowerRight.z;
  1364. maxBox.z = appearType->typeLowerRight.y;
  1365. if (rotation != 0.0f)
  1366. Rotate(minBox,-rotation);
  1367. if (rotation != 0.0f)
  1368. Rotate(maxBox,-rotation);
  1369. boxCoords[0].x = position.x + minBox.x;
  1370. boxCoords[0].y = position.y + minBox.y;
  1371. boxCoords[0].z = position.z + minBox.z;
  1372. boxCoords[1].x = position.x + minBox.x;
  1373. boxCoords[1].y = position.y + maxBox.y;
  1374. boxCoords[1].z = position.z + minBox.z;
  1375. boxCoords[2].x = position.x + maxBox.x;
  1376. boxCoords[2].y = position.y + minBox.y;
  1377. boxCoords[2].z = position.z + minBox.z;
  1378. boxCoords[3].x = position.x + maxBox.x;
  1379. boxCoords[3].y = position.y + maxBox.y;
  1380. boxCoords[3].z = position.z + minBox.z;
  1381. boxCoords[4].x = position.x + maxBox.x;
  1382. boxCoords[4].y = position.y + maxBox.y;
  1383. boxCoords[4].z = position.z + maxBox.z;
  1384. boxCoords[5].x = position.x + maxBox.x;
  1385. boxCoords[5].y = position.y + minBox.y;
  1386. boxCoords[5].z = position.z + maxBox.z;
  1387. boxCoords[6].x = position.x + minBox.x;
  1388. boxCoords[6].y = position.y + maxBox.y;
  1389. boxCoords[6].z = position.z + maxBox.z;
  1390. boxCoords[7].x = position.x + minBox.x;
  1391. boxCoords[7].y = position.y + minBox.y;
  1392. boxCoords[7].z = position.z + maxBox.z;
  1393. float maxX = 0.0f, maxY = 0.0f;
  1394. float minX = 0.0f, minY = 0.0f;
  1395. for (long i=0;i<8;i++)
  1396. {
  1397. eye->projectZ(boxCoords[i],bcsp[i]);
  1398. if (!i)
  1399. {
  1400. maxX = minX = bcsp[i].x;
  1401. maxY = minY = bcsp[i].y;
  1402. }
  1403. if (i)
  1404. {
  1405. if (bcsp[i].x > maxX)
  1406. maxX = bcsp[i].x;
  1407. if (bcsp[i].x < minX)
  1408. minX = bcsp[i].x;
  1409. if (bcsp[i].y > maxY)
  1410. maxY = bcsp[i].y;
  1411. if (bcsp[i].y < minY)
  1412. minY = bcsp[i].y;
  1413. }
  1414. }
  1415. upperLeft.x = minX;
  1416. upperLeft.y = minY;
  1417. lowerRight.x = maxX;
  1418. lowerRight.y = maxY;
  1419. if ((lowerRight.x >= 0) && (lowerRight.y >= 0) &&
  1420. (upperLeft.x <= eye->getScreenResX()) &&
  1421. (upperLeft.y <= eye->getScreenResY()))
  1422. {
  1423. inView = true;
  1424. if ((status != OBJECT_STATUS_DESTROYED) && (status != OBJECT_STATUS_DISABLED))
  1425. {
  1426. //-------------------------------------------------------------------------------
  1427. //Set LOD of Model here because we have the distance and we KNOW we can see it!
  1428. bool baseLOD = true;
  1429. DWORD selectLOD = 0;
  1430. if (useHighObjectDetail)
  1431. {
  1432. for (long i=1;i<MAX_LODS;i++)
  1433. {
  1434. if (appearType->gvShape[i] && (eyeDistance > appearType->lodDistance[i]))
  1435. {
  1436. baseLOD = false;
  1437. selectLOD = i;
  1438. }
  1439. }
  1440. }
  1441. else //We always want to use the lowest LOD!!
  1442. {
  1443. if (appearType->gvShape[1])
  1444. {
  1445. baseLOD = false;
  1446. selectLOD = 1;
  1447. }
  1448. }
  1449. // we are at this LOD level.
  1450. if (selectLOD != currentLOD)
  1451. {
  1452. currentLOD = selectLOD;
  1453. BYTE alphaValue = gvShape->GetAlphaValue();
  1454. gvShape->ClearAnimation();
  1455. delete gvShape;
  1456. gvShape = NULL;
  1457. gvShape = appearType->gvShape[currentLOD]->CreateFrom();
  1458. if (gvAnimationState != -1)
  1459. appearType->setAnimation(gvShape,gvAnimationState);
  1460. gvShape->SetAlphaValue(alphaValue);
  1461. //-------------------------------------------------
  1462. // Load the texture and store its handle.
  1463. for (long j=0;j<gvShape->GetNumTextures();j++)
  1464. {
  1465. char txmName[1024];
  1466. gvShape->GetTextureName(j,txmName,256);
  1467. char texturePath[1024];
  1468. sprintf(texturePath,"%s%d\\",tglPath,ObjectTextureSize);
  1469. FullPathFileName textureName;
  1470. textureName.init(texturePath,txmName,"");
  1471. if (fileExists(textureName))
  1472. {
  1473. if (strnicmp(txmName,"a_",2) == 0)
  1474. {
  1475. DWORD gosTextureHandle = mcTextureManager->loadTexture(textureName,gos_Texture_Alpha,gosHint_DisableMipmap | gosHint_DontShrink);
  1476. gosASSERT(gosTextureHandle != 0xffffffff);
  1477. gvShape->SetTextureHandle(j,gosTextureHandle);
  1478. gvShape->SetTextureAlpha(j,true);
  1479. }
  1480. else
  1481. {
  1482. DWORD gosTextureHandle = mcTextureManager->loadTexture(textureName,gos_Texture_Solid,gosHint_DisableMipmap | gosHint_DontShrink);
  1483. gosASSERT(gosTextureHandle != 0xffffffff);
  1484. gvShape->SetTextureHandle(j,gosTextureHandle);
  1485. gvShape->SetTextureAlpha(j,false);
  1486. }
  1487. }
  1488. else
  1489. {
  1490. //PAUSE(("Warning: %s texture name not found",textureName));
  1491. gvShape->SetTextureHandle(j,0xffffffff);
  1492. }
  1493. }
  1494. resetPaintScheme(psRed,psGreen,psBlue);
  1495. }
  1496. //ONLY change if we need
  1497. if (currentLOD && baseLOD)
  1498. {
  1499. // we are at the Base LOD level.
  1500. currentLOD = 0;
  1501. BYTE alphaValue = gvShape->GetAlphaValue();
  1502. gvShape->ClearAnimation();
  1503. delete gvShape;
  1504. gvShape = NULL;
  1505. gvShape = appearType->gvShape[currentLOD]->CreateFrom();
  1506. gvShape->SetAlphaValue(alphaValue);
  1507. //-------------------------------------------------
  1508. // Load the texture and store its handle.
  1509. for (long i=0;i<gvShape->GetNumTextures();i++)
  1510. {
  1511. char txmName[1024];
  1512. gvShape->GetTextureName(i,txmName,256);
  1513. char texturePath[1024];
  1514. sprintf(texturePath,"%s%d\\",tglPath,ObjectTextureSize);
  1515. FullPathFileName textureName;
  1516. textureName.init(texturePath,txmName,"");
  1517. if (fileExists(textureName))
  1518. {
  1519. if (strnicmp(txmName,"a_",2) == 0)
  1520. {
  1521. localTextureHandle = mcTextureManager->loadTexture(textureName,gos_Texture_Alpha,gosHint_DisableMipmap | gosHint_DontShrink,true);
  1522. gosASSERT(localTextureHandle != 0xffffffff);
  1523. gvShape->SetTextureHandle(i,localTextureHandle);
  1524. gvShape->SetTextureAlpha(i,true);
  1525. }
  1526. else
  1527. {
  1528. localTextureHandle = mcTextureManager->loadTexture(textureName,gos_Texture_Solid,gosHint_DisableMipmap | gosHint_DontShrink,true);
  1529. gosASSERT(localTextureHandle != 0xffffffff);
  1530. gvShape->SetTextureHandle(i,localTextureHandle);
  1531. gvShape->SetTextureAlpha(i,false);
  1532. }
  1533. }
  1534. else
  1535. {
  1536. //PAUSE(("Warning: %s texture name not found",textureName));
  1537. gvShape->SetTextureHandle(i,0xffffffff);
  1538. }
  1539. }
  1540. resetPaintScheme(psRed,psGreen,psBlue);
  1541. }
  1542. }
  1543. }
  1544. else
  1545. {
  1546. inView = false; //Did alot of extra work checking this, but WHY draw and insult to injury?
  1547. }
  1548. }
  1549. else
  1550. {
  1551. inView = false;
  1552. }
  1553. }
  1554. }
  1555. return(inView);
  1556. }
  1557. //-----------------------------------------------------------------------------
  1558. bool GVAppearance::playDestruction (void)
  1559. {
  1560. //Check if there is a Destruct FX
  1561. if (appearType->destructEffect[0])
  1562. {
  1563. //--------------------------------------------
  1564. // Yes, load it on up.
  1565. unsigned flags = gosFX::Effect::ExecuteFlag;
  1566. Check_Object(gosFX::EffectLibrary::Instance);
  1567. gosFX::Effect::Specification* gosEffectSpec = gosFX::EffectLibrary::Instance->Find(appearType->destructEffect);
  1568. if (gosEffectSpec)
  1569. {
  1570. destructFX = gosFX::EffectLibrary::Instance->MakeEffect(gosEffectSpec->m_effectID, flags);
  1571. gosASSERT(destructFX != NULL);
  1572. MidLevelRenderer::MLRTexturePool::Instance->LoadImages();
  1573. Stuff::Point3D tPosition;
  1574. Stuff::LinearMatrix4D shapeOrigin;
  1575. Stuff::LinearMatrix4D localToWorld;
  1576. tPosition.x = -position.x;
  1577. tPosition.y = position.z;
  1578. tPosition.z = position.y;
  1579. shapeOrigin.BuildRotation(Stuff::EulerAngles(0.0f,0.0f,0.0f));
  1580. shapeOrigin.BuildTranslation(tPosition);
  1581. gosFX::Effect::ExecuteInfo info((Stuff::Time)scenarioTime,&shapeOrigin,NULL);
  1582. destructFX->Start(&info);
  1583. return true;
  1584. }
  1585. return false;
  1586. }
  1587. return false; //We didn't have a destruct effect. Tell the object to play its default.
  1588. }
  1589. //-----------------------------------------------------------------------------
  1590. Stuff::Vector3D GVAppearance::getNodeNamePosition (char *nodeName)
  1591. {
  1592. Stuff::Vector3D result = position;
  1593. if (!inView)
  1594. return result;
  1595. //-------------------------------------------
  1596. // Create Matrix to conform to.
  1597. Stuff::UnitQuaternion qRotation;
  1598. float yaw = rotation * DEGREES_TO_RADS;
  1599. qRotation = Stuff::EulerAngles(0.0f, yaw, 0.0f);
  1600. Stuff::Point3D xlatPosition;
  1601. xlatPosition.x = -position.x;
  1602. xlatPosition.y = position.z;
  1603. xlatPosition.z = position.y;
  1604. Stuff::UnitQuaternion torsoRot;
  1605. torsoRot = Stuff::EulerAngles(0.0f,(turretRotation * DEGREES_TO_RADS),0.0f);
  1606. if (rotationalNodeIndex == -1)
  1607. rotationalNodeIndex = gvShape->SetNodeRotation(appearType->rotationalNodeId,&torsoRot);
  1608. gvShape->SetNodeRotation(rotationalNodeIndex,&torsoRot);
  1609. result = gvShape->GetTransformedNodePosition(&xlatPosition,&qRotation,nodeName);
  1610. if ((result.x == 0.0f) &&
  1611. (result.y == 0.0f) &&
  1612. (result.z == 0.0f))
  1613. result = position;
  1614. return result;
  1615. }
  1616. //-----------------------------------------------------------------------------
  1617. Stuff::Vector3D GVAppearance::getNodeIdPosition (long nodeId)
  1618. {
  1619. Stuff::Vector3D result = position;
  1620. if (!inView)
  1621. return result;
  1622. //-------------------------------------------
  1623. // Create Matrix to conform to.
  1624. Stuff::UnitQuaternion qRotation;
  1625. float yaw = rotation * DEGREES_TO_RADS;
  1626. qRotation = Stuff::EulerAngles(0.0f, yaw, 0.0f);
  1627. Stuff::Point3D xlatPosition;
  1628. xlatPosition.x = -position.x;
  1629. xlatPosition.y = position.z;
  1630. xlatPosition.z = position.y;
  1631. Stuff::UnitQuaternion torsoRot;
  1632. torsoRot = Stuff::EulerAngles(0.0f,(turretRotation * DEGREES_TO_RADS),0.0f);
  1633. if (rotationalNodeIndex == -1)
  1634. rotationalNodeIndex = gvShape->SetNodeRotation(appearType->rotationalNodeId,&torsoRot);
  1635. gvShape->SetNodeRotation(rotationalNodeIndex,&torsoRot);
  1636. result = gvShape->GetTransformedNodePosition(&xlatPosition,&qRotation,nodeId);
  1637. if ((result.x == 0.0f) &&
  1638. (result.y == 0.0f) &&
  1639. (result.z == 0.0f))
  1640. result = position;
  1641. return result;
  1642. }
  1643. //-----------------------------------------------------------------------------
  1644. long GVAppearance::renderShadows (void)
  1645. {
  1646. gvShape->SetTextureHandle(0,localTextureHandle);
  1647. if (inView && visible)
  1648. {
  1649. //---------------------------------------------
  1650. // Call Multi-shape render stuff here.
  1651. if (gvShadowShape)
  1652. gvShadowShape->RenderShadows(true);
  1653. else
  1654. gvShape->RenderShadows(true);
  1655. }
  1656. return NO_ERR;
  1657. }
  1658. //-----------------------------------------------------------------------------
  1659. long GVAppearance::render (long depthFixup)
  1660. {
  1661. gvShape->SetTextureHandle(0,localTextureHandle);
  1662. if (inView)
  1663. {
  1664. long color = SD_BLUE;
  1665. unsigned long highLight = 0x007f7f7f;
  1666. if ((teamId > -1) && (teamId < 8)) {
  1667. static unsigned long highLightTable[3] = {0x00007f00, 0x0000007f, 0x007f0000};
  1668. static long colorTable[3] = {SB_GREEN | 0xff000000, SB_BLUE| 0xff000000, SB_RED | 0xff000000};
  1669. color = colorTable[homeTeamRelationship];
  1670. highLight = highLightTable[homeTeamRelationship];
  1671. }
  1672. if (visible)
  1673. {
  1674. if (selected & DRAW_COLORED && duration <= 0 )
  1675. {
  1676. gvShape->SetARGBHighLight(highLight);
  1677. }
  1678. else
  1679. {
  1680. gvShape->SetARGBHighLight(highlightColor);
  1681. }
  1682. Camera::HazeFactor = hazeFactor;
  1683. if (drawFlash)
  1684. {
  1685. gvShape->SetARGBHighLight(flashColor);
  1686. }
  1687. //---------------------------------------------
  1688. // Call Multi-shape render stuff here.
  1689. // Force textures to reload due to unique instance.
  1690. gvShape->Render(true);
  1691. if (selected & DRAW_TEXT)
  1692. {
  1693. gvShape->SetARGBHighLight(highLight);
  1694. }
  1695. else
  1696. {
  1697. gvShape->SetARGBHighLight(0x0);
  1698. }
  1699. if (selected & DRAW_BARS)
  1700. {
  1701. drawBars();
  1702. }
  1703. if ( selected & DRAW_BRACKETS )
  1704. {
  1705. drawSelectBrackets(color);
  1706. }
  1707. if ( selected & DRAW_TEXT && !sensorLevel )
  1708. {
  1709. if (objectNameId != -1)
  1710. {
  1711. char tmpString[255];
  1712. cLoadString(objectNameId, tmpString, 254);
  1713. drawTextHelp(tmpString, color);
  1714. }
  1715. if ( strlen( pilotName ) )
  1716. {
  1717. drawPilotName( pilotName, color );
  1718. }
  1719. }
  1720. //selected = FALSE;
  1721. //------------------------------------------
  1722. // Render GOS FX if necessary
  1723. if (destructFX && destructFX->IsExecuted())
  1724. {
  1725. gosFX::Effect::DrawInfo drawInfo;
  1726. drawInfo.m_clipper = theClipper;
  1727. MidLevelRenderer::MLRState mlrState;
  1728. mlrState.SetDitherOn();
  1729. mlrState.SetTextureCorrectionOn();
  1730. mlrState.SetZBufferCompareOn();
  1731. mlrState.SetZBufferWriteOn();
  1732. drawInfo.m_state = mlrState;
  1733. drawInfo.m_clippingFlags = 0x0;
  1734. Stuff::LinearMatrix4D shapeOrigin;
  1735. Stuff::LinearMatrix4D localToWorld;
  1736. Stuff::Point3D tPosition;
  1737. tPosition.x = -position.x;
  1738. tPosition.y = position.z;
  1739. tPosition.z = position.y;
  1740. shapeOrigin.BuildRotation(Stuff::EulerAngles(0.0f,0.0f,0.0f));
  1741. shapeOrigin.BuildTranslation(tPosition);
  1742. drawInfo.m_parentToWorld = &shapeOrigin;
  1743. if (!MLRVertexLimitReached)
  1744. destructFX->Draw(&drawInfo);
  1745. }
  1746. if (!sensorLevel)
  1747. {
  1748. if (waterWake && isWaking)
  1749. {
  1750. gosFX::Effect::DrawInfo drawInfo;
  1751. drawInfo.m_clipper = theClipper;
  1752. MidLevelRenderer::MLRState mlrState;
  1753. mlrState.SetDitherOn();
  1754. mlrState.SetTextureCorrectionOn();
  1755. mlrState.SetZBufferCompareOn();
  1756. mlrState.SetZBufferWriteOn();
  1757. drawInfo.m_state = mlrState;
  1758. drawInfo.m_clippingFlags = 0x0;
  1759. Stuff::LinearMatrix4D shapeOrigin;
  1760. Stuff::LinearMatrix4D localToWorld;
  1761. Stuff::LinearMatrix4D localResult;
  1762. Stuff::Point3D wakePos;
  1763. wakePos.x = -position.x;
  1764. wakePos.y = Terrain::waterElevation;
  1765. wakePos.z = position.y;
  1766. shapeOrigin.BuildRotation(Stuff::EulerAngles(0.0f,0.0f,0.0f));
  1767. shapeOrigin.BuildTranslation(wakePos);
  1768. Stuff::UnitQuaternion effectRot;
  1769. effectRot = Stuff::EulerAngles(90.0f * DEGREES_TO_RADS,rotation * DEGREES_TO_RADS,0.0f);
  1770. localToWorld.Multiply(gosFX::Effect_Against_Motion,effectRot);
  1771. localResult.Multiply(localToWorld,shapeOrigin);
  1772. drawInfo.m_parentToWorld = &localResult;
  1773. if (!MLRVertexLimitReached)
  1774. waterWake->Draw(&drawInfo);
  1775. }
  1776. else if (dustCloud)
  1777. {
  1778. gosFX::Effect::DrawInfo drawInfo;
  1779. drawInfo.m_clipper = theClipper;
  1780. MidLevelRenderer::MLRState mlrState;
  1781. mlrState.SetDitherOn();
  1782. mlrState.SetTextureCorrectionOn();
  1783. mlrState.SetZBufferCompareOn();
  1784. mlrState.SetZBufferWriteOn();
  1785. drawInfo.m_state = mlrState;
  1786. drawInfo.m_clippingFlags = 0x0;
  1787. Stuff::LinearMatrix4D shapeOrigin;
  1788. Stuff::LinearMatrix4D localToWorld;
  1789. Stuff::LinearMatrix4D localResult;
  1790. if (dustNodeIndex == -1)
  1791. dustNodeIndex = gvShape->GetNodeNameId("dust_body");
  1792. Stuff::Vector3D dustPos = getNodeIdPosition(dustNodeIndex);
  1793. Stuff::Point3D wakePos;
  1794. wakePos.x = -dustPos.x;
  1795. wakePos.y = dustPos.z;
  1796. wakePos.z = dustPos.y;
  1797. shapeOrigin.BuildRotation(Stuff::EulerAngles(0.0f,0.0f,0.0f));
  1798. shapeOrigin.BuildTranslation(wakePos);
  1799. Stuff::UnitQuaternion effectRot;
  1800. effectRot = Stuff::EulerAngles(0.0f,rotation * DEGREES_TO_RADS,0.0f);
  1801. localToWorld.Multiply(gosFX::Effect_Against_Motion,effectRot);
  1802. localResult.Multiply(localToWorld,shapeOrigin);
  1803. drawInfo.m_parentToWorld = &localResult;
  1804. if (!MLRVertexLimitReached)
  1805. dustCloud->Draw(&drawInfo);
  1806. }
  1807. if (activity && isActivitying)
  1808. {
  1809. gosFX::Effect::DrawInfo drawInfo;
  1810. drawInfo.m_clipper = theClipper;
  1811. MidLevelRenderer::MLRState mlrState;
  1812. mlrState.SetDitherOn();
  1813. mlrState.SetTextureCorrectionOn();
  1814. mlrState.SetZBufferCompareOn();
  1815. mlrState.SetZBufferWriteOn();
  1816. drawInfo.m_state = mlrState;
  1817. drawInfo.m_clippingFlags = 0x0;
  1818. Stuff::LinearMatrix4D shapeOrigin;
  1819. Stuff::LinearMatrix4D localToWorld;
  1820. Stuff::LinearMatrix4D localResult;
  1821. if (activityNodeIndex == -1)
  1822. activityNodeIndex = gvShape->GetNodeNameId("activity_node");
  1823. Stuff::Vector3D dustPos = getNodeIdPosition(activityNodeIndex);
  1824. Stuff::Point3D wakePos;
  1825. wakePos.x = -dustPos.x;
  1826. wakePos.y = dustPos.z;
  1827. wakePos.z = dustPos.y;
  1828. shapeOrigin.BuildRotation(Stuff::EulerAngles(0.0f,0.0f,0.0f));
  1829. shapeOrigin.BuildTranslation(wakePos);
  1830. /*
  1831. Stuff::UnitQuaternion effectRot;
  1832. effectRot = Stuff::EulerAngles(0.0f,rotation * DEGREES_TO_RADS,0.0f);
  1833. localToWorld.Multiply(gosFX::Effect_Against_Motion,effectRot);
  1834. localResult.Multiply(localToWorld,shapeOrigin);
  1835. */
  1836. drawInfo.m_parentToWorld = &shapeOrigin;
  1837. if (!MLRVertexLimitReached)
  1838. activity->Draw(&drawInfo);
  1839. }
  1840. }
  1841. }
  1842. if ((sensorLevel > 0) && (sensorLevel < 5))
  1843. {
  1844. //---------------------------------------
  1845. // Draw Sensor Contact here.
  1846. if (sensorLevel > 1)
  1847. {
  1848. sensorCircleShape->Render();
  1849. }
  1850. else
  1851. {
  1852. sensorTriangleShape->Render();
  1853. }
  1854. }
  1855. }
  1856. return NO_ERR;
  1857. }
  1858. //-----------------------------------------------------------------------------
  1859. void GVAppearance::updateGeometry (void)
  1860. {
  1861. //if (visible)
  1862. //{
  1863. if (rotation > 180)
  1864. rotation -= 360;
  1865. if (rotation < -180)
  1866. rotation += 360;
  1867. if (turretRotation > 180)
  1868. turretRotation -= 360;
  1869. if (turretRotation < -180)
  1870. turretRotation += 360;
  1871. float pitchAngle = pitch;
  1872. float rollAngle = roll;
  1873. if ((status == OBJECT_STATUS_NORMAL || status == OBJECT_STATUS_SHUTDOWN) && land) //Are we still oK?
  1874. {
  1875. long cellR, cellC;
  1876. land->worldToCell(position,cellR, cellC);
  1877. if (GameMap && !GameMap->getDeepWater(cellR, cellC) && !GameMap->getShallowWater(cellR, cellC))
  1878. {
  1879. Stuff::Vector3D worldK;
  1880. land->getTerrainAngle(position,&worldK);
  1881. //--------------------------------------------------
  1882. // Rotate Angle obtained into Vehicle Rotation.
  1883. Rotate(worldK,rotation);
  1884. //------------------------------------------------
  1885. // Find Pitch first.
  1886. Stuff::Vector3D pitchK;
  1887. pitchK = worldK;
  1888. pitchK.x = 0.0f;
  1889. pitchK.Normalize(pitchK);
  1890. Stuff::Vector3D rollK;
  1891. rollK = worldK;
  1892. rollK.y = 0.0f;
  1893. rollK.Normalize(rollK);
  1894. Stuff::Vector3D up;
  1895. up.x = up.y = 0.0f;
  1896. up.z = 1.0f;
  1897. pitchAngle = up * pitchK;
  1898. pitchAngle = acos(pitchAngle) * RADS_TO_DEGREES;
  1899. if (pitchK.y < 0.0f)
  1900. pitchAngle = -pitchAngle;
  1901. rollAngle = up * rollK;
  1902. rollAngle = acos(rollAngle) * RADS_TO_DEGREES;
  1903. if (rollK.x < 0.0f)
  1904. rollAngle = -rollAngle;
  1905. }
  1906. }
  1907. //-------------------------------------------
  1908. // Does math necessary to draw Vehicle
  1909. Stuff::UnitQuaternion rot, pitchRoll;
  1910. float yaw = rotation * DEGREES_TO_RADS;
  1911. pitchAngle *= DEGREES_TO_RADS;
  1912. rollAngle *= DEGREES_TO_RADS;
  1913. Stuff::UnitQuaternion totalRotation;
  1914. rot = Stuff::EulerAngles(0.0f, yaw, 0.0f);
  1915. pitchRoll = Stuff::EulerAngles(pitchAngle, 0.0f, rollAngle);
  1916. totalRotation.Multiply(pitchRoll,rot);
  1917. unsigned char lightr,lightg,lightb;
  1918. float lightIntensity = 1.0f;
  1919. if (land)
  1920. lightIntensity = land->getTerrainLight(position);
  1921. lightr = eye->getLightRed(lightIntensity);
  1922. lightg = eye->getLightGreen(lightIntensity);
  1923. lightb = eye->getLightBlue(lightIntensity);
  1924. DWORD lightRGB = (lightr<<16) + (lightg<<8) + lightb;
  1925. eye->setLightColor(0,lightRGB);
  1926. eye->setLightIntensity(0,1.0);
  1927. DWORD fogRGB = 0xff<<24;
  1928. float fogStart = eye->fogStart;
  1929. float fogFull = eye->fogFull;
  1930. Stuff::Point3D xlatPosition;
  1931. xlatPosition.x = -position.x;
  1932. xlatPosition.y = position.z;
  1933. xlatPosition.z = position.y;
  1934. if (xlatPosition.y < fogStart)
  1935. {
  1936. float fogFactor = fogStart - xlatPosition.y;
  1937. if (fogFactor < 0.0)
  1938. fogRGB = 0xff<<24;
  1939. else
  1940. {
  1941. fogFactor /= (fogStart - fogFull);
  1942. if (fogFactor <= 1.0)
  1943. {
  1944. fogFactor *= fogFactor;
  1945. fogFactor = 1.0 - fogFactor;
  1946. fogFactor *= 256.0;
  1947. }
  1948. else
  1949. {
  1950. fogFactor = 256.0;
  1951. }
  1952. unsigned char fogResult = fogFactor;
  1953. fogRGB = fogResult << 24;
  1954. }
  1955. }
  1956. else
  1957. {
  1958. fogRGB = 0xff<<24;
  1959. }
  1960. if (useFog)
  1961. gvShape->SetFogRGB(fogRGB);
  1962. else
  1963. gvShape->SetFogRGB(0xffffffff);
  1964. Stuff::UnitQuaternion turretRot;
  1965. turretRot = Stuff::EulerAngles(0.0f,(turretRotation * DEGREES_TO_RADS),0.0f);
  1966. if (rotationalNodeIndex == -1)
  1967. rotationalNodeIndex = gvShape->SetNodeRotation(appearType->rotationalNodeId,&turretRot);
  1968. gvShape->SetNodeRotation(rotationalNodeIndex,&turretRot);
  1969. if (gvShadowShape)
  1970. gvShape->SetUseShadow(false);
  1971. if (gvShadowShape && useShadows)
  1972. {
  1973. gvShadowShape->SetLightList(eye->getWorldLights(),eye->getNumLights());
  1974. gvShadowShape->TransformMultiShape (&xlatPosition,&rot);
  1975. }
  1976. // Camera::HazeFactor = hazeFactor;
  1977. gvShape->SetLightList(eye->getWorldLights(),eye->getNumLights());
  1978. gvShape->TransformMultiShape (&xlatPosition,&totalRotation);
  1979. //}
  1980. //------------------------------------------------
  1981. // Update GOSFX
  1982. if (destructFX && destructFX->IsExecuted())
  1983. {
  1984. Stuff::LinearMatrix4D shapeOrigin;
  1985. Stuff::LinearMatrix4D localToWorld;
  1986. Stuff::Point3D tPosition;
  1987. shapeOrigin.BuildRotation(Stuff::EulerAngles(0.0f,0.0f,0.0f));
  1988. shapeOrigin.BuildTranslation(tPosition);
  1989. tPosition.x = -position.x;
  1990. tPosition.y = position.z;
  1991. tPosition.z = position.y;
  1992. Stuff::OBB boundingBox;
  1993. gosFX::Effect::ExecuteInfo info((Stuff::Time)scenarioTime,&shapeOrigin,&boundingBox);
  1994. bool result = destructFX->Execute(&info);
  1995. if (!result)
  1996. {
  1997. destructFX->Kill();
  1998. delete destructFX;
  1999. destructFX = NULL;
  2000. }
  2001. }
  2002. if (waterWake && isWaking)
  2003. {
  2004. Stuff::LinearMatrix4D shapeOrigin;
  2005. Stuff::LinearMatrix4D localToWorld;
  2006. Stuff::LinearMatrix4D localResult;
  2007. Stuff::Point3D wakePos;
  2008. wakePos.x = -position.x;
  2009. wakePos.y = Terrain::waterElevation;
  2010. wakePos.z = position.y;
  2011. shapeOrigin.BuildRotation(Stuff::EulerAngles(0.0f,0.0f,0.0f));
  2012. shapeOrigin.BuildTranslation(wakePos);
  2013. Stuff::UnitQuaternion effectRot;
  2014. effectRot = Stuff::EulerAngles(90.0f * DEGREES_TO_RADS,rotation * DEGREES_TO_RADS,0.0f);
  2015. localToWorld.Multiply(gosFX::Effect_Against_Motion,effectRot);
  2016. localResult.Multiply(localToWorld,shapeOrigin);
  2017. Stuff::OBB boundingBox;
  2018. gosFX::Effect::ExecuteInfo info((Stuff::Time)scenarioTime,&localResult,&boundingBox);
  2019. waterWake->Execute(&info);
  2020. }
  2021. else if (dustCloud)
  2022. {
  2023. if (movedThisFrame && !isInfantry)
  2024. {
  2025. dustCloud->SetLoopOn();
  2026. dustCloud->SetExecuteOn();
  2027. }
  2028. else
  2029. {
  2030. dustCloud->SetLoopOff();
  2031. dustCloud->SetExecuteOn();
  2032. }
  2033. if (!dustCloudStart)
  2034. {
  2035. Stuff::LinearMatrix4D shapeOrigin;
  2036. Stuff::LinearMatrix4D localToWorld;
  2037. Stuff::LinearMatrix4D localResult;
  2038. if (dustNodeIndex == -1)
  2039. dustNodeIndex = gvShape->GetNodeNameId("dust_body");
  2040. Stuff::Vector3D dustPos = getNodeIdPosition(dustNodeIndex);
  2041. Stuff::Point3D wakePos;
  2042. wakePos.x = -dustPos.x;
  2043. wakePos.y = dustPos.z;
  2044. wakePos.z = dustPos.y;
  2045. shapeOrigin.BuildRotation(Stuff::EulerAngles(0.0f,0.0f,0.0f));
  2046. shapeOrigin.BuildTranslation(wakePos);
  2047. Stuff::UnitQuaternion effectRot;
  2048. effectRot = Stuff::EulerAngles(0.0f,rotation * DEGREES_TO_RADS,0.0f);
  2049. localToWorld.Multiply(gosFX::Effect_Against_Motion,effectRot);
  2050. localResult.Multiply(localToWorld,shapeOrigin);
  2051. gosFX::Effect::ExecuteInfo info((Stuff::Time)scenarioTime,&localResult,NULL);
  2052. dustCloud->Start(&info);
  2053. dustCloudStart = true;
  2054. }
  2055. Stuff::LinearMatrix4D shapeOrigin;
  2056. Stuff::LinearMatrix4D localToWorld;
  2057. Stuff::LinearMatrix4D localResult;
  2058. if (dustNodeIndex == -1)
  2059. dustNodeIndex = gvShape->GetNodeNameId("dust_body");
  2060. Stuff::Vector3D dustPos = getNodeIdPosition(dustNodeIndex);
  2061. Stuff::Point3D wakePos;
  2062. wakePos.x = -dustPos.x;
  2063. wakePos.y = dustPos.z;
  2064. wakePos.z = dustPos.y;
  2065. shapeOrigin.BuildRotation(Stuff::EulerAngles(0.0f,0.0f,0.0f));
  2066. shapeOrigin.BuildTranslation(wakePos);
  2067. Stuff::UnitQuaternion effectRot;
  2068. effectRot = Stuff::EulerAngles(0.0f,rotation * DEGREES_TO_RADS,0.0f);
  2069. localToWorld.Multiply(gosFX::Effect_Against_Motion,effectRot);
  2070. localResult.Multiply(localToWorld,shapeOrigin);
  2071. Stuff::OBB boundingBox;
  2072. gosFX::Effect::ExecuteInfo info((Stuff::Time)scenarioTime,&localResult,&boundingBox);
  2073. dustCloud->Execute(&info);
  2074. }
  2075. if (activity && isActivitying)
  2076. {
  2077. Stuff::LinearMatrix4D shapeOrigin;
  2078. Stuff::LinearMatrix4D localToWorld;
  2079. Stuff::LinearMatrix4D localResult;
  2080. if (activityNodeIndex == -1)
  2081. activityNodeIndex = gvShape->GetNodeNameId("activity_node");
  2082. Stuff::Vector3D dustPos = getNodeIdPosition(activityNodeIndex);
  2083. Stuff::Point3D wakePos;
  2084. wakePos.x = -dustPos.x;
  2085. wakePos.y = dustPos.z;
  2086. wakePos.z = dustPos.y;
  2087. shapeOrigin.BuildRotation(Stuff::EulerAngles(0.0f,0.0f,0.0f));
  2088. shapeOrigin.BuildTranslation(wakePos);
  2089. /*
  2090. Stuff::UnitQuaternion effectRot;
  2091. effectRot = Stuff::EulerAngles(0.0f,rotation * DEGREES_TO_RADS,0.0f);
  2092. localToWorld.Multiply(gosFX::Effect_Against_Motion,effectRot);
  2093. localResult.Multiply(localToWorld,shapeOrigin);
  2094. */
  2095. Stuff::OBB boundingBox;
  2096. gosFX::Effect::ExecuteInfo info((Stuff::Time)scenarioTime,&shapeOrigin,&boundingBox);
  2097. activity->Execute(&info);
  2098. }
  2099. sensorSpin += SPIN_RATE * frameLength;
  2100. if (sensorSpin > 180)
  2101. sensorSpin -= 360;
  2102. if (sensorSpin < -180)
  2103. sensorSpin += 360;
  2104. totalRotation = Stuff::EulerAngles(0.0f,sensorSpin * DEGREES_TO_RADS,0.0f);
  2105. //----------------------------------------------
  2106. // Do geometry here to draw sensor contact
  2107. sensorTriangleShape->SetFogRGB(0xffffffff);
  2108. sensorTriangleShape->SetLightList(eye->getWorldLights(),eye->getNumLights());
  2109. sensorTriangleShape->TransformMultiShape (&xlatPosition,&totalRotation);
  2110. //----------------------------------------------
  2111. // Do geometry here to draw sensor contact
  2112. sensorCircleShape->SetFogRGB(0xffffffff);
  2113. sensorCircleShape->SetLightList(eye->getWorldLights(),eye->getNumLights());
  2114. sensorCircleShape->TransformMultiShape (&xlatPosition,&totalRotation);
  2115. }
  2116. //-----------------------------------------------------------------------------
  2117. long GVAppearance::update (bool animate)
  2118. {
  2119. //----------------------------------------
  2120. // Recycle the weapon Nodes
  2121. if (nodeRecycle)
  2122. {
  2123. for (long i=0;i<appearType->numWeaponNodes;i++)
  2124. {
  2125. if (nodeRecycle[i] > 0.0f)
  2126. {
  2127. nodeRecycle[i] -= frameLength;
  2128. if (nodeRecycle[i] < 0.0f)
  2129. nodeRecycle[i] = 0.0f;
  2130. }
  2131. }
  2132. }
  2133. //Update flashing regardless of view!!!
  2134. if (duration > 0.0f)
  2135. {
  2136. duration -= frameLength;
  2137. currentFlash -= frameLength;
  2138. if (currentFlash < 0.0f)
  2139. {
  2140. drawFlash ^= true;
  2141. currentFlash = flashDuration;
  2142. }
  2143. }
  2144. else
  2145. {
  2146. drawFlash = false;
  2147. }
  2148. //Always override with our local instance.
  2149. gvShape->SetTextureHandle(0,localTextureHandle);
  2150. if ((status == OBJECT_STATUS_DESTROYED) || (status == OBJECT_STATUS_DISABLED))
  2151. {
  2152. gvShape->SetLightsOut(true);
  2153. }
  2154. if (animate && gvFrameRate != 0.0f)
  2155. {
  2156. //--------------------------------------------------------
  2157. // Make sure animation runs no faster than bdFrameRate fps.
  2158. float frameInc = gvFrameRate * frameLength;
  2159. //---------------------------------------
  2160. // Increment Frames -- Everything else!
  2161. if (frameInc != 0.0f)
  2162. {
  2163. if (!setFirstFrame) //DO NOT ANIMATE ON FIRST FRAME! Wait a bit!
  2164. {
  2165. if (isReversed)
  2166. currentFrame -= frameInc;
  2167. else
  2168. currentFrame += frameInc;
  2169. }
  2170. else
  2171. {
  2172. setFirstFrame = false;
  2173. }
  2174. //--------------------------------------
  2175. //Check Positive overflow of Animation
  2176. if (currentFrame >= appearType->getNumFrames(gvAnimationState))
  2177. {
  2178. if (isLooping)
  2179. currentFrame -= appearType->getNumFrames(gvAnimationState);
  2180. else
  2181. currentFrame = appearType->getNumFrames(gvAnimationState) - 1;
  2182. canTransition = true; //Whenever we have completed one cycle or at last frame, OK to move on!
  2183. }
  2184. //--------------------------------------
  2185. //Check negative overflow of gesture
  2186. if (currentFrame < 0)
  2187. {
  2188. if (isLooping)
  2189. currentFrame += appearType->getNumFrames(gvAnimationState);
  2190. else
  2191. currentFrame = 0.0f;
  2192. canTransition = true; //Whenever we have completed one cycle or at last frame, OK to move on!
  2193. }
  2194. }
  2195. gvShape->SetFrameNum(currentFrame);
  2196. }
  2197. if ((turn < 3) || inView)
  2198. updateGeometry();
  2199. return TRUE;
  2200. }
  2201. //-----------------------------------------------------------------------------
  2202. void GVAppearance::destroy (void)
  2203. {
  2204. if (gvShape)
  2205. {
  2206. delete gvShape;
  2207. gvShape = NULL;
  2208. }
  2209. if (gvShadowShape)
  2210. {
  2211. delete gvShadowShape;
  2212. gvShadowShape = NULL;
  2213. }
  2214. if (sensorCircleShape)
  2215. {
  2216. delete sensorCircleShape;
  2217. sensorCircleShape = NULL;
  2218. }
  2219. if (sensorTriangleShape)
  2220. {
  2221. delete sensorTriangleShape;
  2222. sensorTriangleShape = NULL;
  2223. }
  2224. if (destructFX)
  2225. {
  2226. destructFX->Kill();
  2227. delete destructFX;
  2228. destructFX = NULL;
  2229. }
  2230. if (waterWake)
  2231. {
  2232. waterWake->Kill();
  2233. delete waterWake;
  2234. waterWake = NULL;
  2235. }
  2236. if (dustCloud)
  2237. {
  2238. dustCloud->Kill();
  2239. delete dustCloud;
  2240. dustCloud = NULL;
  2241. }
  2242. if (activity)
  2243. {
  2244. activity->Kill();
  2245. delete activity;
  2246. activity = NULL;
  2247. }
  2248. appearanceTypeList->removeAppearance(appearType);
  2249. }
  2250. //-----------------------------------------------------------------------------
  2251. void GVAppearance::startWaterWake (void)
  2252. {
  2253. //Check if we are already playing one. If not, wake city.
  2254. //First, check if its even loaded.
  2255. // can easily preload this. Should we? Memory?
  2256. if (!waterWake && useNonWeaponEffects)
  2257. {
  2258. if (strcmp(weaponEffects->GetEffectName(VEHICLE_WATER_WAKE),"NONE") != 0)
  2259. {
  2260. //--------------------------------------------
  2261. // Yes, load it on up.
  2262. unsigned flags = gosFX::Effect::ExecuteFlag|gosFX::Effect::LoopFlag;
  2263. Check_Object(gosFX::EffectLibrary::Instance);
  2264. gosFX::Effect::Specification* gosEffectSpec = gosFX::EffectLibrary::Instance->Find(weaponEffects->GetEffectName(VEHICLE_WATER_WAKE));
  2265. if (gosEffectSpec)
  2266. {
  2267. waterWake = gosFX::EffectLibrary::Instance->MakeEffect(gosEffectSpec->m_effectID, flags);
  2268. gosASSERT(waterWake != NULL);
  2269. MidLevelRenderer::MLRTexturePool::Instance->LoadImages();
  2270. }
  2271. }
  2272. }
  2273. if (waterWake && !isWaking) //Start the effect if we are not running it yet!!
  2274. {
  2275. Stuff::LinearMatrix4D shapeOrigin;
  2276. Stuff::LinearMatrix4D localToWorld;
  2277. Stuff::LinearMatrix4D localResult;
  2278. Stuff::Point3D wakePos;
  2279. wakePos.x = -position.x;
  2280. wakePos.y = Terrain::waterElevation; //Wake is at Water Level!
  2281. wakePos.z = position.y;
  2282. shapeOrigin.BuildRotation(Stuff::EulerAngles(0.0f,0.0f,0.0f));
  2283. shapeOrigin.BuildTranslation(wakePos);
  2284. Stuff::UnitQuaternion effectRot;
  2285. effectRot = Stuff::EulerAngles(90.0f * DEGREES_TO_RADS,rotation * DEGREES_TO_RADS,0.0f);
  2286. localToWorld.Multiply(gosFX::Effect_Against_Motion,effectRot);
  2287. localResult.Multiply(localToWorld,shapeOrigin);
  2288. gosFX::Effect::ExecuteInfo info((Stuff::Time)scenarioTime,&localResult,NULL);
  2289. waterWake->Start(&info);
  2290. isWaking = true;
  2291. }
  2292. }
  2293. //-----------------------------------------------------------------------------
  2294. void GVAppearance::stopWaterWake (void)
  2295. {
  2296. if (waterWake && isWaking) //Stop the effect if we are running it!!
  2297. {
  2298. waterWake->Kill();
  2299. }
  2300. isWaking = false;
  2301. }
  2302. //-----------------------------------------------------------------------------
  2303. void GVAppearance::startActivity (long effectId, bool loop)
  2304. {
  2305. //Check if we are already playing one. If not, be active!
  2306. //First, check if its even loaded.
  2307. // can easily preload this. Should we? NO. We don't know what will be passed in.
  2308. if (!activity && useNonWeaponEffects)
  2309. {
  2310. if (strcmp(weaponEffects->GetEffectName(effectId),"NONE") != 0)
  2311. {
  2312. //--------------------------------------------
  2313. // Yes, load it on up.
  2314. unsigned flags = gosFX::Effect::ExecuteFlag|gosFX::Effect::LoopFlag;
  2315. if (!loop)
  2316. flags = gosFX::Effect::ExecuteFlag;
  2317. Check_Object(gosFX::EffectLibrary::Instance);
  2318. gosFX::Effect::Specification* gosEffectSpec = gosFX::EffectLibrary::Instance->Find(weaponEffects->GetEffectName(effectId));
  2319. if (gosEffectSpec)
  2320. {
  2321. activity = gosFX::EffectLibrary::Instance->MakeEffect(gosEffectSpec->m_effectID, flags);
  2322. gosASSERT(activity != NULL);
  2323. MidLevelRenderer::MLRTexturePool::Instance->LoadImages();
  2324. }
  2325. }
  2326. }
  2327. if (!isActivitying && activity) //Start the effect if we are not running it yet!!
  2328. {
  2329. Stuff::LinearMatrix4D shapeOrigin;
  2330. Stuff::LinearMatrix4D localToWorld;
  2331. Stuff::LinearMatrix4D localResult;
  2332. if (activityNodeIndex == -1)
  2333. activityNodeIndex = gvShape->GetNodeNameId("activity_node");
  2334. Stuff::Vector3D nodePos = getNodeIdPosition(activityNodeIndex);
  2335. Stuff::Point3D wakePos;
  2336. wakePos.x = -nodePos.x;
  2337. wakePos.y = nodePos.z; //Wake is at Water Level!
  2338. wakePos.z = nodePos.y;
  2339. shapeOrigin.BuildRotation(Stuff::EulerAngles(0.0f,0.0f,0.0f));
  2340. shapeOrigin.BuildTranslation(wakePos);
  2341. /*
  2342. Stuff::UnitQuaternion effectRot;
  2343. effectRot = Stuff::EulerAngles(0.0f,rotation * DEGREES_TO_RADS,0.0f);
  2344. localToWorld.Multiply(gosFX::Effect_Against_Motion,effectRot);
  2345. localResult.Multiply(localToWorld,shapeOrigin);
  2346. */
  2347. gosFX::Effect::ExecuteInfo info((Stuff::Time)scenarioTime,&shapeOrigin,NULL);
  2348. activity->Start(&info);
  2349. isActivitying = true;
  2350. }
  2351. }
  2352. //-----------------------------------------------------------------------------
  2353. void GVAppearance::stopActivity (void)
  2354. {
  2355. if (activity && isActivitying) //Stop the effect if we are running it!!
  2356. {
  2357. activity->Kill();
  2358. }
  2359. isActivitying = false;
  2360. }
  2361. //-----------------------------------------------------------------------------
  2362. bool GVAppearance::PerPolySelect (long mouseX, long mouseY)
  2363. {
  2364. return gvShape->PerPolySelect(mouseX,mouseY);
  2365. }
  2366. //-----------------------------------------------------------------------------
  2367. void GVAppearance::flashBuilding (float dur, float fDuration, DWORD color)
  2368. {
  2369. duration = dur;
  2370. flashDuration = fDuration;
  2371. flashColor = color;
  2372. drawFlash = true;
  2373. currentFlash = flashDuration;
  2374. }
  2375. //*****************************************************************************