W3DTreeBuffer.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694
  1. /*
  2. ** Command & Conquer Generals(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. // Includes
  44. //-----------------------------------------------------------------------------
  45. #include "W3DDevice/GameClient/W3DTreeBuffer.h"
  46. #include <stdio.h>
  47. #include <string.h>
  48. #include <assetmgr.h>
  49. #include <texture.h>
  50. #include "common/GlobalData.h"
  51. #include "GameClient/ClientRandomValue.h"
  52. #include "W3DDevice/GameClient/TerrainTex.h"
  53. #include "W3DDevice/GameClient/HeightMap.h"
  54. #include "W3DDevice/GameClient/W3DDynamicLight.h"
  55. #include "WW3D2/Camera.h"
  56. #include "WW3D2/DX8Wrapper.h"
  57. #include "WW3D2/DX8Renderer.h"
  58. #include "WW3D2/Mesh.h"
  59. #include "WW3D2/MeshMdl.h"
  60. //-----------------------------------------------------------------------------
  61. // Private Data
  62. //-----------------------------------------------------------------------------
  63. // A W3D shader that does alpha, texturing, tests zbuffer, doesn't update zbuffer.
  64. #define SC_ALPHA_DETAIL ( SHADE_CNST(ShaderClass::PASS_LEQUAL, ShaderClass::DEPTH_WRITE_DISABLE, ShaderClass::COLOR_WRITE_ENABLE, ShaderClass::SRCBLEND_SRC_ALPHA, \
  65. ShaderClass::DSTBLEND_ONE_MINUS_SRC_ALPHA, ShaderClass::FOG_DISABLE, ShaderClass::GRADIENT_MODULATE, ShaderClass::SECONDARY_GRADIENT_DISABLE, ShaderClass::TEXTURING_ENABLE, \
  66. ShaderClass::ALPHATEST_DISABLE, ShaderClass::CULL_MODE_DISABLE, \
  67. ShaderClass::DETAILCOLOR_DISABLE, ShaderClass::DETAILALPHA_DISABLE) )
  68. static ShaderClass detailAlphaShader(SC_ALPHA_DETAIL);
  69. /*
  70. #define SC_ALPHA_MIRROR ( SHADE_CNST(ShaderClass::PASS_LEQUAL, ShaderClass::DEPTH_WRITE_DISABLE, ShaderClass::COLOR_WRITE_ENABLE, ShaderClass::SRCBLEND_SRC_ALPHA, \
  71. ShaderClass::DSTBLEND_ONE_MINUS_SRC_ALPHA, ShaderClass::FOG_DISABLE, ShaderClass::GRADIENT_MODULATE, ShaderClass::SECONDARY_GRADIENT_DISABLE, ShaderClass::TEXTURING_ENABLE, \
  72. ShaderClass::DETAILCOLOR_DISABLE, ShaderClass::DETAILALPHA_DISABLE, ShaderClass::ALPHATEST_DISABLE, ShaderClass::CULL_MODE_DISABLE, \
  73. ShaderClass::DETAILCOLOR_DISABLE, ShaderClass::DETAILALPHA_DISABLE) )
  74. static ShaderClass mirrorAlphaShader(SC_ALPHA_DETAIL);
  75. // ShaderClass::PASS_ALWAYS,
  76. #define SC_ALPHA_2D ( SHADE_CNST(PASS_ALWAYS, DEPTH_WRITE_DISABLE, COLOR_WRITE_ENABLE, \
  77. SRCBLEND_SRC_ALPHA, DSTBLEND_ONE_MINUS_SRC_ALPHA, FOG_DISABLE, GRADIENT_DISABLE, \
  78. SECONDARY_GRADIENT_DISABLE, TEXTURING_ENABLE, DETAILCOLOR_DISABLE, DETAILALPHA_DISABLE, \
  79. ALPHATEST_DISABLE, CULL_MODE_ENABLE, DETAILCOLOR_DISABLE, DETAILALPHA_DISABLE) )
  80. ShaderClass ShaderClass::_PresetAlpha2DShader(SC_ALPHA_2D);
  81. */
  82. //-----------------------------------------------------------------------------
  83. // Private Functions
  84. //-----------------------------------------------------------------------------
  85. //=============================================================================
  86. // W3DTreeBuffer::cull
  87. //=============================================================================
  88. /** Culls the trees, marking the visible flag. If a tree becomes visible, it sets
  89. it's sortKey */
  90. //=============================================================================
  91. void W3DTreeBuffer::cull(CameraClass * camera)
  92. {
  93. Int curTree;
  94. m_anythingChanged = false;
  95. // Calulate the vector direction that the camera is looking at.
  96. Matrix3D camera_matrix = camera->Get_Transform();
  97. float zmod = -1;
  98. float x = zmod * camera_matrix[0][2] ;
  99. float y = zmod * camera_matrix[1][2] ;
  100. float z = zmod * camera_matrix[2][2] ;
  101. m_cameraLookAtVector.Set(x,y,z);
  102. for (curTree=0; curTree<m_numTrees; curTree++) {
  103. Bool doKey = false; // We calculate the key when a tree becomes visible.
  104. Bool visible = !camera->Cull_Sphere(m_trees[curTree].bounds);
  105. if (visible!=m_trees[curTree].visible) {
  106. m_trees[curTree].visible=visible;
  107. m_anythingChanged = true;
  108. if (visible) {
  109. doKey = true;
  110. }
  111. }
  112. // Also calculate sort key if a tree is visible, and the view changed setting m_updateAllKeys to true.
  113. if (doKey || (visible&&m_updateAllKeys)) {
  114. // The sort key is essentially the distance of location in the direction of the
  115. // camera look at.
  116. m_trees[curTree].sortKey = Vector3::Dot_Product(m_trees[curTree].location, m_cameraLookAtVector);
  117. }
  118. }
  119. m_updateAllKeys = false;
  120. }
  121. //=============================================================================
  122. // W3DTreeBuffer::cullMirror
  123. //=============================================================================
  124. /** Culls the trees, marking the visible flag for the mirror view. Unlike cull(),
  125. doesn't update anything except the visible flag. */
  126. //=============================================================================
  127. void W3DTreeBuffer::cullMirror(CameraClass * camera)
  128. {
  129. Int curTree;
  130. m_anythingChanged = false;
  131. for (curTree=0; curTree<m_numTrees; curTree++) {
  132. if (!m_trees[curTree].mirrorVisible) {
  133. if (m_trees[curTree].visible) {
  134. m_anythingChanged = true;
  135. }
  136. m_trees[curTree].visible = false;
  137. continue;
  138. }
  139. Bool visible = !camera->Cull_Sphere(m_trees[curTree].bounds);
  140. m_trees[curTree].visible=visible;
  141. }
  142. }
  143. //=============================================================================
  144. // W3DTreeBuffer::sort
  145. //=============================================================================
  146. /** Sorts the trees. Does num_iterations of a bubble sort. This is good because
  147. it ends immediately if the trees are already sorted (which is most of the time)
  148. and will perform a fixed amount of work each frame until it becomes sorted. */
  149. //=============================================================================
  150. void W3DTreeBuffer::sort(Int numIterations)
  151. {
  152. // sort in descending order.
  153. Int iter;
  154. Bool swap = false;
  155. for (iter = 0; iter<numIterations; iter++) {
  156. Int cur = 0;
  157. // Note - only sorts the visible trees.
  158. while (cur<m_numTrees-iter && !m_trees[cur].visible) {
  159. cur++;
  160. }
  161. Int i;
  162. for (i=cur+1; i<m_numTrees-iter; i++) {
  163. if (m_trees[i].visible) {
  164. if (m_trees[cur].sortKey > m_trees[i].sortKey) {
  165. TTree tmp = m_trees[cur];
  166. m_trees[cur] = m_trees[i];
  167. m_trees[i] = tmp;
  168. swap = true;
  169. }
  170. cur = i;
  171. }
  172. }
  173. if (!swap) {
  174. return;
  175. }
  176. m_anythingChanged = true;
  177. }
  178. }
  179. //=============================================================================
  180. // W3DTreeBuffer::doLighting
  181. //=============================================================================
  182. /** Calculates the diffuse lighting as affected by dynamic lighting. */
  183. //=============================================================================
  184. Int W3DTreeBuffer::doLighting(Vector3 *loc, Real r, Real g, Real b, SphereClass &bounds, RefRenderObjListIterator *pDynamicLightsIterator)
  185. {
  186. if (pDynamicLightsIterator == NULL) {
  187. return(REAL_TO_INT(b) | (REAL_TO_INT(g) << 8) | (REAL_TO_INT(r) << 16) | (255 << 24));
  188. }
  189. Real shadeR, shadeG, shadeB;
  190. shadeR = r;
  191. shadeG = g;
  192. shadeB = b;
  193. Bool didLight = false;
  194. for (pDynamicLightsIterator->First(); !pDynamicLightsIterator->Is_Done(); pDynamicLightsIterator->Next())
  195. {
  196. W3DDynamicLight *pLight = (W3DDynamicLight*)pDynamicLightsIterator->Peek_Obj();
  197. if (!pLight->isEnabled()) {
  198. continue; // he is turned off.
  199. }
  200. if (CollisionMath::Overlap_Test(bounds, pLight->Get_Bounding_Sphere()) == CollisionMath::OUTSIDE) {
  201. continue; // this tree is outside of the light's influence.
  202. }
  203. Vector3 lightDirection = *loc;
  204. Real factor;
  205. switch(pLight->Get_Type()) {
  206. case LightClass::POINT:
  207. case LightClass::SPOT: {
  208. Vector3 lightLoc = pLight->Get_Position();
  209. lightDirection -= lightLoc;
  210. double range, midRange;
  211. pLight->Get_Far_Attenuation_Range(midRange, range);
  212. Real dist = lightDirection.Length();
  213. if (dist >= range) continue;
  214. if (midRange < 0.1) continue;
  215. factor = 1.0f - (dist - midRange) / (range - midRange);
  216. factor = WWMath::Clamp(factor,0.0f,1.0f);
  217. }
  218. break;
  219. case LightClass::DIRECTIONAL:
  220. pLight->Get_Spot_Direction(lightDirection);
  221. factor = 1.0;
  222. break;
  223. };
  224. Real shade = 0.5f * factor; // Assume adjustment for diffuse.
  225. Vector3 vDiffuse;
  226. pLight->Get_Diffuse(&vDiffuse);
  227. Vector3 ambient;
  228. pLight->Get_Ambient(&ambient);
  229. if (shade > 1.0) shade = 1.0;
  230. if(shade < 0.0f) shade = 0.0f;
  231. shadeR += shade*vDiffuse.X;
  232. shadeG += shade*vDiffuse.Y;
  233. shadeB += shade*vDiffuse.Z;
  234. shadeR += factor*ambient.X;
  235. shadeG += factor*ambient.Y;
  236. shadeB += factor*ambient.Z;
  237. didLight = true;
  238. }
  239. if (!didLight) {
  240. return(REAL_TO_INT(b) | (REAL_TO_INT(g) << 8) | (REAL_TO_INT(r) << 16) | (255 << 24));
  241. }
  242. if (shadeR > 1.0) shadeR = 1.0;
  243. if(shadeR < 0.0f) shadeR = 0.0f;
  244. if (shadeG > 1.0) shadeG = 1.0;
  245. if(shadeG < 0.0f) shadeG = 0.0f;
  246. if (shadeB > 1.0) shadeB = 1.0;
  247. if(shadeB < 0.0f) shadeB = 0.0f;
  248. shadeR*=255.0f;
  249. shadeG*=255.0f;
  250. shadeB*=255.0f;
  251. return(REAL_TO_INT(shadeB) | (REAL_TO_INT(shadeG) << 8) | (REAL_TO_INT(shadeR) << 16) | (255 << 24));
  252. }
  253. //=============================================================================
  254. // W3DTreeBuffer::loadTreesInVertexAndIndexBuffers
  255. //=============================================================================
  256. /** Loads the trees into the vertex buffer for drawing. */
  257. //=============================================================================
  258. void W3DTreeBuffer::loadTreesInVertexAndIndexBuffers(RefRenderObjListIterator *pDynamicLightsIterator)
  259. {
  260. if (!m_indexTree || !m_vertexTree || !m_initialized) {
  261. return;
  262. }
  263. if (!m_anythingChanged) {
  264. //return;
  265. }
  266. m_curNumTreeVertices = 0;
  267. m_curNumTreeIndices = 0;
  268. VertexFormatXYZDUV1 *vb;
  269. UnsignedShort *ib;
  270. // Lock the buffers.
  271. DX8IndexBufferClass::WriteLockClass lockIdxBuffer(m_indexTree);
  272. DX8VertexBufferClass::WriteLockClass lockVtxBuffer(m_vertexTree);
  273. vb=(VertexFormatXYZDUV1*)lockVtxBuffer.Get_Vertex_Array();
  274. ib = lockIdxBuffer.Get_Index_Array();
  275. // Add to the index buffer & vertex buffer.
  276. Vector2 lookAtVector(m_cameraLookAtVector.X, m_cameraLookAtVector.Y);
  277. lookAtVector.Normalize();
  278. // We draw from back to front, so we put the indexes in the buffer
  279. // from back to front.
  280. UnsignedShort *curIb = ib+MAX_TREE_INDEX;
  281. VertexFormatXYZDUV1 *curVb = vb;
  282. Int curTree;
  283. // Calculate a static lighting value to use for all the trees.
  284. Real shadeR, shadeG, shadeB;
  285. shadeR = TheGlobalData->m_terrainAmbient[0].red;
  286. shadeG = TheGlobalData->m_terrainAmbient[0].green;
  287. shadeB = TheGlobalData->m_terrainAmbient[0].blue;
  288. shadeR += TheGlobalData->m_terrainDiffuse[0].red;
  289. shadeG += TheGlobalData->m_terrainDiffuse[0].green;
  290. shadeB += TheGlobalData->m_terrainDiffuse[0].blue;
  291. if (shadeR>1.0f) shadeR=1.0f;
  292. if (shadeG>1.0f) shadeG=1.0f;
  293. if (shadeB>1.0f) shadeB=1.0f;
  294. shadeR*=255.0f;
  295. shadeG*=255.0f;
  296. shadeB*=255.0f;
  297. for (curTree=0; curTree<m_numTrees; curTree++) {
  298. if (!m_trees[curTree].visible) continue;
  299. Real scale = m_trees[curTree].scale;
  300. Vector3 loc = m_trees[curTree].location;
  301. Int type = m_trees[curTree].treeType;
  302. Real theSin = m_trees[curTree].sin;
  303. Real theCos = m_trees[curTree].cos;
  304. if (type<0 || m_typeMesh[type] == 0) {
  305. type = 0;
  306. }
  307. Bool doVertexLighting = false;
  308. #if 0 // no dynamic lighting.
  309. for (pDynamicLightsIterator->First(); !pDynamicLightsIterator->Is_Done(); pDynamicLightsIterator->Next())
  310. {
  311. W3DDynamicLight *pLight = (W3DDynamicLight*)pDynamicLightsIterator->Peek_Obj();
  312. if (!pLight->isEnabled()) {
  313. continue; // he is turned off.
  314. }
  315. if (CollisionMath::Overlap_Test(m_trees[curTree].bounds, pLight->Get_Bounding_Sphere()) == CollisionMath::OUTSIDE) {
  316. continue; // this tree is outside of the light's influence.
  317. }
  318. doVertexLighting = true;
  319. }
  320. #endif
  321. Int diffuse = 0;
  322. if (!doVertexLighting) {
  323. diffuse = doLighting(&loc, shadeR, shadeG, shadeB, m_trees[curTree].bounds, NULL);
  324. }
  325. Real typeOffset = type*0.5;
  326. Int startVertex = m_curNumTreeVertices;
  327. Int i, j;
  328. Int numVertex = m_typeMesh[type]->Peek_Model()->Get_Vertex_Count();
  329. Vector3 *pVert = m_typeMesh[type]->Peek_Model()->Get_Vertex_Array();
  330. // If we happen to have too many trees, stop.
  331. if (m_curNumTreeVertices+numVertex+2>= MAX_TREE_VERTEX) {
  332. break;
  333. }
  334. Int numIndex = m_typeMesh[type]->Get_Model()->Get_Polygon_Count();
  335. const Vector3i *pPoly = m_typeMesh[type]->Get_Model()->Get_Polygon_Array();
  336. if (m_curNumTreeIndices+3*numIndex+6 >= MAX_TREE_INDEX) {
  337. break;
  338. }
  339. const Vector2*uvs=m_typeMesh[type]->Get_Model()->Get_UV_Array_By_Index(0);
  340. // If we are doing reduced resolution terrain, do reduced
  341. // poly trees.
  342. Bool doPanel = (TheGlobalData->m_useHalfHeightMap || TheGlobalData->m_stretchTerrain);
  343. if (doPanel) {
  344. if (m_trees[curTree].rotates) {
  345. theSin = -lookAtVector.X;
  346. theCos = lookAtVector.Y;
  347. }
  348. // panel start is index offset, there are 3 index per triangle.
  349. if (m_trees[curTree].panelStart/3 + 2 > numIndex) {
  350. continue; // not enought polygons for the offset. jba.
  351. }
  352. for (j=0; j<6; j++) {
  353. i = ((Int *)pPoly)[j+m_trees[curTree].panelStart];
  354. if (m_curNumTreeVertices >= MAX_TREE_VERTEX)
  355. break;
  356. // Update the uv values. The W3D models each have their own texture, and
  357. // we use one texture with all images in one, so we have to change the uvs to
  358. // match.
  359. Real U, V;
  360. if (type==SHRUB) {
  361. // shrub texture is tucked in the corner
  362. U = ((512-64)+uvs[i].U*64.0f)/512.0f;
  363. V = ((256-64)+uvs[i].V*64.0f)/256.0f;
  364. } else if (type==FENCE) {
  365. U = uvs[i].U*0.5f;
  366. V = 1.0f + uvs[i].V;
  367. } else {
  368. U = typeOffset+uvs[i].U*0.5f;
  369. V = uvs[i].V;
  370. }
  371. curVb->u1 = U;
  372. curVb->v1 = V/2.0;
  373. Vector3 vLoc;
  374. vLoc.X = pVert[i].X*scale*theCos - pVert[i].Z*scale*theSin;
  375. vLoc.Y = pVert[i].Z*scale*theCos + pVert[i].X*scale*theSin;
  376. vLoc.X += loc.X;
  377. vLoc.Y += loc.Y;
  378. vLoc.Z = loc.Z + pVert[i].Y*scale; // In W3D z is up, in 3dMax y is up.
  379. curVb->x = vLoc.X;
  380. curVb->y = vLoc.Y;
  381. curVb->z = vLoc.Z;
  382. if (doVertexLighting) {
  383. curVb->diffuse = doLighting(&vLoc, shadeR, shadeG, shadeB, m_trees[curTree].bounds, pDynamicLightsIterator);
  384. } else {
  385. curVb->diffuse = diffuse;
  386. }
  387. curVb++;
  388. m_curNumTreeVertices++;
  389. }
  390. for (i=0; i<6; i++) {
  391. if (m_curNumTreeIndices+4 > MAX_TREE_INDEX)
  392. break;
  393. curIb--;
  394. *curIb = startVertex + i;
  395. m_curNumTreeIndices++;
  396. }
  397. } else {
  398. for (i=0; i<numVertex; i++) {
  399. if (m_curNumTreeVertices >= MAX_TREE_VERTEX)
  400. break;
  401. // Update the uv values. The W3D models each have their own texture, and
  402. // we use one texture with all images in one, so we have to change the uvs to
  403. // match.
  404. Real U, V;
  405. if (type==SHRUB) {
  406. // shrub texture is tucked in the corner
  407. U = ((512-64)+uvs[i].U*64.0f)/512.0f;
  408. V = ((256-64)+uvs[i].V*64.0f)/256.0f;
  409. } else if (type==FENCE) {
  410. U = uvs[i].U*0.5f;
  411. V = 1.0f + uvs[i].V;
  412. } else {
  413. U = typeOffset+uvs[i].U*0.5f;
  414. V = uvs[i].V;
  415. }
  416. curVb->u1 = U;
  417. curVb->v1 = V/2.0;
  418. Vector3 vLoc;
  419. vLoc.X = pVert[i].X*scale*theCos - pVert[i].Z*scale*theSin;
  420. vLoc.Y = pVert[i].Z*scale*theCos + pVert[i].X*scale*theSin;
  421. vLoc.X += loc.X;
  422. vLoc.Y += loc.Y;
  423. vLoc.Z = loc.Z + pVert[i].Y*scale; // In W3D z is up, in 3dMax y is up.
  424. curVb->x = vLoc.X;
  425. curVb->y = vLoc.Y;
  426. curVb->z = vLoc.Z;
  427. if (doVertexLighting) {
  428. curVb->diffuse = doLighting(&vLoc, shadeR, shadeG, shadeB, m_trees[curTree].bounds, pDynamicLightsIterator);
  429. } else {
  430. curVb->diffuse = diffuse;
  431. }
  432. curVb++;
  433. m_curNumTreeVertices++;
  434. }
  435. for (i=0; i<numIndex; i++) {
  436. if (m_curNumTreeIndices+4 > MAX_TREE_INDEX)
  437. break;
  438. curIb-=3;
  439. *curIb++ = startVertex + pPoly[i].I;
  440. *curIb++ = startVertex + pPoly[i].J;
  441. *curIb++ = startVertex + pPoly[i].K;
  442. curIb-=3;
  443. m_curNumTreeIndices+=3;
  444. }
  445. }
  446. }
  447. m_curTreeIndexOffset = curIb - ib;
  448. }
  449. //-----------------------------------------------------------------------------
  450. // Public Functions
  451. //-----------------------------------------------------------------------------
  452. //=============================================================================
  453. // W3DTreeBuffer::~W3DTreeBuffer
  454. //=============================================================================
  455. /** Destructor. Releases w3d assets. */
  456. //=============================================================================
  457. W3DTreeBuffer::~W3DTreeBuffer(void)
  458. {
  459. freeTreeBuffers();
  460. REF_PTR_RELEASE(m_treeTexture);
  461. Int i;
  462. for (i=0; i<MAX_TYPES; i++) {
  463. REF_PTR_RELEASE(m_typeMesh[i]);
  464. }
  465. }
  466. //=============================================================================
  467. // W3DTreeBuffer::W3DTreeBuffer
  468. //=============================================================================
  469. /** Constructor. Sets m_initialized to true if it finds the w3d models it needs
  470. for the trees. */
  471. //=============================================================================
  472. W3DTreeBuffer::W3DTreeBuffer(void)
  473. {
  474. m_initialized = false;
  475. ///@toto - reactivate this optimization if useful. jba.
  476. return;
  477. m_vertexTree = NULL;
  478. m_indexTree = NULL;
  479. m_treeTexture = NULL;
  480. m_curNumTreeVertices=0;
  481. m_curNumTreeIndices=0;
  482. clearAllTrees();
  483. allocateTreeBuffers();
  484. Int i;
  485. for (i=0; i<MAX_TYPES; i++) {
  486. m_typeMesh[i] = 0;
  487. }
  488. if (WW3DAssetManager::Get_Instance()==NULL)
  489. return; // WorldBuilderTool doesn't initialize the asset manager. jba.
  490. m_treeTexture = NEW_REF(TextureClass, ("trees.tga"));
  491. m_treeTexture->Set_U_Addr_Mode(TextureClass::TEXTURE_ADDRESS_CLAMP);
  492. m_treeTexture->Set_V_Addr_Mode(TextureClass::TEXTURE_ADDRESS_CLAMP);
  493. for (i=0; i<MAX_TYPES; i++) {
  494. switch(i) {
  495. case 0:
  496. m_typeMesh[i] = (MeshClass*)WW3DAssetManager::Get_Instance()->Create_Render_Obj("ALPINETREE.TREE 1" );
  497. break;
  498. case 1:
  499. m_typeMesh[i] = (MeshClass*)WW3DAssetManager::Get_Instance()->Create_Render_Obj("DECIDUOUS.TREE 1" );
  500. break;
  501. case 2:
  502. m_typeMesh[i] = (MeshClass*)WW3DAssetManager::Get_Instance()->Create_Render_Obj("SHRUB.TREE 1" );
  503. break;
  504. case 3:
  505. m_typeMesh[i] = (MeshClass*)WW3DAssetManager::Get_Instance()->Create_Render_Obj("FENCE.PLANE09" );
  506. break;
  507. }
  508. if (m_typeMesh[i] == NULL) continue;
  509. Int numVertex = m_typeMesh[i]->Peek_Model()->Get_Vertex_Count();
  510. Vector3 *pVert = m_typeMesh[i]->Peek_Model()->Get_Vertex_Array();
  511. const Matrix3D xfm = m_typeMesh[i]->Get_Transform();
  512. SphereClass bounds(pVert, numVertex);
  513. // Model is in y up format, so swap y and z.
  514. Real tmp;
  515. tmp = bounds.Center.Y;
  516. bounds.Center.Y = bounds.Center.Z;
  517. bounds.Center.Z = tmp;
  518. m_typeBounds[i] = bounds;
  519. }
  520. if (m_typeMesh[0] == NULL) {
  521. //DEBUG_LOG("!!!!!!!!!!!!*************** W3DTreeBuffer failed to initialize.\n");
  522. return; // didn't initialize.
  523. }
  524. m_initialized = true;
  525. }
  526. //=============================================================================
  527. // W3DTreeBuffer::freeTreeBuffers
  528. //=============================================================================
  529. /** Frees the index and vertex buffers. */
  530. //=============================================================================
  531. void W3DTreeBuffer::freeTreeBuffers(void)
  532. {
  533. REF_PTR_RELEASE(m_vertexTree);
  534. REF_PTR_RELEASE(m_indexTree);
  535. }
  536. //=============================================================================
  537. // W3DTreeBuffer::allocateTreeBuffers
  538. //=============================================================================
  539. /** Allocates the index and vertex buffers. */
  540. //=============================================================================
  541. void W3DTreeBuffer::allocateTreeBuffers(void)
  542. {
  543. m_vertexTree=NEW_REF(DX8VertexBufferClass,(DX8_FVF_XYZDUV1,MAX_TREE_VERTEX+4,DX8VertexBufferClass::USAGE_DYNAMIC));
  544. m_indexTree=NEW_REF(DX8IndexBufferClass,(2*MAX_TREE_INDEX+4, DX8IndexBufferClass::USAGE_DYNAMIC));
  545. m_curNumTreeVertices=0;
  546. m_curNumTreeIndices=0;
  547. }
  548. //=============================================================================
  549. // W3DTreeBuffer::clearAllTrees
  550. //=============================================================================
  551. /** Removes all trees. */
  552. //=============================================================================
  553. void W3DTreeBuffer::clearAllTrees(void)
  554. {
  555. m_numTrees=0;
  556. }
  557. //=============================================================================
  558. // W3DTreeBuffer::addTree
  559. //=============================================================================
  560. /** Adds a tree. Name is the W3D model name, supported models are
  561. ALPINE, DECIDUOUS and SHRUB. */
  562. //=============================================================================
  563. void W3DTreeBuffer::addTree(Coord3D loc, Real scale, Real angle, AsciiString name, Bool mirrorVisible)
  564. {
  565. if (m_numTrees >= MAX_TREES) {
  566. return;
  567. }
  568. if (!m_initialized) {
  569. return;
  570. }
  571. TTreeType treeType = ALPINE_TREE;
  572. if (!name.compare("DECIDUOUS")) {
  573. treeType = DECIDUOUS_TREE;
  574. } else if (!name.compare("SHRUB")) {
  575. treeType = SHRUB;
  576. } else if (!name.compare("FENCE")) {
  577. treeType = FENCE;
  578. }
  579. m_trees[m_numTrees].panelStart = 0;
  580. Real randomScale = GameClientRandomValueReal( 0.7f, 1.3f );
  581. if (treeType == FENCE) {
  582. // Fences don't randomly scale & orient
  583. m_trees[m_numTrees].sin = WWMath::Sin(angle);
  584. m_trees[m_numTrees].scale = scale;
  585. m_trees[m_numTrees].cos = WWMath::Cos(angle);
  586. m_trees[m_numTrees].rotates = false;
  587. m_trees[m_numTrees].panelStart = 48;
  588. } else {
  589. // Randomizes the scale and orientation of trees.
  590. m_trees[m_numTrees].sin = GameClientRandomValueReal( -1.0f, 1.0f );
  591. m_trees[m_numTrees].scale = scale*randomScale;
  592. m_trees[m_numTrees].cos = WWMath::Sqrt(1.0 - m_trees[m_numTrees].sin*m_trees[m_numTrees].sin);
  593. m_trees[m_numTrees].rotates = true;
  594. }
  595. m_trees[m_numTrees].location = Vector3(loc.x, loc.y, loc.z);
  596. m_trees[m_numTrees].treeType = treeType;
  597. // Translate the bounding sphere of the model.
  598. m_trees[m_numTrees].bounds = m_typeBounds[treeType];
  599. m_trees[m_numTrees].bounds.Center *= scale;
  600. m_trees[m_numTrees].bounds.Radius *= scale;
  601. m_trees[m_numTrees].bounds.Center += m_trees[m_numTrees].location;
  602. // Initially set it invisible. cull will update it's visiblity flag.
  603. m_trees[m_numTrees].visible = false;
  604. m_trees[m_numTrees].mirrorVisible = mirrorVisible;
  605. m_numTrees++;
  606. }
  607. //=============================================================================
  608. // W3DTreeBuffer::drawTrees
  609. //=============================================================================
  610. /** Draws the trees. Uses camera to cull. */
  611. //=============================================================================
  612. void W3DTreeBuffer::drawTrees(CameraClass * camera, RefRenderObjListIterator *pDynamicLightsIterator)
  613. {
  614. if (!m_isTerrainPass) {
  615. return;
  616. }
  617. m_isTerrainPass = false;
  618. if (ShaderClass::Is_Backface_Culling_Inverted()) {
  619. // Mirror inverts backface culling.
  620. cullMirror(camera);
  621. } else {
  622. // Normal draw.
  623. cull(camera);
  624. // Only sort once per frame.
  625. sort(SORT_ITERATIONS_PER_FRAME);
  626. }
  627. loadTreesInVertexAndIndexBuffers(pDynamicLightsIterator);
  628. if (m_curNumTreeIndices == 0) {
  629. return;
  630. }
  631. // Setup the vertex buffer, shader & texture.
  632. DX8Wrapper::Set_Index_Buffer(m_indexTree,0);
  633. DX8Wrapper::Set_Vertex_Buffer(m_vertexTree);
  634. DX8Wrapper::Set_Shader(detailAlphaShader);
  635. DX8Wrapper::Set_Texture(0,m_treeTexture);
  636. // Draw all the trees.
  637. DX8Wrapper::Draw_Triangles( m_curTreeIndexOffset, m_curNumTreeIndices/3, 0, m_curNumTreeVertices);
  638. }