W3DTreeBuffer.cpp 74 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048
  1. /*
  2. ** Command & Conquer Generals Zero Hour(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. ////////////////////////////////////////////////////////////////////////////////
  19. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. // FILE: W3DTreeBuffer.cpp ////////////////////////////////////////////////
  24. //-----------------------------------------------------------------------------
  25. //
  26. // Westwood Studios Pacific.
  27. //
  28. // Confidential Information
  29. // Copyright (C) 2001 - All Rights Reserved
  30. //
  31. //-----------------------------------------------------------------------------
  32. //
  33. // Project: RTS3
  34. //
  35. // File name: W3DTreeBuffer.cpp
  36. //
  37. // Created: John Ahlquist, May 2001
  38. //
  39. // Desc: Draw buffer to handle all the trees in a scene.
  40. //
  41. //-----------------------------------------------------------------------------
  42. // ------------------------------------------------------------------------------------------------
  43. /** Topple options */
  44. // ------------------------------------------------------------------------------------------------
  45. enum
  46. {
  47. W3D_TOPPLE_OPTIONS_NONE = 0x00000000,
  48. W3D_TOPPLE_OPTIONS_NO_BOUNCE = 0x00000001, ///< do not bounce when hit the ground
  49. W3D_TOPPLE_OPTIONS_NO_FX = 0x00000002 ///< do not play any FX when hit the ground
  50. };
  51. //-----------------------------------------------------------------------------
  52. // Includes
  53. //-----------------------------------------------------------------------------
  54. #include "W3DDevice/GameClient/W3DTreeBuffer.h"
  55. #include <stdio.h>
  56. #include <string.h>
  57. #include <assetmgr.h>
  58. #include <texture.h>
  59. #include "Common/MapReaderWriterInfo.h"
  60. #include "Common/FileSystem.h"
  61. #include "Common/file.h"
  62. #include "Common/PerfTimer.h"
  63. #include "Common/Player.h"
  64. #include "Common/PlayerList.h"
  65. #include "GameLogic/ScriptEngine.h"
  66. #include "GameLogic/GameLogic.h"
  67. #include "GameLogic/Object.h"
  68. #include "GameLogic/PartitionManager.h"
  69. #include "GameClient/ClientRandomValue.h"
  70. #include "GameClient/FXList.h"
  71. #include "W3DDevice/GameClient/TerrainTex.h"
  72. #include "W3DDevice/GameClient/HeightMap.h"
  73. #include "W3DDevice/GameClient/W3DDynamicLight.h"
  74. #include "W3DDevice/GameClient/Module/W3DTreeDraw.h"
  75. #include "W3DDevice/GameClient/W3DShaderManager.h"
  76. #include "W3DDevice/GameClient/W3DShadow.h"
  77. #include "W3DDevice/GameClient/W3DShroud.h"
  78. #include "W3DDevice/GameClient/W3DProjectedShadow.h"
  79. #include "WW3D2/Camera.h"
  80. #include "WW3D2/DX8Wrapper.h"
  81. #include "WW3D2/DX8Renderer.h"
  82. #include "WW3D2/Matinfo.h"
  83. #include "WW3D2/Mesh.h"
  84. #include "WW3D2/MeshMdl.h"
  85. #include "d3dx8tex.h"
  86. #ifdef _INTERNAL
  87. // for occasional debugging...
  88. //#pragma optimize("", off)
  89. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  90. #endif
  91. // If TEST_AND_BLEND is defined, it will do an alpha test and blend. Otherwise just alpha test. jba. [5/30/2003]
  92. #define dontTEST_AND_BLEND 1
  93. #define USE_STATIC 1
  94. #define END_OF_PARTITION (-1)
  95. #define DELETED_TREE_TYPE (-2)
  96. /******************************************************************************
  97. W3DTreeTextureClass
  98. ******************************************************************************/
  99. //-----------------------------------------------------------------------------
  100. // Public Functions
  101. //-----------------------------------------------------------------------------
  102. //=============================================================================
  103. // W3DTreeBuffer::W3DTreeTextureClass::W3DTreeTextureClass
  104. //=============================================================================
  105. /** Constructor. Calls parent constructor to create a 16 bit per pixel D3D
  106. texture of the desired height and mip level. */
  107. //=============================================================================
  108. W3DTreeBuffer::W3DTreeTextureClass::W3DTreeTextureClass(unsigned width, unsigned height) :
  109. TextureClass(width, height,
  110. WW3D_FORMAT_A8R8G8B8, MIP_LEVELS_ALL )
  111. {
  112. }
  113. //=============================================================================
  114. // W3DTreeBuffer::W3DTreeTextureClass::update
  115. //=============================================================================
  116. /** Sets the tile bitmap data into the texture. The tiles are placed with 4
  117. pixel borders around them, so that when the tiles are scaled and bilinearly
  118. interpolated, you don't get seams between the tiles. */
  119. //=============================================================================
  120. int W3DTreeBuffer::W3DTreeTextureClass::update(W3DTreeBuffer *buffer)
  121. {
  122. //Set to clamp.
  123. Get_Filter().Set_U_Addr_Mode(TextureFilterClass::TEXTURE_ADDRESS_CLAMP);
  124. Get_Filter().Set_V_Addr_Mode(TextureFilterClass::TEXTURE_ADDRESS_CLAMP);
  125. IDirect3DSurface8 *surface_level;
  126. D3DSURFACE_DESC surface_desc;
  127. D3DLOCKED_RECT locked_rect;
  128. DX8_ErrorCode(Peek_D3D_Texture()->GetSurfaceLevel(0, &surface_level));
  129. DX8_ErrorCode(surface_level->GetDesc(&surface_desc));
  130. DX8_ErrorCode(surface_level->LockRect(&locked_rect, NULL, 0));
  131. Int tilePixelExtent = TILE_PIXEL_EXTENT;
  132. // Int numRows = surface_desc.Height/(tilePixelExtent+TILE_OFFSET);
  133. #ifdef _DEBUG
  134. //DASSERT_MSG(tilesPerRow*numRows >= htMap->m_numBitmapTiles,Debug::Format ("Too many tiles."));
  135. //DEBUG_ASSERTCRASH((Int)surface_desc.Width >= tilePixelExtent*tilesPerRow, ("Bitmap too small."));
  136. #endif
  137. if (surface_desc.Format == D3DFMT_A8R8G8B8) {
  138. Int tileNdx;
  139. Int pixelBytes = 4;
  140. #if 0 // Fill unused texture for debug display.
  141. UnsignedInt cellX, cellY;
  142. for (cellX = 0; cellX < surface_desc.Width; cellX++) {
  143. for (cellY = 0; cellY < surface_desc.Height; cellY++) {
  144. UnsignedByte *pBGR = ((UnsignedByte *)locked_rect.pBits)+(cellY*surface_desc.Width+cellX)*pixelBytes;
  145. //*((Short*)pBGR) = 0x8000 + (((255-2*cellY)>>3)<<10) + ((4*cellX)>>4);
  146. *((Int*)pBGR) = 0xFF000000 | ( (((255-cellY))<<16) + ((cellX)) );
  147. }
  148. }
  149. #endif
  150. for (tileNdx=0; tileNdx < buffer->getNumTiles(); tileNdx++) {
  151. TileData *pTile = buffer->getSourceTile(tileNdx);
  152. if (!pTile) continue;
  153. ICoord2D position = pTile->m_tileLocationInTexture;
  154. if (position.x<0) {
  155. continue;
  156. }
  157. Int i,j;
  158. for (j=0; j<tilePixelExtent; j++) {
  159. UnsignedByte *pBGR = pTile->getRGBDataForWidth(tilePixelExtent);
  160. pBGR += (tilePixelExtent-(1+j))*TILE_BYTES_PER_PIXEL*tilePixelExtent; // invert to match.
  161. Int row = position.y+j;
  162. UnsignedByte *pBGRA = ((UnsignedByte*)locked_rect.pBits) +
  163. (row)*surface_desc.Width*pixelBytes;
  164. Int column = position.x;
  165. pBGRA += column*pixelBytes;
  166. for (i=0; i<tilePixelExtent; i++) {
  167. // 15 bit color *((Short*)pBGRA) = 0x8000 + ((pBGR[2]>>3)<<10) + ((pBGR[1]>>3)<<5) + (pBGR[0]>>3);
  168. *((Int *)pBGRA) = (pBGR[3]<<24) + (pBGR[2]<<16) + (pBGR[1]<<8) + (pBGR[0]);
  169. pBGRA +=pixelBytes;
  170. pBGR +=TILE_BYTES_PER_PIXEL;
  171. }
  172. }
  173. }
  174. }
  175. DX8_ErrorCode(surface_level->UnlockRect());
  176. surface_level->Release();
  177. DX8_ErrorCode(D3DXFilterTexture(Peek_D3D_Texture(), NULL, (UINT)0, D3DX_FILTER_BOX));
  178. if (TheWritableGlobalData->m_textureReductionFactor) {
  179. DX8_ErrorCode(Peek_D3D_Texture()->SetLOD((DWORD)TheWritableGlobalData->m_textureReductionFactor));
  180. }
  181. return(surface_desc.Height);
  182. }
  183. //=============================================================================
  184. // W3DTreeBuffer::W3DTreeTextureClass::setLOD
  185. //=============================================================================
  186. /** Sets the lod of the texture to be loaded into the video card. */
  187. //=============================================================================
  188. void W3DTreeBuffer::W3DTreeTextureClass::setLOD(Int LOD) const
  189. {
  190. if (Peek_D3D_Texture()) {
  191. DX8_ErrorCode(Peek_D3D_Texture()->SetLOD((DWORD)LOD));
  192. }
  193. }
  194. //=============================================================================
  195. // W3DTreeBuffer::W3DTreeTextureClass::Apply
  196. //=============================================================================
  197. /** Sets the texture as the current D3D texture, and does some custom setup
  198. (standard D3D setup, but beyond the scope of W3D). */
  199. //=============================================================================
  200. void W3DTreeBuffer::W3DTreeTextureClass::Apply(unsigned int stage)
  201. {
  202. // Do the base apply.
  203. TextureClass::Apply(stage);
  204. }
  205. //-----------------------------------------------------------------------------
  206. // Private Data
  207. //-----------------------------------------------------------------------------
  208. #ifdef TEST_AND_BLEND
  209. // A W3D shader that does alpha, texturing, tests zbuffer, doesn't update zbuffer.
  210. #define SC_ALPHA_DETAIL ( SHADE_CNST(ShaderClass::PASS_LEQUAL, ShaderClass::DEPTH_WRITE_ENABLE, ShaderClass::COLOR_WRITE_ENABLE, ShaderClass::SRCBLEND_SRC_ALPHA, \
  211. ShaderClass::DSTBLEND_ONE_MINUS_SRC_ALPHA, ShaderClass::FOG_DISABLE, ShaderClass::GRADIENT_MODULATE, ShaderClass::SECONDARY_GRADIENT_DISABLE, ShaderClass::TEXTURING_ENABLE, \
  212. ShaderClass::ALPHATEST_ENABLE, ShaderClass::CULL_MODE_ENABLE, \
  213. ShaderClass::DETAILCOLOR_DISABLE, ShaderClass::DETAILALPHA_DISABLE) )
  214. #define SC_ALPHA_DETAIL_2X ( SHADE_CNST(ShaderClass::PASS_LEQUAL, ShaderClass::DEPTH_WRITE_ENABLE, ShaderClass::COLOR_WRITE_ENABLE, ShaderClass::SRCBLEND_SRC_ALPHA, \
  215. ShaderClass::DSTBLEND_ONE_MINUS_SRC_ALPHA, ShaderClass::FOG_DISABLE, ShaderClass::GRADIENT_MODULATE2X, ShaderClass::SECONDARY_GRADIENT_DISABLE, ShaderClass::TEXTURING_ENABLE, \
  216. ShaderClass::ALPHATEST_ENABLE, ShaderClass::CULL_MODE_ENABLE, \
  217. ShaderClass::DETAILCOLOR_DISABLE, ShaderClass::DETAILALPHA_DISABLE) )
  218. #else
  219. #define SC_ALPHA_DETAIL ( SHADE_CNST(ShaderClass::PASS_LEQUAL, ShaderClass::DEPTH_WRITE_ENABLE, ShaderClass::COLOR_WRITE_ENABLE, ShaderClass::SRCBLEND_ONE, \
  220. ShaderClass::DSTBLEND_ZERO, ShaderClass::FOG_DISABLE, ShaderClass::GRADIENT_MODULATE, ShaderClass::SECONDARY_GRADIENT_DISABLE, ShaderClass::TEXTURING_ENABLE, \
  221. ShaderClass::ALPHATEST_ENABLE, ShaderClass::CULL_MODE_DISABLE, \
  222. ShaderClass::DETAILCOLOR_DISABLE, ShaderClass::DETAILALPHA_DISABLE) )
  223. #define SC_ALPHA_DETAIL_2X ( SHADE_CNST(ShaderClass::PASS_LEQUAL, ShaderClass::DEPTH_WRITE_ENABLE, ShaderClass::COLOR_WRITE_ENABLE, ShaderClass::SRCBLEND_ONE, \
  224. ShaderClass::DSTBLEND_ZERO, ShaderClass::FOG_DISABLE, ShaderClass::GRADIENT_MODULATE2X, ShaderClass::SECONDARY_GRADIENT_DISABLE, ShaderClass::TEXTURING_ENABLE, \
  225. ShaderClass::ALPHATEST_ENABLE, ShaderClass::CULL_MODE_ENABLE, \
  226. ShaderClass::DETAILCOLOR_DISABLE, ShaderClass::DETAILALPHA_DISABLE) )
  227. #endif
  228. static ShaderClass detailAlphaShader(SC_ALPHA_DETAIL);
  229. static ShaderClass detailAlphaShader2X(SC_ALPHA_DETAIL_2X);
  230. /*
  231. #define SC_ALPHA_DETAIL ( SHADE_CNST(ShaderClass::PASS_LEQUAL, ShaderClass::DEPTH_WRITE_ENABLE, ShaderClass::COLOR_WRITE_ENABLE, ShaderClass::SRCBLEND_ONE, \
  232. ShaderClass::DSTBLEND_ZERO, ShaderClass::FOG_DISABLE, ShaderClass::GRADIENT_MODULATE, ShaderClass::SECONDARY_GRADIENT_DISABLE, ShaderClass::TEXTURING_ENABLE, \
  233. ShaderClass::ALPHATEST_ENABLE, ShaderClass::CULL_MODE_DISABLE, \
  234. ShaderClass::DETAILCOLOR_DISABLE, ShaderClass::DETAILALPHA_DISABLE) )
  235. static ShaderClass detailAlphaShader(SC_ALPHA_DETAIL);
  236. */
  237. /*
  238. #define SC_ALPHA_DETAIL ( SHADE_CNST(ShaderClass::PASS_LEQUAL, ShaderClass::DEPTH_WRITE_DISABLE, ShaderClass::COLOR_WRITE_ENABLE, ShaderClass::SRCBLEND_SRC_ALPHA, \
  239. ShaderClass::DSTBLEND_ONE_MINUS_SRC_ALPHA, ShaderClass::FOG_DISABLE, ShaderClass::GRADIENT_MODULATE, ShaderClass::SECONDARY_GRADIENT_DISABLE, ShaderClass::TEXTURING_ENABLE, \
  240. ShaderClass::ALPHATEST_ENABLE, ShaderClass::CULL_MODE_ENABLE, \
  241. ShaderClass::DETAILCOLOR_DISABLE, ShaderClass::DETAILALPHA_DISABLE) )
  242. static ShaderClass detailAlphaShader(SC_ALPHA_DETAIL);
  243. */
  244. /*
  245. #define SC_ALPHA_MIRROR ( SHADE_CNST(ShaderClass::PASS_LEQUAL, ShaderClass::DEPTH_WRITE_DISABLE, ShaderClass::COLOR_WRITE_ENABLE, ShaderClass::SRCBLEND_SRC_ALPHA, \
  246. ShaderClass::DSTBLEND_ONE_MINUS_SRC_ALPHA, ShaderClass::FOG_DISABLE, ShaderClass::GRADIENT_MODULATE, ShaderClass::SECONDARY_GRADIENT_DISABLE, ShaderClass::TEXTURING_ENABLE, \
  247. ShaderClass::DETAILCOLOR_DISABLE, ShaderClass::DETAILALPHA_DISABLE, ShaderClass::ALPHATEST_DISABLE, ShaderClass::CULL_MODE_DISABLE, \
  248. ShaderClass::DETAILCOLOR_DISABLE, ShaderClass::DETAILALPHA_DISABLE) )
  249. static ShaderClass mirrorAlphaShader(SC_ALPHA_DETAIL);
  250. // ShaderClass::PASS_ALWAYS,
  251. #define SC_ALPHA_2D ( SHADE_CNST(PASS_ALWAYS, DEPTH_WRITE_DISABLE, COLOR_WRITE_ENABLE, \
  252. SRCBLEND_SRC_ALPHA, DSTBLEND_ONE_MINUS_SRC_ALPHA, FOG_DISABLE, GRADIENT_DISABLE, \
  253. SECONDARY_GRADIENT_DISABLE, TEXTURING_ENABLE, DETAILCOLOR_DISABLE, DETAILALPHA_DISABLE, \
  254. ALPHATEST_DISABLE, CULL_MODE_ENABLE, DETAILCOLOR_DISABLE, DETAILALPHA_DISABLE) )
  255. ShaderClass ShaderClass::_PresetAlpha2DShader(SC_ALPHA_2D);
  256. */
  257. //-----------------------------------------------------------------------------
  258. // Private Functions
  259. //-----------------------------------------------------------------------------
  260. //=============================================================================
  261. // W3DTreeBuffer::cull
  262. //=============================================================================
  263. /** Culls the trees, marking the visible flag. If a tree becomes visible, it sets
  264. it's sortKey */
  265. //=============================================================================
  266. void W3DTreeBuffer::cull(const CameraClass * camera)
  267. {
  268. Int curTree;
  269. // Calulate the vector direction that the camera is looking at.
  270. Matrix3D camera_matrix = camera->Get_Transform();
  271. float zmod = -1;
  272. float x = zmod * camera_matrix[0][2] ;
  273. float y = zmod * camera_matrix[1][2] ;
  274. float z = zmod * camera_matrix[2][2] ;
  275. m_cameraLookAtVector.Set(x,y,z);
  276. for (curTree=0; curTree<m_numTrees; curTree++) {
  277. Bool doKey = false; // We calculate the key when a tree becomes visible.
  278. Bool visible = !camera->Cull_Sphere(m_trees[curTree].bounds);
  279. if (visible != m_trees[curTree].visible) {
  280. m_trees[curTree].visible=visible;
  281. m_anythingChanged = true;
  282. if (visible) {
  283. doKey = true;
  284. }
  285. }
  286. // Also calculate sort key if a tree is visible, and the view changed setting m_updateAllKeys to true.
  287. if (doKey || (visible&&m_updateAllKeys)) {
  288. // The sort key is essentially the distance of location in the direction of the
  289. // camera look at.
  290. m_trees[curTree].sortKey = Vector3::Dot_Product(m_trees[curTree].location, m_cameraLookAtVector);
  291. }
  292. }
  293. m_updateAllKeys = false;
  294. }
  295. //=============================================================================
  296. // W3DTreeBuffer::getPartitionBucket
  297. //=============================================================================
  298. /** Returns the bucket index into m_areaPartition for a given location. */
  299. //=============================================================================
  300. Int W3DTreeBuffer::getPartitionBucket(const Coord3D &pos) const
  301. {
  302. Real x = pos.x;
  303. Real y = pos.y;
  304. if (x<m_bounds.lo.x) x = m_bounds.lo.x;
  305. if (y<m_bounds.lo.y) y = m_bounds.lo.y;
  306. if (x>m_bounds.hi.x) x = m_bounds.hi.x;
  307. if (y>m_bounds.hi.y) y = m_bounds.hi.y;
  308. Int xIndex = REAL_TO_INT_FLOOR ( (x/(m_bounds.hi.x-m_bounds.lo.x)) * (PARTITION_WIDTH_HEIGHT-0.1f) );
  309. Int yIndex = REAL_TO_INT_FLOOR ( (y/(m_bounds.hi.y-m_bounds.lo.y)) * (PARTITION_WIDTH_HEIGHT-0.1f) );
  310. DEBUG_ASSERTCRASH(xIndex>=0 && yIndex>=0 && xIndex<PARTITION_WIDTH_HEIGHT && yIndex<PARTITION_WIDTH_HEIGHT, ("Invalid range."));
  311. return yIndex*PARTITION_WIDTH_HEIGHT + xIndex;
  312. }
  313. //=============================================================================
  314. // W3DTreeBuffer::cull
  315. //=============================================================================
  316. /** Culls the trees, marking the visible flag. If a tree becomes visible, it sets
  317. it's sortKey */
  318. //=============================================================================
  319. void W3DTreeBuffer::updateSway(const BreezeInfo& info)
  320. {
  321. Int i;
  322. for (i=0; i<NUM_SWAY_ENTRIES; i++) {
  323. Real factor = Cos(i*2.0f*PI/(NUM_SWAY_ENTRIES+1.0f));
  324. Real angle = info.m_lean + (info.m_intensity * factor);
  325. Real S = Sin(angle);
  326. Real C = Cos(angle);
  327. m_swayOffsets[i].X = info.m_directionVec.x * S;
  328. m_swayOffsets[i].Y = info.m_directionVec.y * S;
  329. m_swayOffsets[i].Z = C - 1.0f;
  330. }
  331. Real delta = info.m_randomness * 0.5f;
  332. for (i=0; i<m_numTrees; i++) {
  333. m_trees[i].swayType = 1+GameClientRandomValue(0, MAX_SWAY_TYPES-1);
  334. }
  335. for (i=0; i<MAX_SWAY_TYPES; i++) {
  336. m_curSwayStep[i] = NUM_SWAY_ENTRIES / (Real)info.m_breezePeriod;
  337. m_curSwayStep[i] *= GameClientRandomValueReal(1.0f-delta, 1.0f+delta);
  338. if (m_curSwayStep[i]<0.0f) {
  339. m_curSwayStep[i] = 0.0f;
  340. }
  341. m_curSwayOffset[i] = 0;
  342. m_curSwayFactor[i] = GameClientRandomValueReal(1.0f-delta, 1.0f+delta);
  343. }
  344. m_curSwayVersion = info.m_breezeVersion;
  345. }
  346. #if 0 // sort is not used, and messes up the order jba. [6/6/2003]
  347. //=============================================================================
  348. // W3DTreeBuffer::sort
  349. //=============================================================================
  350. /** Sorts the trees. Does num_iterations of a bubble sort. This is good because
  351. it ends immediately if the trees are already sorted (which is most of the time)
  352. and will perform a fixed amount of work each frame until it becomes sorted. */
  353. //=============================================================================
  354. void W3DTreeBuffer::sort(Int numIterations)
  355. {
  356. // sort in descending order.
  357. Int iter;
  358. Bool swap = false;
  359. for (iter = 0; iter<numIterations; iter++) {
  360. Int cur = 0;
  361. // Note - only sorts the visible trees.
  362. while (cur<m_numTrees-iter && !m_trees[cur].visible) {
  363. cur++;
  364. }
  365. Int i;
  366. for (i=cur+1; i<m_numTrees-iter; i++) {
  367. if (m_trees[i].visible) {
  368. if (m_trees[cur].sortKey > m_trees[i].sortKey) {
  369. TTree tmp = m_trees[cur];
  370. m_trees[cur] = m_trees[i];
  371. m_trees[i] = tmp;
  372. swap = true;
  373. }
  374. cur = i;
  375. }
  376. }
  377. if (!swap) {
  378. return;
  379. }
  380. m_anythingChanged = true;
  381. }
  382. }
  383. #endif
  384. /********** GDIFileStream2 class ****************************/
  385. class GDIFileStream2 : public InputStream
  386. {
  387. protected:
  388. File* m_file;
  389. public:
  390. GDIFileStream2():m_file(NULL) {};
  391. GDIFileStream2(File* pFile):m_file(pFile) {};
  392. virtual Int read(void *pData, Int numBytes) {
  393. return(m_file?m_file->read(pData, numBytes):0);
  394. };
  395. };
  396. //=============================================================================
  397. // W3DTreeBuffer::updateTexture
  398. //=============================================================================
  399. /** Creates a new texture. */
  400. //=============================================================================
  401. void W3DTreeBuffer::updateTexture(void)
  402. {
  403. const Int MAX_TEX_WIDTH = 2048;
  404. Int i, j;
  405. Int maxHeight = 0;
  406. const Int maxTilesPerRow = MAX_TEX_WIDTH/(TILE_PIXEL_EXTENT);
  407. REF_PTR_RELEASE(m_treeTexture);
  408. Bool availableGrid[maxTilesPerRow][maxTilesPerRow];
  409. Int row, column;
  410. for (row=0; row<maxTilesPerRow; row++) {
  411. for (column=0; column<maxTilesPerRow; column++) {
  412. availableGrid[row][column] = true;
  413. }
  414. }
  415. for (i=0; i<m_numTiles; i++) {
  416. REF_PTR_RELEASE (m_sourceTiles[i]);
  417. }
  418. m_numTiles = 0;
  419. File *theFile = NULL;
  420. for (i=0; i<m_numTreeTypes; i++) {
  421. char texturePath[ _MAX_PATH ];
  422. m_treeTypes[i].m_numTiles = 0;
  423. sprintf( texturePath, "%s%s", TERRAIN_TGA_DIR_PATH, m_treeTypes[i].m_data->m_textureName.str() );
  424. theFile = TheFileSystem->openFile( texturePath, File::READ|File::BINARY);
  425. if (theFile==NULL) {
  426. sprintf( texturePath, "%s%s", TGA_DIR_PATH, m_treeTypes[i].m_data->m_textureName.str() );
  427. theFile = TheFileSystem->openFile( texturePath, File::READ|File::BINARY);
  428. }
  429. if (theFile != NULL) {
  430. GDIFileStream2 theStream(theFile);
  431. InputStream *pStr = &theStream;
  432. Bool halfTile;
  433. Int numTiles = WorldHeightMap::countTiles(pStr, &halfTile);
  434. Int width;
  435. for (width = 10; width >= 1; width--) {
  436. if (numTiles >= width*width) {
  437. numTiles = width*width;
  438. break;
  439. }
  440. }
  441. Bool texFound = false;
  442. for (j=0; j<i; j++) {
  443. if (m_treeTypes[j].m_data->m_textureName.compareNoCase(m_treeTypes[i].m_data->m_textureName)==0) {
  444. m_treeTypes[i].m_firstTile = 0;
  445. m_treeTypes[i].m_tileWidth = width;
  446. m_treeTypes[i].m_numTiles = 0;
  447. texFound = true;
  448. break;
  449. }
  450. }
  451. if (texFound) {
  452. theFile->close();
  453. continue;
  454. }
  455. if (m_numTiles+numTiles<=MAX_TILES) {
  456. theFile->seek(0, File::START);
  457. m_treeTypes[i].m_firstTile = m_numTiles;
  458. m_treeTypes[i].m_tileWidth = width;
  459. m_treeTypes[i].m_numTiles = numTiles;
  460. m_treeTypes[i].m_halfTile = halfTile;
  461. WorldHeightMap::readTiles(pStr, m_sourceTiles+m_treeTypes[i].m_firstTile, width);
  462. m_numTiles += numTiles;
  463. } else {
  464. m_treeTypes[i].m_firstTile = 0;
  465. m_treeTypes[i].m_tileWidth = 0;
  466. m_treeTypes[i].m_numTiles = 0;
  467. }
  468. theFile->close();
  469. } else {
  470. DEBUG_CRASH(("Could not find texture %s\n", m_treeTypes[i].m_data->m_textureName.str()));
  471. m_treeTypes[i].m_firstTile = 0;
  472. m_treeTypes[i].m_tileWidth = 0;
  473. m_treeTypes[i].m_numTiles = 0;
  474. }
  475. }
  476. Int tmpWidth = 8;
  477. while (tmpWidth*tmpWidth<m_numTiles) {
  478. tmpWidth*=2;
  479. }
  480. Int tilesPerRow = tmpWidth;
  481. m_textureWidth = tmpWidth*TILE_PIXEL_EXTENT;
  482. if (m_textureWidth>MAX_TEX_WIDTH) {
  483. m_textureWidth = 64;
  484. m_textureHeight = 64;
  485. if (m_treeTexture==NULL) {
  486. m_treeTexture = new TextureClass("missing.tga");
  487. }
  488. DEBUG_CRASH(("Too many trees in a scene."));
  489. return;
  490. }
  491. for (i=0; i<m_numTiles; i++) {
  492. if (m_sourceTiles[i]) {
  493. m_sourceTiles[i]->m_tileLocationInTexture.x = -1;
  494. m_sourceTiles[i]->m_tileLocationInTexture.y = -1;
  495. }
  496. }
  497. /* put the tree tiles into the texture */
  498. Int texClass;
  499. Int tileWidth;
  500. for (tileWidth = tilesPerRow; tileWidth>0; tileWidth--) {
  501. for (texClass=0; texClass<m_numTreeTypes; texClass++) {
  502. Int width = m_treeTypes[texClass].m_tileWidth;
  503. if (width != tileWidth) continue;
  504. Bool texFound = false;
  505. for (i=0; i<texClass; i++) {
  506. if (m_treeTypes[i].m_data->m_textureName.compareNoCase(m_treeTypes[texClass].m_data->m_textureName)==0) {
  507. m_treeTypes[texClass].m_textureOrigin.x = m_treeTypes[i].m_textureOrigin.x;
  508. m_treeTypes[texClass].m_textureOrigin.y = m_treeTypes[i].m_textureOrigin.y;
  509. texFound = true;
  510. break;
  511. }
  512. }
  513. if (texFound) {
  514. continue;
  515. }
  516. // Find an available block of space.
  517. Bool found = false;
  518. for (row=0; row<(tilesPerRow-width)+1 && !found; row++) {
  519. for (column=0; column<(tilesPerRow-width)+1 && !found; column++) {
  520. if (availableGrid[row][column]) {
  521. Bool open = true;
  522. for (i=0; i<width && open; i++) {
  523. for (j=0; j<width&&open; j++) {
  524. if (!availableGrid[row+j][column+i]) {
  525. open = false;
  526. }
  527. }
  528. }
  529. if (open) found = true;
  530. break;
  531. }
  532. }
  533. if (found) break;
  534. }
  535. if (!found) {
  536. m_treeTypes[texClass].m_textureOrigin.x = 0;
  537. m_treeTypes[texClass].m_textureOrigin.y = 0;
  538. continue;
  539. }
  540. Int xOrigin = column*(TILE_PIXEL_EXTENT);
  541. Int yOrigin = row*(TILE_PIXEL_EXTENT);
  542. m_treeTypes[texClass].m_textureOrigin.x = xOrigin;
  543. m_treeTypes[texClass].m_textureOrigin.y = yOrigin;
  544. Int classHeight = yOrigin + width*TILE_PIXEL_EXTENT;
  545. if (maxHeight < classHeight) maxHeight = classHeight;
  546. for (i=0; i<width; i++) {
  547. for (j=0; j<width; j++) {
  548. availableGrid[row+j][column+i] = false;
  549. Int baseNdx = m_treeTypes[texClass].m_firstTile + i + j*width;
  550. Int x = xOrigin + i*TILE_PIXEL_EXTENT;
  551. Int y = yOrigin + ((width-j)-1)*TILE_PIXEL_EXTENT;
  552. m_sourceTiles[baseNdx]->m_tileLocationInTexture.x = x;
  553. m_sourceTiles[baseNdx]->m_tileLocationInTexture.y = y;
  554. }
  555. }
  556. }
  557. }
  558. DEBUG_ASSERTCRASH(maxHeight<=m_textureWidth, ("Bad max height."));
  559. W3DTreeTextureClass *tex = new W3DTreeTextureClass((DWORD)m_textureWidth, (DWORD)m_textureWidth);
  560. m_textureHeight = tex->update(this);
  561. m_treeTexture = tex;
  562. for (i=0; i<m_numTiles; i++) {
  563. REF_PTR_RELEASE (m_sourceTiles[i]);
  564. }
  565. // m_treeTexture = NEW_REF (TextureClass, (m_treeTypes[0].m_textureName.str()));
  566. }
  567. /**Adjust the resolution of tree texture uploaded to the video card. The system memory
  568. version always remains at full resolution. Someone should probably optimize this at
  569. some point since it wastes a lot of system memory on low-end systems. -MW
  570. */
  571. void W3DTreeBuffer::setTextureLOD(Int lod)
  572. {
  573. if (m_treeTexture)
  574. ((W3DTreeTextureClass*)m_treeTexture)->setLOD(lod);
  575. }
  576. //=============================================================================
  577. // W3DTreeBuffer::doLighting
  578. //=============================================================================
  579. /** Calculates the diffuse lighting as affected by dynamic lighting. */
  580. //=============================================================================
  581. UnsignedInt W3DTreeBuffer::doLighting(const Vector3 *normal,
  582. const GlobalData::TerrainLighting *objectLighting,
  583. const Vector3 *emissive, UnsignedInt vertDiffuse, Real scale) const
  584. {
  585. Real shadeR, shadeG, shadeB;
  586. Real shade;
  587. shadeR = objectLighting[0].ambient.red+emissive->X; //only the first light contributes to ambient
  588. shadeG = objectLighting[0].ambient.green+emissive->Y;
  589. shadeB = objectLighting[0].ambient.blue+emissive->Z;
  590. Int i;
  591. for (i=0; i<MAX_GLOBAL_LIGHTS; i++) {
  592. Vector3 lightDirection(objectLighting[i].lightPos.x, objectLighting[i].lightPos.y, objectLighting[i].lightPos.z);
  593. lightDirection.Normalize();
  594. Vector3 lightRay(-lightDirection.X, -lightDirection.Y, -lightDirection.Z);
  595. shade = Vector3::Dot_Product(lightRay, *normal);
  596. if (shade > 1.0) shade = 1.0;
  597. if(shade < 0.0f) shade = 0.0f;
  598. shadeR += shade*objectLighting[i].diffuse.red;
  599. shadeG += shade*objectLighting[i].diffuse.green;
  600. shadeB += shade*objectLighting[i].diffuse.blue;
  601. }
  602. shadeR *= scale;
  603. shadeG *= scale;
  604. shadeB *= scale;
  605. if (shadeR > 1.0) shadeR = 1.0;
  606. if(shadeR < 0.0f) shadeR = 0.0f;
  607. if (shadeG > 1.0) shadeG = 1.0;
  608. if(shadeG < 0.0f) shadeG = 0.0f;
  609. if (shadeB > 1.0) shadeB = 1.0;
  610. if(shadeB < 0.0f) shadeB = 0.0f;
  611. if (vertDiffuse!=0xFFFFFFFF) {
  612. shade = vertDiffuse&0xff; //blue;
  613. shadeB *= shade/255.0f;
  614. shade = (vertDiffuse>>8)&0xFF; // green;
  615. shadeG *= shade/255.0f;
  616. shade = (vertDiffuse>>16)&0xFF; // red;
  617. shadeR *= shade/255.0f;
  618. }
  619. shadeR*=255.0f;
  620. shadeG*=255.0f;
  621. shadeB*=255.0f;
  622. const Real alpha = 255.0;
  623. return REAL_TO_UNSIGNEDINT(shadeB) | (REAL_TO_INT(shadeG) << 8) | (REAL_TO_INT(shadeR) << 16) | ((Int)alpha << 24);
  624. }
  625. //=============================================================================
  626. // W3DTreeBuffer::loadTreesInVertexAndIndexBuffers
  627. //=============================================================================
  628. /** Loads the trees into the vertex buffer for drawing. */
  629. //=============================================================================
  630. void W3DTreeBuffer::loadTreesInVertexAndIndexBuffers(RefRenderObjListIterator *pDynamicLightsIterator)
  631. {
  632. if (!m_indexTree[0] || !m_vertexTree[0] || !m_initialized) {
  633. return;
  634. }
  635. if (!m_anythingChanged) {
  636. return;
  637. }
  638. if (m_shadow == NULL && TheW3DProjectedShadowManager) {
  639. Shadow::ShadowTypeInfo shadowInfo;
  640. shadowInfo.m_ShadowName[0] = 0;
  641. shadowInfo.allowUpdates=FALSE; //shadow image will never update
  642. shadowInfo.allowWorldAlign=TRUE; //shadow image will wrap around world objects
  643. shadowInfo.m_type = (ShadowType)SHADOW_DECAL;
  644. shadowInfo.m_sizeX=20;
  645. shadowInfo.m_sizeY=20;
  646. shadowInfo.m_offsetX=0;
  647. shadowInfo.m_offsetY=0;
  648. m_shadow = TheW3DProjectedShadowManager->createDecalShadow(&shadowInfo);
  649. }
  650. m_anythingChanged = false;
  651. Int curTree=0;
  652. Int bNdx;
  653. const GlobalData::TerrainLighting *objectLighting = TheGlobalData->m_terrainObjectsLighting[TheGlobalData->m_timeOfDay];
  654. for (bNdx=0; bNdx<MAX_BUFFERS; bNdx++) {
  655. m_curNumTreeVertices[bNdx] = 0;
  656. m_curNumTreeIndices[bNdx] = 0;
  657. if (curTree >= m_numTrees) {
  658. break;
  659. }
  660. VertexFormatXYZNDUV1 *vb;
  661. UnsignedShort *ib;
  662. // Lock the buffers.
  663. #ifdef USE_STATIC
  664. DX8IndexBufferClass::WriteLockClass lockIdxBuffer(m_indexTree[bNdx], 0);
  665. DX8VertexBufferClass::WriteLockClass lockVtxBuffer(m_vertexTree[bNdx], 0);
  666. #else
  667. DX8IndexBufferClass::WriteLockClass lockIdxBuffer(m_indexTree[bNdx], D3DLOCK_DISCARD);
  668. DX8VertexBufferClass::WriteLockClass lockVtxBuffer(m_vertexTree[bNdx], D3DLOCK_DISCARD);
  669. #endif
  670. vb=(VertexFormatXYZNDUV1*)lockVtxBuffer.Get_Vertex_Array();
  671. ib = lockIdxBuffer.Get_Index_Array();
  672. // Add to the index buffer & vertex buffer.
  673. Vector2 lookAtVector(m_cameraLookAtVector.X, m_cameraLookAtVector.Y);
  674. lookAtVector.Normalize();
  675. // We draw from back to front, so we put the indexes in the buffer
  676. // from back to front.
  677. UnsignedShort *curIb = ib;
  678. VertexFormatXYZNDUV1 *curVb = vb;
  679. for ( ;curTree<m_numTrees;curTree++) {
  680. Int type = m_trees[curTree].treeType;
  681. if (type<0) {
  682. continue; // Deleted tree. [6/9/2003]
  683. }
  684. if (!m_trees[curTree].visible) continue;
  685. Real scale = m_trees[curTree].scale;
  686. Vector3 loc = m_trees[curTree].location;
  687. Real theSin = m_trees[curTree].sin;
  688. Real theCos = m_trees[curTree].cos;
  689. if (type<0 || m_treeTypes[type].m_mesh == 0) {
  690. continue;
  691. }
  692. Bool doVertexLighting = true;
  693. #if 0 // no dynamic lighting.
  694. for (pDynamicLightsIterator->First(); !pDynamicLightsIterator->Is_Done(); pDynamicLightsIterator->Next())
  695. {
  696. W3DDynamicLight *pLight = (W3DDynamicLight*)pDynamicLightsIterator->Peek_Obj();
  697. if (!pLight->isEnabled()) {
  698. continue; // he is turned off.
  699. }
  700. if (CollisionMath::Overlap_Test(m_trees[curTree].bounds, pLight->Get_Bounding_Sphere()) == CollisionMath::OUTSIDE) {
  701. continue; // this tree is outside of the light's influence.
  702. }
  703. doVertexLighting = true;
  704. }
  705. #endif
  706. Vector3 emissive(0.0f,0.0f,0.0f);
  707. MaterialInfoClass * matInfo = m_treeTypes[type].m_mesh->Get_Material_Info();
  708. if (matInfo) {
  709. VertexMaterialClass *vertMat = matInfo->Peek_Vertex_Material(0);
  710. if (vertMat) {
  711. vertMat->Get_Emissive(&emissive);
  712. }
  713. }
  714. REF_PTR_RELEASE(matInfo);
  715. Int startVertex = m_curNumTreeVertices[bNdx];
  716. m_trees[curTree].firstIndex = startVertex;
  717. m_trees[curTree].bufferNdx = bNdx;
  718. Int i;
  719. Int numVertex = m_treeTypes[type].m_mesh->Peek_Model()->Get_Vertex_Count();
  720. Vector3 *pVert = m_treeTypes[type].m_mesh->Peek_Model()->Get_Vertex_Array();
  721. // If we happen to have too many trees, stop.
  722. if (m_curNumTreeVertices[bNdx]+numVertex+2>= MAX_TREE_VERTEX) {
  723. break;
  724. }
  725. Int numIndex = m_treeTypes[type].m_mesh->Peek_Model()->Get_Polygon_Count();
  726. const TriIndex *pPoly = m_treeTypes[type].m_mesh->Peek_Model()->Get_Polygon_Array();
  727. if (m_curNumTreeIndices[bNdx]+3*numIndex+6 >= MAX_TREE_INDEX) {
  728. break;
  729. }
  730. const Vector2*uvs=m_treeTypes[type].m_mesh->Peek_Model()->Get_UV_Array_By_Index(0);
  731. const Vector3*normals = m_treeTypes[type].m_mesh->Peek_Model()->Get_Vertex_Normal_Array();
  732. const unsigned *vecDiffuse = m_treeTypes[type].m_mesh->Peek_Model()->Get_Color_Array(0, false);
  733. Int diffuse = 0;
  734. if (normals == NULL) {
  735. doVertexLighting = false;
  736. Vector3 normal(0.0f,0.0f,1.0f);
  737. diffuse = doLighting(&normal, objectLighting, &emissive, 0xFFFFFFFF, 1.0f);
  738. }
  739. /*
  740. *
  741. // If we are doing reduced resolution terrain, do reduced
  742. // poly trees.
  743. Bool doPanel = (TheGlobalData->m_useHalfHeightMap || TheGlobalData->m_stretchTerrain);
  744. if (doPanel) {
  745. if (m_trees[curTree].rotates) {
  746. theSin = -lookAtVector.X;
  747. theCos = lookAtVector.Y;
  748. }
  749. // panel start is index offset, there are 3 index per triangle.
  750. if (m_trees[curTree].panelStart/3 + 2 > numIndex) {
  751. continue; // not enought polygons for the offset. jba.
  752. }
  753. for (j=0; j<6; j++) {
  754. i = ((Int *)pPoly)[j+m_trees[curTree].panelStart];
  755. if (m_curNumTreeVertices >= MAX_TREE_VERTEX)
  756. break;
  757. // Update the uv values. The W3D models each have their own texture, and
  758. // we use one texture with all images in one, so we have to change the uvs to
  759. // match.
  760. Real U, V;
  761. if (type==SHRUB) {
  762. // shrub texture is tucked in the corner
  763. U = ((512-64)+uvs[i].U*64.0f)/512.0f;
  764. V = ((256-64)+uvs[i].V*64.0f)/256.0f;
  765. } else if (type==FENCE) {
  766. U = uvs[i].U*0.5f;
  767. V = 1.0f + uvs[i].V;
  768. } else {
  769. U = typeOffset+uvs[i].U*0.5f;
  770. V = uvs[i].V;
  771. }
  772. curVb->u1 = U;
  773. curVb->v1 = V/2.0;
  774. Vector3 vLoc;
  775. vLoc.X = pVert[i].X*scale*theCos - pVert[i].Y*scale*theSin;
  776. vLoc.Y = pVert[i].Y*scale*theCos + pVert[i].X*scale*theSin;
  777. vLoc.X += loc.X;
  778. vLoc.Y += loc.Y;
  779. vLoc.Z = loc.Z + pVert[i].Z*scale;
  780. curVb->x = vLoc.X;
  781. curVb->y = vLoc.Y;
  782. curVb->z = vLoc.Z;
  783. if (doVertexLighting) {
  784. curVb->diffuse = doLighting(&vLoc, shadeR, shadeG, shadeB, m_trees[curTree].bounds, pDynamicLightsIterator);
  785. } else {
  786. curVb->diffuse = diffuse;
  787. }
  788. curVb++;
  789. m_curNumTreeVertices++;
  790. }
  791. for (i=0; i<6; i++) {
  792. if (m_curNumTreeIndices+4 > MAX_TREE_INDEX)
  793. break;
  794. curIb--;
  795. *curIb = startVertex + i;
  796. m_curNumTreeIndices++;
  797. }
  798. } else {
  799. */
  800. Real Uscale = m_treeTypes[type].m_tileWidth * (Real)TILE_PIXEL_EXTENT / (Real)m_textureWidth;
  801. Real Vscale = m_treeTypes[type].m_tileWidth * (Real)TILE_PIXEL_EXTENT / (Real)m_textureHeight;
  802. Real UOffset = m_treeTypes[type].m_textureOrigin.x/(Real)m_textureWidth;
  803. Real VOffset = m_treeTypes[type].m_textureOrigin.y/(Real)m_textureHeight;
  804. if (m_treeTypes[type].m_halfTile) {
  805. Uscale *= 0.5f;
  806. Vscale *= 0.5f;
  807. VOffset += (TILE_PIXEL_EXTENT/2) / (Real)m_textureHeight;
  808. }
  809. for (i=0; i<numVertex; i++) {
  810. if (m_curNumTreeVertices[bNdx] >= MAX_TREE_VERTEX)
  811. break;
  812. // Update the uv values. The W3D models each have their own texture, and
  813. // we use one texture with all images in one, so we have to change the uvs to
  814. // match.
  815. Real U, V;
  816. U = uvs[i].U;
  817. V = uvs[i].V;
  818. if (U>1.0f) U=1.0f;
  819. if (U<0.0f) U=0.0f;
  820. if (V>1.0f) V=1.0f;
  821. if (V<0.0f) V=0.0f;
  822. curVb->u1 = U*Uscale + UOffset;
  823. curVb->v1 = V*Vscale + VOffset;
  824. Real x = pVert[i].X;
  825. Real y = pVert[i].Y;
  826. Vector3 vLoc;
  827. x += m_treeTypes[type].m_offset.X;
  828. y += m_treeTypes[type].m_offset.Y;
  829. vLoc.X = x*scale*theCos - y*scale*theSin;
  830. vLoc.Y = y*scale*theCos + x*scale*theSin;
  831. vLoc.Z = pVert[i].Z*scale;
  832. vLoc.Z += m_treeTypes[type].m_offset.Z;
  833. if (m_trees[curTree].m_toppleState != TOPPLE_UPRIGHT) {
  834. Matrix3D::Transform_Vector(m_trees[curTree].m_mtx, vLoc, &vLoc);
  835. } else {
  836. if (m_trees[curTree].pushAside>0.0f) {
  837. vLoc.X += pVert[i].Z * m_trees[curTree].pushAside * m_trees[curTree].pushAsideCos * m_treeTypes[type].m_data->m_maxOutwardMovement;
  838. vLoc.Y += pVert[i].Z * m_trees[curTree].pushAside * m_trees[curTree].pushAsideSin* m_treeTypes[type].m_data->m_maxOutwardMovement;
  839. }
  840. vLoc.X += loc.X;
  841. vLoc.Y += loc.Y;
  842. vLoc.Z += loc.Z;
  843. }
  844. curVb->x = vLoc.X;
  845. curVb->y = vLoc.Y;
  846. curVb->z = vLoc.Z;
  847. curVb->nx = m_trees[curTree].swayType;
  848. curVb->ny = 1.0f - m_treeTypes[type].m_data->m_darkening*m_trees[curTree].pushAside;
  849. curVb->nz = loc.Z;
  850. if (doVertexLighting) {
  851. Vector3 normal(0.0f, 0.0f, 1.0f);
  852. if (normals) {
  853. normal.X = normals[i].X*theCos - normals[i].Y*theSin;
  854. normal.Y = normals[i].Y*theCos + normals[i].X*theSin;
  855. normal.Z = normals[i].Z;
  856. }
  857. UnsignedInt vertexDiffuse;
  858. if (vecDiffuse) {
  859. vertexDiffuse = vecDiffuse[i];
  860. } else {
  861. vertexDiffuse = 0xffffffff;
  862. }
  863. curVb->diffuse = doLighting(&normal, objectLighting, &emissive,
  864. vertexDiffuse, 1.0f);
  865. } else {
  866. curVb->diffuse = diffuse;
  867. }
  868. curVb++;
  869. m_curNumTreeVertices[bNdx]++;
  870. }
  871. try {
  872. for (i=0; i<numIndex; i++) {
  873. if (m_curNumTreeIndices[bNdx]+4 > MAX_TREE_INDEX)
  874. break;
  875. *curIb++ = startVertex + pPoly[i].I;
  876. *curIb++ = startVertex + pPoly[i].J;
  877. *curIb++ = startVertex + pPoly[i].K;
  878. m_curNumTreeIndices[bNdx]+=3;
  879. }
  880. IndexBufferExceptionFunc();
  881. } catch(...) {
  882. IndexBufferExceptionFunc();
  883. }
  884. }
  885. }
  886. }
  887. //=============================================================================
  888. // W3DTreeBuffer::updateVertexBuffer
  889. //=============================================================================
  890. /** Updates the push aside offset in vertex buffer. */
  891. //=============================================================================
  892. void W3DTreeBuffer::updateVertexBuffer(void)
  893. {
  894. if (!m_indexTree[0] || !m_vertexTree[0] || !m_initialized) {
  895. return;
  896. }
  897. Int bNdx;
  898. for (bNdx = 0; bNdx<MAX_BUFFERS; bNdx++) {
  899. if (m_curNumTreeIndices[bNdx]==0) {
  900. break;
  901. }
  902. VertexFormatXYZNDUV1 *vb;
  903. // Lock the buffers.
  904. #ifdef USE_STATIC
  905. DX8VertexBufferClass::WriteLockClass lockVtxBuffer(m_vertexTree[bNdx], 0);
  906. #else
  907. DX8VertexBufferClass::WriteLockClass lockVtxBuffer(m_vertexTree[bNdx], D3DLOCK_DISCARD);
  908. #endif
  909. vb=(VertexFormatXYZNDUV1*)lockVtxBuffer.Get_Vertex_Array();
  910. VertexFormatXYZNDUV1 *curVb;
  911. Int curTree;
  912. for (curTree=0; curTree<m_numTrees; curTree++) {
  913. if (m_trees[curTree].bufferNdx!=bNdx) {
  914. continue;
  915. }
  916. Int type = m_trees[curTree].treeType;
  917. if (type<0) {
  918. continue; // Deleted tree. [6/9/2003]
  919. }
  920. if (m_trees[curTree].pushAsideDelta==0.0f && m_trees[curTree].m_toppleState == TOPPLE_UPRIGHT) {
  921. continue; // not toppling or pushed, no need to update. jba [7/11/2003]
  922. }
  923. m_anyPushChanged = true;
  924. if (!m_trees[curTree].visible) continue;
  925. Real scale = m_trees[curTree].scale;
  926. Vector3 loc = m_trees[curTree].location;
  927. Real theSin = m_trees[curTree].sin;
  928. Real theCos = m_trees[curTree].cos;
  929. if (type<0 || m_treeTypes[type].m_mesh == 0) {
  930. type = 0;
  931. }
  932. Int startVertex = m_trees[curTree].firstIndex;
  933. curVb = vb+startVertex;
  934. Int i;
  935. Int numVertex = m_treeTypes[type].m_mesh->Peek_Model()->Get_Vertex_Count();
  936. Vector3 *pVert = m_treeTypes[type].m_mesh->Peek_Model()->Get_Vertex_Array();
  937. for (i=0; i<numVertex; i++) {
  938. Real x = pVert[i].X;
  939. Real y = pVert[i].Y;
  940. Vector3 vLoc;
  941. x += m_treeTypes[type].m_offset.X;
  942. y += m_treeTypes[type].m_offset.Y;
  943. vLoc.X = x*scale*theCos - y*scale*theSin;
  944. vLoc.Y = y*scale*theCos + x*scale*theSin;
  945. vLoc.Z = pVert[i].Z*scale;
  946. vLoc.Z += m_treeTypes[type].m_offset.Z;
  947. if (m_trees[curTree].m_toppleState != TOPPLE_UPRIGHT) {
  948. m_trees[curTree].m_mtx.Transform_Vector(m_trees[curTree].m_mtx, vLoc, &vLoc);
  949. } else {
  950. if (m_trees[curTree].pushAside>0.0f) {
  951. vLoc.X += pVert[i].Z * m_trees[curTree].pushAside * m_trees[curTree].pushAsideCos * m_treeTypes[type].m_data->m_maxOutwardMovement;
  952. vLoc.Y += pVert[i].Z * m_trees[curTree].pushAside * m_trees[curTree].pushAsideSin* m_treeTypes[type].m_data->m_maxOutwardMovement;
  953. }
  954. vLoc.X += loc.X;
  955. vLoc.Y += loc.Y;
  956. vLoc.Z += loc.Z;
  957. }
  958. curVb->x = vLoc.X;
  959. curVb->y = vLoc.Y;
  960. curVb->z = vLoc.Z;
  961. curVb->ny = 1.0f - m_treeTypes[type].m_data->m_darkening*m_trees[curTree].pushAside;
  962. curVb++;
  963. }
  964. }
  965. }
  966. }
  967. //-----------------------------------------------------------------------------
  968. // Public Functions
  969. //-----------------------------------------------------------------------------
  970. //=============================================================================
  971. // W3DTreeBuffer::~W3DTreeBuffer
  972. //=============================================================================
  973. /** Destructor. Releases w3d assets. */
  974. //=============================================================================
  975. W3DTreeBuffer::~W3DTreeBuffer(void)
  976. {
  977. freeTreeBuffers();
  978. REF_PTR_RELEASE(m_treeTexture);
  979. Int i;
  980. for (i=0; i<MAX_TYPES; i++) {
  981. REF_PTR_RELEASE(m_treeTypes[i].m_mesh);
  982. }
  983. if (m_shadow) {
  984. delete m_shadow;
  985. m_shadow = NULL;
  986. }
  987. }
  988. //=============================================================================
  989. // W3DTreeBuffer::W3DTreeBuffer
  990. //=============================================================================
  991. /** Constructor. Sets m_initialized to true if it finds the w3d models it needs
  992. for the trees. */
  993. //=============================================================================
  994. W3DTreeBuffer::W3DTreeBuffer(void)
  995. {
  996. memset(this, sizeof(W3DTreeBuffer), 0);
  997. m_initialized = false;
  998. Int i;
  999. for (i=0; i<MAX_BUFFERS; i++) {
  1000. m_vertexTree[i] = NULL;
  1001. m_indexTree[i] = NULL;
  1002. m_curNumTreeVertices[i]=0;
  1003. m_curNumTreeIndices[i]=0;
  1004. }
  1005. m_treeTexture = NULL;
  1006. m_dwTreeVertexShader = 0;
  1007. m_dwTreePixelShader = 0;
  1008. clearAllTrees();
  1009. allocateTreeBuffers();
  1010. m_initialized = true;
  1011. m_curSwayVersion = -1;
  1012. m_shadow = NULL;
  1013. }
  1014. //=============================================================================
  1015. // W3DTreeBuffer::freeTreeBuffers
  1016. //=============================================================================
  1017. /** Frees the index and vertex buffers. */
  1018. //=============================================================================
  1019. void W3DTreeBuffer::freeTreeBuffers(void)
  1020. {
  1021. Int i;
  1022. for (i=0; i<MAX_BUFFERS; i++) {
  1023. REF_PTR_RELEASE(m_vertexTree[i]);
  1024. REF_PTR_RELEASE(m_indexTree[i]);
  1025. }
  1026. if (m_dwTreePixelShader)
  1027. DX8Wrapper::_Get_D3D_Device8()->DeletePixelShader(m_dwTreePixelShader);
  1028. m_dwTreePixelShader = 0;
  1029. if (m_dwTreeVertexShader)
  1030. DX8Wrapper::_Get_D3D_Device8()->DeleteVertexShader(m_dwTreeVertexShader);
  1031. m_dwTreeVertexShader = 0;
  1032. }
  1033. //=============================================================================
  1034. // W3DTreeBuffer::unitMoved
  1035. //=============================================================================
  1036. /** Check to see if a unit collided with a tree/grass/bush. */
  1037. //=============================================================================
  1038. void W3DTreeBuffer::unitMoved(Object *unit)
  1039. {
  1040. if (unit->isKindOf(KINDOF_IMMOBILE)) {
  1041. // This is the initial positioning of the object, and we don't care. jba. [6/5/2003]
  1042. return;
  1043. }
  1044. Real radius = unit->getGeometryInfo().getMajorRadius();
  1045. if (unit->getGeometryInfo().getGeomType()==GEOMETRY_BOX) {
  1046. if (radius>unit->getGeometryInfo().getMinorRadius()) {
  1047. radius = unit->getGeometryInfo().getMinorRadius();
  1048. }
  1049. }
  1050. // Value to assume for the tree radius.
  1051. #define TREE_RADIUS_APPROX 7.0f
  1052. radius += TREE_RADIUS_APPROX;
  1053. Coord3D pos = *unit->getPosition();
  1054. Real x = pos.x-radius;
  1055. Real y = pos.y-radius;
  1056. if (x<m_bounds.lo.x) x = m_bounds.lo.x;
  1057. if (y<m_bounds.lo.y) y = m_bounds.lo.y;
  1058. if (x>m_bounds.hi.x) x = m_bounds.hi.x;
  1059. if (y>m_bounds.hi.y) y = m_bounds.hi.y;
  1060. Int xIndex = REAL_TO_INT_FLOOR ( (x/(m_bounds.hi.x-m_bounds.lo.x)) * (PARTITION_WIDTH_HEIGHT-0.1f) );
  1061. Int yIndex = REAL_TO_INT_FLOOR ( (y/(m_bounds.hi.y-m_bounds.lo.y)) * (PARTITION_WIDTH_HEIGHT-0.1f) );
  1062. DEBUG_ASSERTCRASH(xIndex>=0 && yIndex>=0 && xIndex<PARTITION_WIDTH_HEIGHT && yIndex<PARTITION_WIDTH_HEIGHT, ("Invalid range."));
  1063. x = pos.x+radius;
  1064. y = pos.y+radius;
  1065. if (x<m_bounds.lo.x) x = m_bounds.lo.x;
  1066. if (y<m_bounds.lo.y) y = m_bounds.lo.y;
  1067. if (x>m_bounds.hi.x) x = m_bounds.hi.x;
  1068. if (y>m_bounds.hi.y) y = m_bounds.hi.y;
  1069. Int xMax = REAL_TO_INT_CEIL ( (x/(m_bounds.hi.x-m_bounds.lo.x)) * (PARTITION_WIDTH_HEIGHT-0.1f) );
  1070. Int yMax = REAL_TO_INT_CEIL ( (y/(m_bounds.hi.y-m_bounds.lo.y)) * (PARTITION_WIDTH_HEIGHT-0.1f) );
  1071. DEBUG_ASSERTCRASH(xMax>=0 && yMax>=0 && xMax<=PARTITION_WIDTH_HEIGHT && yMax<=PARTITION_WIDTH_HEIGHT, ("Invalid range."));
  1072. Int i, j;
  1073. for (i=xIndex; i<xMax; i++) {
  1074. for (j=yIndex; j<yMax; j++) {
  1075. Int treeNdx = m_areaPartition[i + PARTITION_WIDTH_HEIGHT*j];
  1076. while (treeNdx != END_OF_PARTITION) {
  1077. // paranoia [7/7/2003]
  1078. if (treeNdx<0 || treeNdx>=m_numTrees) {
  1079. DEBUG_CRASH(("Invalid index."));
  1080. break;
  1081. }
  1082. if (m_trees[treeNdx].treeType<0) {
  1083. treeNdx = m_trees[treeNdx].nextInPartition;
  1084. continue; // Tree is deleted. [7/11/2003]
  1085. }
  1086. Coord3D delta;
  1087. delta.set(m_trees[treeNdx].location.X, m_trees[treeNdx].location.Y, m_trees[treeNdx].location.Z );
  1088. delta.sub(&pos);
  1089. if (radius*radius>delta.lengthSqr()) {
  1090. bool canTopple = unit->getCrusherLevel() > 1;
  1091. if (canTopple && m_treeTypes[m_trees[treeNdx].treeType].m_data->m_doTopple) {
  1092. // Give a vector with direction to thing.
  1093. Coord3D toppleVector;
  1094. toppleVector.set(m_trees[treeNdx].location.X, m_trees[treeNdx].location.Y, 0);
  1095. toppleVector.x -= unit->getPosition()->x;
  1096. toppleVector.y -= unit->getPosition()->y;
  1097. applyTopplingForce(m_trees+treeNdx, &toppleVector, 0, W3D_TOPPLE_OPTIONS_NONE);
  1098. } else if (m_treeTypes[m_trees[treeNdx].treeType].m_data->m_framesToMoveOutward>1) {
  1099. pushAsideTree(m_trees[treeNdx].drawableID, &pos, unit->getUnitDirectionVector2D(), unit->getID());
  1100. }
  1101. }
  1102. treeNdx = m_trees[treeNdx].nextInPartition;
  1103. }
  1104. }
  1105. }
  1106. }
  1107. //=============================================================================
  1108. // W3DTreeBuffer::allocateTreeBuffers
  1109. //=============================================================================
  1110. /** Allocates the index and vertex buffers. */
  1111. //=============================================================================
  1112. void W3DTreeBuffer::allocateTreeBuffers(void)
  1113. {
  1114. Int i;
  1115. for (i=0; i<MAX_BUFFERS; i++) {
  1116. #ifdef USE_STATIC
  1117. m_vertexTree[i]=NEW_REF(DX8VertexBufferClass,(DX8_FVF_XYZNDUV1,MAX_TREE_VERTEX+4,DX8VertexBufferClass::USAGE_DEFAULT));
  1118. m_indexTree[i]=NEW_REF(DX8IndexBufferClass,(MAX_TREE_INDEX+4, DX8IndexBufferClass::USAGE_DEFAULT));
  1119. #else
  1120. m_vertexTree[i]=NEW_REF(DX8VertexBufferClass,(DX8_FVF_XYZNDUV1,MAX_TREE_VERTEX+4,DX8VertexBufferClass::USAGE_DYNAMIC));
  1121. m_indexTree[i]=NEW_REF(DX8IndexBufferClass,(MAX_TREE_INDEX+4, DX8IndexBufferClass::USAGE_DYNAMIC));
  1122. #endif
  1123. m_curNumTreeVertices[i]=0;
  1124. m_curNumTreeIndices[i]=0;
  1125. }
  1126. //shader decleration
  1127. // DX8_FVF_XYZNDUV1
  1128. DWORD Declaration[] =
  1129. {
  1130. D3DVSD_STREAM( 0 ),
  1131. D3DVSD_REG( 0, D3DVSDT_FLOAT3 ), // Position
  1132. D3DVSD_REG( 1, D3DVSDT_FLOAT3 ), // Normal
  1133. D3DVSD_REG( 2, D3DVSDT_D3DCOLOR), // Diffuse color
  1134. D3DVSD_REG( 7, D3DVSDT_FLOAT2 ), // Tex coord
  1135. D3DVSD_END()
  1136. };
  1137. HRESULT hr;
  1138. hr = W3DShaderManager::LoadAndCreateD3DShader("shaders\\Trees.vso", &Declaration[0], 0, true, &m_dwTreeVertexShader);
  1139. if (FAILED(hr))
  1140. return;
  1141. hr = W3DShaderManager::LoadAndCreateD3DShader("shaders\\Trees.pso", &Declaration[0], 0, false, &m_dwTreePixelShader);
  1142. if (FAILED(hr))
  1143. return;
  1144. }
  1145. //=============================================================================
  1146. // W3DTreeBuffer::clearAllTrees
  1147. //=============================================================================
  1148. /** Removes all trees. */
  1149. //=============================================================================
  1150. void W3DTreeBuffer::clearAllTrees(void)
  1151. {
  1152. m_numTrees=0;
  1153. m_bounds.lo.x = m_bounds.lo.y = 0;
  1154. m_bounds.hi.x = m_bounds.hi.y = 1;
  1155. REF_PTR_RELEASE(m_treeTexture);
  1156. m_curNumTreeIndices[0]=0;
  1157. m_anythingChanged = true;
  1158. Int i;
  1159. for (i=0; i<MAX_TYPES; i++) {
  1160. REF_PTR_RELEASE(m_treeTypes[i].m_mesh);
  1161. }
  1162. for (i=0; i<PARTITION_WIDTH_HEIGHT*PARTITION_WIDTH_HEIGHT; i++) {
  1163. m_areaPartition[i] = END_OF_PARTITION;
  1164. }
  1165. m_numTreeTypes = 0;
  1166. }
  1167. //=============================================================================
  1168. // W3DTreeBuffer::removeTree
  1169. //=============================================================================
  1170. /** Removes a tree. */
  1171. //=============================================================================
  1172. void W3DTreeBuffer::removeTree(DrawableID id)
  1173. {
  1174. Int i;
  1175. for (i=0; i<m_numTrees; i++) {
  1176. if (m_trees[i].drawableID == id) {
  1177. m_trees[i].location = Vector3(0,0,0);
  1178. m_trees[i].treeType = DELETED_TREE_TYPE;
  1179. // Translate the bounding sphere of the model.
  1180. m_trees[i].bounds.Center = Vector3(0,0,0);
  1181. m_trees[i].bounds.Radius = 1;
  1182. m_anythingChanged = true;
  1183. }
  1184. }
  1185. }
  1186. //=============================================================================
  1187. // W3DTreeBuffer::removeTree
  1188. //=============================================================================
  1189. /** Removes any trees that would be under a building. */
  1190. //=============================================================================
  1191. void W3DTreeBuffer::removeTreesForConstruction(const Coord3D* pos, const GeometryInfo& geom, Real angle )
  1192. {
  1193. // Just iterate all trees, as even non-collidable ones get removed. jba. [7/11/2003]
  1194. Int i;
  1195. for (i=0; i<m_numTrees; i++) { // small, height, radius, minor radius
  1196. if (m_trees[i].treeType < 0) {
  1197. continue; // already deleted. jba [7/11/2003]
  1198. }
  1199. GeometryInfo info(GEOMETRY_CYLINDER, false, 5*TREE_RADIUS_APPROX, 2*TREE_RADIUS_APPROX, 2*TREE_RADIUS_APPROX);
  1200. Coord3D treePos;
  1201. treePos.set(m_trees[i].location.X, m_trees[i].location.Y, m_trees[i].location.Z);
  1202. if (ThePartitionManager->geomCollidesWithGeom( pos, geom, angle, &treePos, info, 0.0f)) {
  1203. // remove it [7/11/2003]
  1204. m_trees[i].treeType = DELETED_TREE_TYPE;
  1205. m_anythingChanged = true;
  1206. }
  1207. }
  1208. }
  1209. //=============================================================================
  1210. // W3DTreeBuffer::addTreeTypes
  1211. //=============================================================================
  1212. /** Adds a type of tree (model & texture). */
  1213. //=============================================================================
  1214. Int W3DTreeBuffer::addTreeType(const W3DTreeDrawModuleData *data)
  1215. {
  1216. if (m_numTreeTypes>=MAX_TYPES) {
  1217. DEBUG_CRASH(("Too many kinds of trees in map. Reduce kinds of trees, or raise tree limit. jba."));
  1218. return 0;
  1219. }
  1220. m_needToUpdateTexture = true;
  1221. m_treeTypes[m_numTreeTypes].m_mesh = NULL;
  1222. RenderObjClass *robj=WW3DAssetManager::Get_Instance()->Create_Render_Obj(data->m_modelName.str());
  1223. if (robj==NULL) {
  1224. DEBUG_CRASH(("Unable to find model for tree %s\n", data->m_modelName.str()));
  1225. return 0;
  1226. }
  1227. AABoxClass box;
  1228. robj->Get_Obj_Space_Bounding_Box(box);
  1229. Vector3 offset(0,0,0);
  1230. if (robj->Class_ID() == RenderObjClass::CLASSID_HLOD) {
  1231. RenderObjClass *hlod = robj;
  1232. robj = hlod->Get_Sub_Object(0);
  1233. const Matrix3D xfm = robj->Get_Bone_Transform(0);
  1234. xfm.Get_Translation(&offset);
  1235. REF_PTR_RELEASE(hlod);
  1236. }
  1237. if (robj->Class_ID() == RenderObjClass::CLASSID_MESH)
  1238. m_treeTypes[m_numTreeTypes].m_mesh = (MeshClass*)robj;
  1239. if (m_treeTypes[m_numTreeTypes].m_mesh==NULL) {
  1240. DEBUG_CRASH(("Tree %s is not simple mesh. Tell artist to re-export. Don't Ignore!!!\n", data->m_modelName.str()));
  1241. return 0;
  1242. }
  1243. Int numVertex = m_treeTypes[m_numTreeTypes].m_mesh->Peek_Model()->Get_Vertex_Count();
  1244. Vector3 *pVert = m_treeTypes[m_numTreeTypes].m_mesh->Peek_Model()->Get_Vertex_Array();
  1245. const Matrix3D xfm = m_treeTypes[m_numTreeTypes].m_mesh->Get_Transform();
  1246. SphereClass bounds(pVert, numVertex);
  1247. bounds.Center += offset;
  1248. m_treeTypes[m_numTreeTypes].m_bounds = bounds;
  1249. m_treeTypes[m_numTreeTypes].m_textureOrigin.x = 0;
  1250. m_treeTypes[m_numTreeTypes].m_textureOrigin.y = 0;
  1251. m_treeTypes[m_numTreeTypes].m_data = data;
  1252. m_treeTypes[m_numTreeTypes].m_offset = offset;
  1253. m_treeTypes[m_numTreeTypes].m_shadowSize = (box.Extent.X + box.Extent.Y); // Average extent * 2. jba.
  1254. m_treeTypes[m_numTreeTypes].m_doShadow = data->m_doShadow;
  1255. m_numTreeTypes++;
  1256. return m_numTreeTypes-1;
  1257. }
  1258. //=============================================================================
  1259. // W3DTreeBuffer::addTree
  1260. //=============================================================================
  1261. /** Adds a tree. Name is the W3D model name, supported models are
  1262. ALPINE, DECIDUOUS and SHRUB. */
  1263. //=============================================================================
  1264. void W3DTreeBuffer::addTree(DrawableID id, Coord3D location, Real scale, Real angle,
  1265. Real randomScaleAmount, const W3DTreeDrawModuleData *data)
  1266. {
  1267. if (m_numTrees >= MAX_TREES) {
  1268. return;
  1269. }
  1270. if (!m_initialized) {
  1271. return;
  1272. }
  1273. Int treeType = DELETED_TREE_TYPE;
  1274. Int i;
  1275. for (i=0; i<m_numTreeTypes; i++) {
  1276. if (m_treeTypes[i].m_data->m_modelName.compareNoCase(data->m_modelName)==0 &&
  1277. m_treeTypes[i].m_data->m_textureName.compareNoCase(data->m_textureName)==0) {
  1278. treeType = i;
  1279. break;
  1280. }
  1281. }
  1282. if (treeType<0) {
  1283. treeType = addTreeType(data);
  1284. if (treeType<0) {
  1285. return;
  1286. }
  1287. m_needToUpdateTexture = true;
  1288. }
  1289. if (data->m_framesToMoveOutward > 2 || data->m_doTopple) {
  1290. // Trees/grass that topples or gets pushed aside (outward) gets put in the area partition. jba [7/7/2003]
  1291. Short bucket = getPartitionBucket(location);
  1292. m_trees[m_numTrees].nextInPartition = m_areaPartition[bucket];
  1293. m_areaPartition[bucket] = m_numTrees;
  1294. } else {
  1295. m_trees[m_numTrees].nextInPartition = END_OF_PARTITION;
  1296. }
  1297. Real randomScale = GameClientRandomValueReal( 1.0f - randomScaleAmount, 1.0f+ randomScaleAmount );
  1298. m_trees[m_numTrees].sin = WWMath::Sin(angle);
  1299. m_trees[m_numTrees].cos = WWMath::Cos(angle);
  1300. if (randomScaleAmount>0.0f) {
  1301. // Randomizes the scale and orientation of trees.
  1302. m_trees[m_numTrees].scale = scale*randomScale;
  1303. } else {
  1304. // Don't randomly scale & orient
  1305. m_trees[m_numTrees].scale = scale;
  1306. }
  1307. m_trees[m_numTrees].location = Vector3(location.x, location.y, location.z);
  1308. m_trees[m_numTrees].treeType = treeType;
  1309. // Translate the bounding sphere of the model.
  1310. m_trees[m_numTrees].bounds = m_treeTypes[treeType].m_bounds;
  1311. m_trees[m_numTrees].bounds.Center *= m_trees[m_numTrees].scale;
  1312. m_trees[m_numTrees].bounds.Radius *= m_trees[m_numTrees].scale;
  1313. m_trees[m_numTrees].bounds.Center += m_trees[m_numTrees].location;
  1314. // Initially set it invisible. cull will update it's visiblity flag.
  1315. m_trees[m_numTrees].visible = false;
  1316. m_trees[m_numTrees].drawableID = id;
  1317. m_trees[m_numTrees].firstIndex = 0;
  1318. m_trees[m_numTrees].bufferNdx = -1;
  1319. m_trees[m_numTrees].swayType = GameClientRandomValue(0, MAX_SWAY_TYPES-1);
  1320. m_trees[m_numTrees].pushAside = 0;
  1321. m_trees[m_numTrees].lastFrameUpdated = 0;
  1322. m_trees[m_numTrees].pushAsideSource = INVALID_ID;
  1323. m_trees[m_numTrees].pushAsideDelta = 0;
  1324. m_trees[m_numTrees].pushAsideCos = 1;
  1325. m_trees[m_numTrees].pushAsideSin = 1;
  1326. m_trees[m_numTrees].m_toppleState = TOPPLE_UPRIGHT;
  1327. m_numTrees++;
  1328. }
  1329. //=============================================================================
  1330. // W3DTreeBuffer::updateTreePosition
  1331. //=============================================================================
  1332. /** Updates a tree's position */
  1333. //=============================================================================
  1334. Bool W3DTreeBuffer::updateTreePosition(DrawableID id, Coord3D location, Real angle)
  1335. {
  1336. Int i;
  1337. for (i=0; i<m_numTrees; i++) {
  1338. if (m_trees[i].drawableID == id) {
  1339. m_trees[i].location = Vector3(location.x, location.y, location.z);
  1340. m_trees[i].sin = WWMath::Sin(angle);
  1341. m_trees[i].cos = WWMath::Cos(angle);
  1342. // Translate the bounding sphere of the model.
  1343. m_trees[i].bounds = m_treeTypes[m_trees[i].treeType].m_bounds;
  1344. m_trees[i].bounds.Center *= m_trees[i].scale;
  1345. m_trees[i].bounds.Radius *= m_trees[i].scale;
  1346. m_trees[i].bounds.Center += m_trees[i].location;
  1347. m_anythingChanged = true;
  1348. return true;
  1349. }
  1350. }
  1351. return false;
  1352. }
  1353. //=============================================================================
  1354. // W3DTreeBuffer::pushAsideTree
  1355. //=============================================================================
  1356. /** Push sideways tree or grass. */
  1357. //=============================================================================
  1358. void W3DTreeBuffer::pushAsideTree(DrawableID id, const Coord3D *pusherPos,
  1359. const Coord3D *pusherDirection, ObjectID pusherID )
  1360. {
  1361. Int i;
  1362. for (i=0; i<m_numTrees; i++) {
  1363. if (m_trees[i].drawableID == id) {
  1364. UnsignedInt lastFrame = m_trees[i].lastFrameUpdated;
  1365. m_trees[i].lastFrameUpdated = TheGameLogic->getFrame();
  1366. if(m_trees[i].pushAsideSource == pusherID) {
  1367. if (m_trees[i].lastFrameUpdated - lastFrame < 3)
  1368. return; // already pushing. [5/28/2003]
  1369. }
  1370. if(m_trees[i].pushAside != 0.0f) {
  1371. return; // already pushing. [5/28/2003]
  1372. }
  1373. m_trees[i].pushAsideSource = pusherID;
  1374. Coord3D delta;
  1375. delta.set(m_trees[i].location.X, m_trees[i].location.Y, m_trees[i].location.Z);
  1376. delta.sub(pusherPos);
  1377. if (pusherDirection->x*delta.y - pusherDirection->y*delta.x > 0.0f) {
  1378. m_trees[i].pushAsideCos = -pusherDirection->y;
  1379. m_trees[i].pushAsideSin = pusherDirection->x;
  1380. } else {
  1381. m_trees[i].pushAsideCos = pusherDirection->y;
  1382. m_trees[i].pushAsideSin = -pusherDirection->x;
  1383. }
  1384. m_anyPushChanged = true;
  1385. m_trees[i].pushAsideDelta = 1.0f/(Real)m_treeTypes[m_trees[i].treeType].m_data->m_framesToMoveOutward;
  1386. }
  1387. }
  1388. }
  1389. DECLARE_PERF_TIMER(Tree_Render)
  1390. //=============================================================================
  1391. // W3DTreeBuffer::drawTrees
  1392. //=============================================================================
  1393. /** Draws the trees. Uses camera to cull. */
  1394. //=============================================================================
  1395. void W3DTreeBuffer::drawTrees(CameraClass * camera, RefRenderObjListIterator *pDynamicLightsIterator)
  1396. {
  1397. USE_PERF_TIMER(Tree_Render)
  1398. if (!m_isTerrainPass) {
  1399. return;
  1400. }
  1401. // if breeze changes, always process the full update, even if not visible,
  1402. // so that things offscreen won't 'pop' when first viewed
  1403. const BreezeInfo& info = TheScriptEngine->getBreezeInfo();
  1404. Bool pause = TheScriptEngine->isTimeFrozenScript() || TheScriptEngine->isTimeFrozenDebug();
  1405. if (TheGameLogic && TheGameLogic->isGamePaused()) {
  1406. pause = true;
  1407. }
  1408. Int i;
  1409. if (!pause) {
  1410. if (info.m_breezeVersion != m_curSwayVersion)
  1411. {
  1412. updateSway(info);
  1413. }
  1414. }
  1415. Vector3 swayFactor[MAX_SWAY_TYPES];
  1416. for (i=0; i<MAX_SWAY_TYPES; i++) {
  1417. if (!pause) {
  1418. m_curSwayOffset[i] += m_curSwayStep[i];
  1419. if (m_curSwayOffset[i] > NUM_SWAY_ENTRIES-1) {
  1420. m_curSwayOffset[i] -= NUM_SWAY_ENTRIES-1;
  1421. }
  1422. }
  1423. Int minOffset = REAL_TO_INT_FLOOR(m_curSwayOffset[i]);
  1424. if (minOffset>=0 && minOffset+1<NUM_SWAY_ENTRIES) {
  1425. Real f2 = m_curSwayOffset[i] - minOffset;
  1426. Real f1 = 1.0f - f2;
  1427. swayFactor[i] = f1*m_swayOffsets[minOffset] + f2*m_swayOffsets[minOffset+1];
  1428. swayFactor[i] *= m_curSwayFactor[i];
  1429. }
  1430. }
  1431. m_isTerrainPass = false;
  1432. if (m_needToUpdateTexture) {
  1433. m_needToUpdateTexture = false;
  1434. updateTexture();
  1435. }
  1436. if (m_treeTexture==NULL) {
  1437. return;
  1438. }
  1439. if (m_updateAllKeys) {
  1440. cull(camera);
  1441. }
  1442. Int curTree;
  1443. // Draw tree shadows.
  1444. if (m_shadow && TheW3DProjectedShadowManager && TheGlobalData->m_useShadowDecals) {
  1445. for (curTree=0; curTree<m_numTrees; curTree++) {
  1446. Int type = m_trees[curTree].treeType;
  1447. if (type<0) { // deleted.
  1448. continue;
  1449. }
  1450. if (!m_trees[curTree].visible || !m_treeTypes[type].m_doShadow) {
  1451. continue;
  1452. }
  1453. Real factor = 1.0f;
  1454. if (m_trees[curTree].m_toppleState == TOPPLE_FALLING ||
  1455. m_trees[curTree].m_toppleState == TOPPLE_DOWN) {
  1456. continue;
  1457. }
  1458. m_shadow->setSize(m_treeTypes[type].m_shadowSize, -m_treeTypes[type].m_shadowSize*factor);
  1459. m_shadow->setPosition(m_trees[curTree].location.X, m_trees[curTree].location.Y, m_trees[curTree].location.Z);
  1460. TheW3DProjectedShadowManager->queueDecal(m_shadow);
  1461. }
  1462. TheW3DProjectedShadowManager->flushDecals(m_shadow->getTexture(0), SHADOW_DECAL);
  1463. }
  1464. // Update pushed aside and toppling trees.
  1465. for (curTree=0; curTree<m_numTrees; curTree++) {
  1466. if (pause) {
  1467. break;
  1468. }
  1469. Int type = m_trees[curTree].treeType;
  1470. if (type<0) { // deleted.
  1471. continue;
  1472. }
  1473. if(m_trees[curTree].m_toppleState == TOPPLE_FALLING ||
  1474. m_trees[curTree].m_toppleState == TOPPLE_FOGGED) {
  1475. updateTopplingTree(m_trees+curTree);
  1476. } else if(m_trees[curTree].m_toppleState == TOPPLE_DOWN) {
  1477. if (m_treeTypes[type].m_data->m_killWhenToppled) {
  1478. if (m_trees[curTree].m_sinkFramesLeft==0) {
  1479. m_trees[curTree].treeType = DELETED_TREE_TYPE; // delete it. [7/11/2003]
  1480. m_anythingChanged = true; // need to regenerate trees. [7/11/2003]
  1481. }
  1482. m_trees[curTree].m_sinkFramesLeft--;
  1483. m_trees[curTree].location.Z -= m_treeTypes[type].m_data->m_sinkDistance/m_treeTypes[type].m_data->m_sinkFrames;
  1484. m_trees[curTree].m_mtx.Set_Translation(m_trees[curTree].location);
  1485. }
  1486. } else if (m_trees[curTree].pushAsideDelta!=0.0f) {
  1487. m_trees[curTree].pushAside += m_trees[curTree].pushAsideDelta;
  1488. if (m_trees[curTree].pushAside>=1.0f) {
  1489. m_trees[curTree].pushAsideDelta = -1.0/(Real)m_treeTypes[type].m_data->m_framesToMoveInward;
  1490. } else if (m_trees[curTree].pushAside<=0.0f) {
  1491. m_trees[curTree].pushAsideDelta = 0.0f;
  1492. m_trees[curTree].pushAside = 0.0f;
  1493. }
  1494. }
  1495. }
  1496. if (m_anythingChanged) {
  1497. loadTreesInVertexAndIndexBuffers(pDynamicLightsIterator);
  1498. m_anythingChanged = false;
  1499. } else if (m_anyPushChanged) {
  1500. m_anyPushChanged = false;
  1501. updateVertexBuffer();
  1502. }
  1503. //#define DEBUG_TEXTURE 1
  1504. #ifdef DEBUG_TEXTURE // Draw the combined texture for debugging. jba. [4/21/2003]
  1505. // Setup the vertex buffer, shader & texture.
  1506. DX8Wrapper::Set_Shader(detailAlphaShader);
  1507. DX8Wrapper::Set_Texture(0,m_treeTexture);
  1508. DynamicIBAccessClass ib_access(BUFFER_TYPE_DYNAMIC_DX8, 6);
  1509. //draw an infinite sky plane
  1510. DynamicVBAccessClass vb_access(BUFFER_TYPE_DYNAMIC_DX8, DX8_FVF_XYZNDUV2, 4);
  1511. {
  1512. DynamicIBAccessClass::WriteLockClass ibLock(&ib_access);
  1513. UnsignedShort *ndx = ibLock.Get_Index_Array();
  1514. if (ndx) {
  1515. ndx[0] = 0;
  1516. ndx[1] = 1;
  1517. ndx[2] = 2;
  1518. ndx[3] = 1;
  1519. ndx[4] = 3;
  1520. ndx[5] = 2;
  1521. }
  1522. DynamicVBAccessClass::WriteLockClass lock(&vb_access);
  1523. VertexFormatXYZNDUV2* verts=lock.Get_Formatted_Vertex_Array();
  1524. if(verts)
  1525. {
  1526. Real width = 300;
  1527. Real origin = 40;
  1528. verts[0].x=origin;
  1529. verts[0].y=origin;
  1530. verts[0].z=15;
  1531. verts[0].u1=0;
  1532. verts[0].v1=0;
  1533. verts[0].diffuse=0xffffffff;
  1534. verts[1].x=origin+width;
  1535. verts[1].y=origin;
  1536. verts[1].z=15;
  1537. verts[1].u1=1;
  1538. verts[1].v1=0;
  1539. verts[1].diffuse=0xffffffff;
  1540. verts[2].x=origin;
  1541. verts[2].y=origin+width;
  1542. verts[2].z=15;
  1543. verts[2].u1=0;
  1544. verts[2].v1=1;
  1545. verts[2].diffuse=0xffffffff;
  1546. verts[3].x=origin+width;
  1547. verts[3].y=origin+width;
  1548. verts[3].z=15;
  1549. verts[3].u1=1;
  1550. verts[3].v1=1;
  1551. verts[3].diffuse=0xffffffff;
  1552. }
  1553. }
  1554. DX8Wrapper::Set_Index_Buffer(ib_access,0);
  1555. DX8Wrapper::Set_Vertex_Buffer(vb_access);
  1556. Matrix3D tm(1);
  1557. DX8Wrapper::Set_Transform(D3DTS_WORLD,tm);
  1558. DX8Wrapper::Draw_Triangles( 0,2, 0, 4); //draw a quad, 2 triangles, 4 verts
  1559. #endif
  1560. if (m_curNumTreeIndices[0] == 0) {
  1561. return;
  1562. }
  1563. DX8Wrapper::Set_Shader(detailAlphaShader);
  1564. DX8Wrapper::Set_Texture(0,m_treeTexture);
  1565. DX8Wrapper::Set_Texture(1,NULL);
  1566. DX8Wrapper::Set_DX8_Texture_Stage_State(0, D3DTSS_TEXCOORDINDEX, 0);
  1567. DX8Wrapper::Set_DX8_Texture_Stage_State(1, D3DTSS_TEXCOORDINDEX, 1);
  1568. // Draw all the trees.
  1569. DX8Wrapper::Apply_Render_State_Changes();
  1570. W3DShaderManager::setShroudTex(1);
  1571. DX8Wrapper::Apply_Render_State_Changes();
  1572. if (m_dwTreeVertexShader) {
  1573. D3DXMATRIX matProj, matView, matWorld;
  1574. DX8Wrapper::_Get_DX8_Transform(D3DTS_WORLD, *(Matrix4x4*)&matWorld);
  1575. DX8Wrapper::_Get_DX8_Transform(D3DTS_VIEW, *(Matrix4x4*)&matView);
  1576. DX8Wrapper::_Get_DX8_Transform(D3DTS_PROJECTION, *(Matrix4x4*)&matProj);
  1577. D3DXMATRIX mat;
  1578. D3DXMatrixMultiply( &mat, &matView, &matProj );
  1579. D3DXMatrixMultiply( &mat, &matWorld, &mat );
  1580. D3DXMatrixTranspose( &mat, &mat );
  1581. // c4 - Composite World-View-Projection Matrix
  1582. DX8Wrapper::_Get_D3D_Device8()->SetVertexShaderConstant( 4, &mat, 4 );
  1583. Vector4 noSway(0,0,0,0);
  1584. DX8Wrapper::_Get_D3D_Device8()->SetVertexShaderConstant( 8, &noSway, 1 );
  1585. // c8 - c8+MAX_SWAY_TYPES - the sway amount.
  1586. for (i=0; i<MAX_SWAY_TYPES; i++) {
  1587. Vector4 sway4(swayFactor[i].X, swayFactor[i].Y, swayFactor[i].Z, 0);
  1588. DX8Wrapper::_Get_D3D_Device8()->SetVertexShaderConstant( 9+i, &sway4, 1 );
  1589. }
  1590. W3DShroud *shroud;
  1591. if ((shroud=TheTerrainRenderObject->getShroud()) != 0) {
  1592. // Setup shroud texture info [6/6/2003]
  1593. float xoffset = 0;
  1594. float yoffset = 0;
  1595. Real width=shroud->getCellWidth();
  1596. Real height=shroud->getCellHeight();
  1597. xoffset = -(float)shroud->getDrawOriginX() + width;
  1598. yoffset = -(float)shroud->getDrawOriginY() + height;
  1599. Vector4 offset(xoffset, yoffset, 0, 0);
  1600. DX8Wrapper::_Get_D3D_Device8()->SetVertexShaderConstant( 32, &offset, 1 );
  1601. width = 1.0f/(width*shroud->getTextureWidth());
  1602. height = 1.0f/(height*shroud->getTextureHeight());
  1603. offset.Set(width, height, 1, 1);
  1604. DX8Wrapper::_Get_D3D_Device8()->SetVertexShaderConstant( 33, &offset, 1 );
  1605. } else {
  1606. Vector4 offset(0,0,0,0);
  1607. DX8Wrapper::_Get_D3D_Device8()->SetVertexShaderConstant( 32, &offset, 1 );
  1608. DX8Wrapper::_Get_D3D_Device8()->SetVertexShaderConstant( 33, &offset, 1 );
  1609. }
  1610. DX8Wrapper::Set_Vertex_Shader(m_dwTreeVertexShader);
  1611. #if 0
  1612. DX8Wrapper::Set_Pixel_Shader(m_dwTreePixelShader);
  1613. // a.c. 6/16 - allow switching between normal and 2X mode for terrain
  1614. Real mulTwoX = 0.5f;
  1615. if(TheGlobalData && TheGlobalData->m_useOverbright)
  1616. mulTwoX = 1.0f;
  1617. DX8Wrapper::_Get_D3D_Device8()->SetPixelShaderConstant(1, D3DXVECTOR4(mulTwoX, mulTwoX, mulTwoX, mulTwoX), 1);
  1618. #endif
  1619. } else {
  1620. DX8Wrapper::Set_Vertex_Shader(DX8_FVF_XYZNDUV1);
  1621. }
  1622. Int bNdx;
  1623. for (bNdx=0;bNdx<MAX_BUFFERS; bNdx++) {
  1624. if (m_curNumTreeIndices[bNdx]==0) {
  1625. break;
  1626. }
  1627. DX8Wrapper::Set_Index_Buffer(m_indexTree[bNdx],0);
  1628. DX8Wrapper::Set_Vertex_Buffer(m_vertexTree[bNdx]);
  1629. // Render the waving grass
  1630. DX8Wrapper::Apply_Render_State_Changes();
  1631. if (m_dwTreeVertexShader) {
  1632. DX8Wrapper::_Get_D3D_Device8()->SetVertexShader(m_dwTreeVertexShader);
  1633. DX8Wrapper::_Get_D3D_Device8()->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0);
  1634. DX8Wrapper::_Get_D3D_Device8()->SetTextureStageState(1, D3DTSS_TEXCOORDINDEX, 1);
  1635. DX8Wrapper::_Get_D3D_Device8()->SetTextureStageState(1, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE);
  1636. }
  1637. DX8Wrapper::Draw_Triangles( 0, m_curNumTreeIndices[bNdx]/3, 0, m_curNumTreeVertices[bNdx]);
  1638. }
  1639. DX8Wrapper::Set_Vertex_Shader(DX8_FVF_XYZNDUV1);
  1640. DX8Wrapper::Set_Pixel_Shader(NULL);
  1641. DX8Wrapper::Invalidate_Cached_Render_States(); //code above mucks around with W3D states so make sure we reset
  1642. }
  1643. //-------------------------------------------------------------------------------------------------
  1644. ///< Start the toppling process by giving a force vector
  1645. //-------------------------------------------------------------------------------------------------
  1646. void W3DTreeBuffer::applyTopplingForce( TTree *tree, const Coord3D* toppleDirection, Real toppleSpeed,
  1647. UnsignedInt options )
  1648. {
  1649. if (tree->m_toppleState != TOPPLE_UPRIGHT) {
  1650. return;
  1651. }
  1652. const W3DTreeDrawModuleData* d = m_treeTypes[tree->treeType].m_data;
  1653. // Having a low toppleSpeed is BAD. In particular, if the toppleSpeed is exactly 0, the
  1654. // tree will stay upright forever, frozen in place (because the sway update is dead)
  1655. // but never dying
  1656. if ( toppleSpeed < d->m_minimumToppleSpeed )
  1657. {
  1658. toppleSpeed = d->m_minimumToppleSpeed;
  1659. }
  1660. tree->m_toppleDirection = *toppleDirection;
  1661. tree->m_toppleDirection.normalize();
  1662. tree->m_angularAccumulation = 0;
  1663. tree->m_angularVelocity = toppleSpeed * d->m_initialVelocityPercent;
  1664. tree->m_angularAcceleration = toppleSpeed * d->m_initialAccelPercent;
  1665. tree->m_toppleState = TOPPLE_FALLING;
  1666. tree->m_options = options;
  1667. Coord3D pos;
  1668. pos.set(tree->location.X, tree->location.Y, tree->location.Z);
  1669. FXList::doFXPos(d->m_toppleFX, &pos);
  1670. m_anyPushChanged = true;
  1671. tree->m_mtx.Make_Identity();
  1672. tree->m_mtx.Set_Translation(tree->location);
  1673. }
  1674. // this is our "bounce" limit -- slightly less that 90 degrees, to account for slop.
  1675. static const Real ANGULAR_LIMIT = PI/2 - PI/64;
  1676. //-------------------------------------------------------------------------------------------------
  1677. ///< Keep track of rotational fall distance, bounce and/or stop when needed.
  1678. //-------------------------------------------------------------------------------------------------
  1679. void W3DTreeBuffer::updateTopplingTree(TTree *tree)
  1680. {
  1681. //DLOG(Debug::Format("updating W3DTreeBuffer %08lx\n",this));
  1682. DEBUG_ASSERTCRASH(tree->m_toppleState != TOPPLE_UPRIGHT, ("hmm, we should be sleeping here"));
  1683. if ( (tree->m_toppleState == TOPPLE_UPRIGHT) || (tree->m_toppleState == TOPPLE_DOWN) )
  1684. return;
  1685. const W3DTreeDrawModuleData* d = m_treeTypes[tree->treeType].m_data;
  1686. Int localPlayerIndex = ThePlayerList ? ThePlayerList->getLocalPlayer()->getPlayerIndex() : 0;
  1687. Coord3D pos;
  1688. pos.set(tree->location.X, tree->location.Y, tree->location.Z);
  1689. ObjectShroudStatus ss = ThePartitionManager->getPropShroudStatusForPlayer(localPlayerIndex, &pos);
  1690. if (ss==OBJECTSHROUD_FOGGED) {
  1691. // Don't update fogged trees. [8/11/2003]
  1692. tree->m_toppleState = TOPPLE_FOGGED;
  1693. return;
  1694. } else if (tree->m_toppleState == TOPPLE_FOGGED) {
  1695. // was fogged, now isn't.
  1696. tree->m_angularVelocity = 0;
  1697. tree->m_toppleState = TOPPLE_DOWN;
  1698. tree->m_mtx.In_Place_Pre_Rotate_X(-ANGULAR_LIMIT * tree->m_toppleDirection.y);
  1699. tree->m_mtx.In_Place_Pre_Rotate_Y(ANGULAR_LIMIT * tree->m_toppleDirection.x);
  1700. if (d->m_killWhenToppled) {
  1701. // If got killed in the fog, just remove. jba [8/11/2003]
  1702. tree->m_sinkFramesLeft = 0;
  1703. }
  1704. return;
  1705. }
  1706. const Real VELOCITY_BOUNCE_LIMIT = 0.01f; // if the velocity after a bounce will be this or lower, just stop at zero
  1707. const Real VELOCITY_BOUNCE_SOUND_LIMIT = 0.03f; // and if this low, then skip the bounce sound
  1708. Real curVelToUse = tree->m_angularVelocity;
  1709. if (tree->m_angularAccumulation + curVelToUse > ANGULAR_LIMIT)
  1710. curVelToUse = ANGULAR_LIMIT - tree->m_angularAccumulation;
  1711. tree->m_mtx.In_Place_Pre_Rotate_X(-curVelToUse * tree->m_toppleDirection.y);
  1712. tree->m_mtx.In_Place_Pre_Rotate_Y(curVelToUse * tree->m_toppleDirection.x);
  1713. tree->m_angularAccumulation += curVelToUse;
  1714. if ((tree->m_angularAccumulation >= ANGULAR_LIMIT) && (tree->m_angularVelocity > 0))
  1715. {
  1716. // Hit so either bounce or stop if too little remaining velocity.
  1717. tree->m_angularVelocity *= -d->m_bounceVelocityPercent;
  1718. if( BitTest( tree->m_options, W3D_TOPPLE_OPTIONS_NO_BOUNCE ) == TRUE ||
  1719. fabs(tree->m_angularVelocity) < VELOCITY_BOUNCE_LIMIT )
  1720. {
  1721. // too slow, just stop
  1722. tree->m_angularVelocity = 0;
  1723. tree->m_toppleState = TOPPLE_DOWN;
  1724. if (d->m_killWhenToppled) {
  1725. tree->m_sinkFramesLeft = d->m_sinkFrames;
  1726. }
  1727. }
  1728. else if( fabs(tree->m_angularVelocity) >= VELOCITY_BOUNCE_SOUND_LIMIT )
  1729. {
  1730. // fast enough bounce to warrant the bounce fx
  1731. if( BitTest( tree->m_options, W3D_TOPPLE_OPTIONS_NO_FX ) == FALSE ) {
  1732. Vector3 loc(0, 0, 3*TREE_RADIUS_APPROX); // Kinda towards the top of the tree. jba. [7/11/2003]
  1733. Vector3 xloc;
  1734. tree->m_mtx.Transform_Vector(tree->m_mtx, loc, &xloc);
  1735. Coord3D pos;
  1736. pos.set(xloc.X, xloc.Y, xloc.Z);
  1737. FXList::doFXPos(d->m_bounceFX, &pos);
  1738. }
  1739. }
  1740. }
  1741. else
  1742. {
  1743. tree->m_angularVelocity += tree->m_angularAcceleration;
  1744. }
  1745. }
  1746. // ------------------------------------------------------------------------------------------------
  1747. /** CRC */
  1748. // ------------------------------------------------------------------------------------------------
  1749. void W3DTreeBuffer::crc( Xfer *xfer )
  1750. {
  1751. // empty. jba [8/11/2003]
  1752. } // end CRC
  1753. // ------------------------------------------------------------------------------------------------
  1754. /** Xfer
  1755. * Version Info:
  1756. * 1: Initial version */
  1757. // ------------------------------------------------------------------------------------------------
  1758. void W3DTreeBuffer::xfer( Xfer *xfer )
  1759. {
  1760. // version
  1761. XferVersion currentVersion = 1;
  1762. XferVersion version = currentVersion;
  1763. xfer->xferVersion( &version, currentVersion );
  1764. Int i;
  1765. Int numTrees = m_numTrees;
  1766. xfer->xferInt(&numTrees);
  1767. if (xfer->getXferMode() == XFER_LOAD) {
  1768. m_numTrees = 0;
  1769. for (i=0; i<PARTITION_WIDTH_HEIGHT*PARTITION_WIDTH_HEIGHT; i++) {
  1770. m_areaPartition[i] = END_OF_PARTITION;
  1771. }
  1772. }
  1773. // Save trees. [8/11/2003]
  1774. for (i=0; i<numTrees; i++) {
  1775. TTree tree;
  1776. memset(&tree, 0, sizeof(tree));
  1777. AsciiString modelName;
  1778. AsciiString modelTexture;
  1779. Int treeType = DELETED_TREE_TYPE;
  1780. if (xfer->getXferMode() != XFER_LOAD) {
  1781. tree = m_trees[i];
  1782. treeType = m_trees[i].treeType;
  1783. if (treeType != DELETED_TREE_TYPE) {
  1784. modelName = m_treeTypes[treeType].m_data->m_modelName;
  1785. modelTexture = m_treeTypes[treeType].m_data->m_textureName;
  1786. }
  1787. }
  1788. xfer->xferAsciiString(&modelName);
  1789. xfer->xferAsciiString(&modelTexture);
  1790. if (xfer->getXferMode() == XFER_LOAD) {
  1791. Int j;
  1792. for (j=0; j<m_numTreeTypes; j++) {
  1793. if (m_treeTypes[j].m_data->m_modelName.compareNoCase(modelName)==0 &&
  1794. m_treeTypes[j].m_data->m_textureName.compareNoCase(modelTexture)==0) {
  1795. treeType = j;
  1796. break;
  1797. }
  1798. }
  1799. }
  1800. xfer->xferReal(&tree.location.X);
  1801. xfer->xferReal(&tree.location.Y);
  1802. xfer->xferReal(&tree.location.Z);
  1803. xfer->xferReal(&tree.scale); ///< Scale at location.
  1804. xfer->xferReal(&tree.sin); ///< Sine of the rotation angle at location.
  1805. xfer->xferReal(&tree.cos); ///< Cosine of the rotation angle at location.
  1806. xfer->xferDrawableID(&tree.drawableID); ///< Drawable this tree corresponds to.
  1807. // Topple parameters. [7/7/2003]
  1808. xfer->xferReal(&tree.m_angularVelocity); ///< Velocity in degrees per frame (or is it radians per frame?)
  1809. xfer->xferReal(&tree.m_angularAcceleration); ///< Acceleration angularVelocity is increasing
  1810. xfer->xferCoord3D(&tree.m_toppleDirection); ///< Z-less direction we are toppling
  1811. xfer->xferUser(&tree.m_toppleState, sizeof(tree.m_toppleState)); ///< Stage this module is in.
  1812. xfer->xferReal(&tree.m_angularAccumulation); ///< How much have I rotated so I know when to bounce.
  1813. xfer->xferUnsignedInt(&tree.m_options); ///< topple options
  1814. xfer->xferMatrix3D(&tree.m_mtx);
  1815. xfer->xferUnsignedInt(&tree.m_sinkFramesLeft); ///< Toppled trees sink into the terrain & disappear, how many frames left.
  1816. if (xfer->getXferMode() == XFER_LOAD && treeType != DELETED_TREE_TYPE && treeType < m_numTreeTypes) {
  1817. Coord3D pos;
  1818. pos.set(tree.location.X, tree.location.Y, tree.location.Z);
  1819. Real angle = 0;
  1820. addTree(tree.drawableID, pos, tree.scale, angle, 0, m_treeTypes[treeType].m_data);
  1821. if (m_numTrees) {
  1822. TTree *curTree = &m_trees[m_numTrees-1];
  1823. curTree->m_angularAcceleration = tree.m_angularAcceleration;
  1824. curTree->m_angularVelocity = tree.m_angularVelocity;
  1825. curTree->m_toppleDirection = tree.m_toppleDirection;
  1826. curTree->m_toppleState = tree.m_toppleState;
  1827. curTree->m_options = tree.m_options;
  1828. curTree->m_mtx = tree.m_mtx;
  1829. curTree->m_sinkFramesLeft = tree.m_sinkFramesLeft;
  1830. }
  1831. }
  1832. }
  1833. } // end xfer
  1834. // ------------------------------------------------------------------------------------------------
  1835. /** Load post process */
  1836. // ------------------------------------------------------------------------------------------------
  1837. void W3DTreeBuffer::loadPostProcess( void )
  1838. {
  1839. // empty. jba [8/11/2003]
  1840. } // end loadPostProcess