W3DTerrainBackground.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810
  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: W3DTerrainBackground.cpp ////////////////////////////////////////////////
  24. //-----------------------------------------------------------------------------
  25. //
  26. // EA Pacific.
  27. //
  28. // Confidential Information
  29. // Copyright (C) 2003 - All Rights Reserved
  30. //
  31. //-----------------------------------------------------------------------------
  32. //
  33. // Project: RTS3
  34. //
  35. // File name: W3DTerrainBackground.cpp
  36. //
  37. // Created: John Ahlquist, March 2003
  38. //
  39. // Desc: Draw buffer to handle backup terrain at lower res.
  40. //
  41. //-----------------------------------------------------------------------------
  42. //-----------------------------------------------------------------------------
  43. // Includes
  44. //-----------------------------------------------------------------------------
  45. #include "W3DDevice/GameClient/W3DTerrainBackground.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/View.h"
  52. #include "W3DDevice/GameClient/TerrainTex.h"
  53. #include "W3DDevice/GameClient/HeightMap.h"
  54. #include "WW3D2/DX8Wrapper.h"
  55. #include "WW3D2/DX8Renderer.h"
  56. #include "WW3D2/Camera.h"
  57. #ifdef _INTERNAL
  58. // for occasional debugging...
  59. //#pragma optimize("", off)
  60. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  61. #endif
  62. //-----------------------------------------------------------------------------
  63. // Private Data
  64. //-----------------------------------------------------------------------------
  65. // A W3D shader that does alpha, texturing, tests zbuffer, doesn't update zbuffer.
  66. #define SC_DETAIL ( SHADE_CNST(ShaderClass::PASS_LEQUAL, ShaderClass::DEPTH_WRITE_ENABLE, ShaderClass::COLOR_WRITE_ENABLE, ShaderClass::SRCBLEND_ONE, \
  67. ShaderClass::DSTBLEND_ZERO, ShaderClass::FOG_DISABLE, ShaderClass::GRADIENT_MODULATE, ShaderClass::SECONDARY_GRADIENT_DISABLE, ShaderClass::TEXTURING_ENABLE, \
  68. ShaderClass::ALPHATEST_DISABLE, ShaderClass::CULL_MODE_DISABLE, \
  69. ShaderClass::DETAILCOLOR_DISABLE, ShaderClass::DETAILALPHA_DISABLE) )
  70. static ShaderClass detailShader(SC_DETAIL);
  71. const Int PIXELS_PER_GRID = 8; // default tex resolution allocated for each tile. jba. [3/24/2003]
  72. //-----------------------------------------------------------------------------
  73. // Private Functions
  74. //-----------------------------------------------------------------------------
  75. //=============================================================================
  76. // W3DTerrainBackground::loadTerrainInVertexAndIndexBuffers
  77. //=============================================================================
  78. /** Loads the terrain into the vertex buffer for drawing. */
  79. //=============================================================================
  80. void W3DTerrainBackground::setFlip(WorldHeightMap *htMap)
  81. {
  82. if (m_map==NULL) return;
  83. if (htMap) {
  84. REF_PTR_SET(m_map, htMap);
  85. }
  86. if (!m_initialized) {
  87. return;
  88. }
  89. setFlipRecursive(0, 0, m_width);
  90. }
  91. const Int STEP=4;
  92. //=============================================================================
  93. // W3DTerrainBackground::doPartialUpdate
  94. //=============================================================================
  95. /** Updates a partial block of vertices from [x0,y0 to x1,y1]
  96. The coordinates in partialRange are map cell coordinates, relative to the entire map.
  97. The vertex coordinates and texture coordinates, as well as static lighting are updated.
  98. */
  99. void W3DTerrainBackground::doPartialUpdate(const IRegion2D &partialRange, WorldHeightMap *htMap, Bool doTextures )
  100. {
  101. if (m_map==NULL) return;
  102. if (htMap) {
  103. REF_PTR_SET(m_map, htMap);
  104. }
  105. if (!m_initialized) {
  106. return;
  107. }
  108. doTesselatedUpdate(partialRange, htMap, doTextures);
  109. return;
  110. Int requiredVertexSize = (m_width+1) * (m_width+1) + 6;
  111. if (m_vertexTerrainSize<requiredVertexSize || m_vertexTerrain==NULL) {
  112. m_vertexTerrainSize = requiredVertexSize;
  113. REF_PTR_RELEASE(m_vertexTerrain);
  114. REF_PTR_RELEASE(m_indexTerrain);
  115. m_vertexTerrain=NEW_REF(DX8VertexBufferClass,(DX8_FVF_XYZDUV1,m_vertexTerrainSize+4,DX8VertexBufferClass::USAGE_DEFAULT));
  116. }
  117. Int requiredIndexSize = (m_width+1) * (m_width+1) + 6;
  118. if (m_indexTerrainSize<requiredIndexSize || m_indexTerrain==NULL) {
  119. m_indexTerrainSize = requiredIndexSize;
  120. REF_PTR_RELEASE(m_indexTerrain);
  121. m_indexTerrain=NEW_REF(DX8IndexBufferClass,(m_indexTerrainSize+4,DX8IndexBufferClass::USAGE_DEFAULT));
  122. }
  123. Int minX = m_xOrigin;
  124. Int minY = m_yOrigin;
  125. Int maxX = m_xOrigin + m_width;
  126. Int maxY = m_yOrigin + m_width;
  127. Int limitX = m_map->getXExtent()-1;
  128. Int limitY = m_map->getYExtent()-1;
  129. if (maxX>limitX) maxX = limitX;
  130. if (maxY>limitY) maxY = limitY;
  131. if (partialRange.lo.x > maxX) return;
  132. if (partialRange.lo.y > maxY) return;
  133. if (partialRange.hi.x < minX) return;
  134. if (partialRange.hi.y < minY) return;
  135. m_curNumTerrainVertices = 0;
  136. //m_curNumTerrainIndices = 0;
  137. VertexFormatXYZDUV2 *vb;
  138. UnsignedShort *ib;
  139. // Lock the buffer.
  140. DX8VertexBufferClass::WriteLockClass lockVtxBuffer(m_vertexTerrain);
  141. vb=(VertexFormatXYZDUV2*)lockVtxBuffer.Get_Vertex_Array();
  142. // Add to the vertex buffer.
  143. VertexFormatXYZDUV2 *curVb = vb;
  144. MinMaxAABoxClass bounds;
  145. bounds.Init_Empty();
  146. Int i, j;
  147. for (j=minY; j<=maxY; j+=STEP) {
  148. for (i=minX; i<=maxX; i+=STEP) {
  149. if (m_curNumTerrainVertices >= m_vertexTerrainSize) return;
  150. curVb->diffuse = (0<<24)|TheTerrainRenderObject->getStaticDiffuse(i,j);
  151. Vector3 pos;
  152. pos.Z = ((float)m_map->getHeight(i,j)*MAP_HEIGHT_SCALE);
  153. pos.X = (i)*MAP_XY_FACTOR - m_map->getBorderSizeInline()*MAP_XY_FACTOR;
  154. pos.Y = (j)*MAP_XY_FACTOR - m_map->getBorderSizeInline()*MAP_XY_FACTOR;
  155. curVb->u1 = (float)(i-minX)/(float)(m_width);
  156. curVb->v1 = 1.0f - (float)(j-minY)/(float)(m_width);
  157. curVb->x = pos.X;
  158. curVb->y = pos.Y;
  159. curVb->z = pos.Z;
  160. curVb++;
  161. m_curNumTerrainVertices++;
  162. bounds.Add_Point(pos);
  163. }
  164. }
  165. m_bounds.Init(bounds);
  166. if (m_terrainTexture == NULL || doTextures) {
  167. REF_PTR_RELEASE(m_terrainTexture);
  168. REF_PTR_RELEASE(m_terrainTexture2X);
  169. REF_PTR_RELEASE(m_terrainTexture4X);
  170. m_terrainTexture = m_map->getFlatTexture(m_xOrigin, m_yOrigin, m_width, PIXELS_PER_GRID);
  171. // DEBUG ONLY. jba. m_terrainTexture = (TerrainTextureClass *)NEW_REF(TextureClass, ("TBBib.tga"));
  172. m_terrainTexture->Get_Filter().Set_U_Addr_Mode(TextureFilterClass::TEXTURE_ADDRESS_CLAMP);
  173. m_terrainTexture->Get_Filter().Set_V_Addr_Mode(TextureFilterClass::TEXTURE_ADDRESS_CLAMP);
  174. }
  175. if (m_curNumTerrainIndices == 0) {
  176. // Only do the index buffer if it has never been done. Index values don't change. jba.
  177. DX8IndexBufferClass::WriteLockClass lockIdxBuffer(m_indexTerrain);
  178. ib = lockIdxBuffer.Get_Index_Array();
  179. UnsignedShort *curIb = ib;
  180. Int yOffset = ((maxX - minX)/STEP+1);
  181. Int width = yOffset;
  182. Int height = (maxY - minY)/STEP;
  183. *curIb++ = width-1;
  184. m_curNumTerrainIndices++;
  185. for (j=0; j<height; j++) {
  186. *curIb++ = j*yOffset + yOffset + width-1;
  187. m_curNumTerrainIndices++;
  188. for (i=width-2; i>=0; i--) {
  189. if (m_curNumTerrainIndices+2 > m_indexTerrainSize) return;
  190. *curIb++ = j*yOffset + i;
  191. *curIb++ = j*yOffset + i+yOffset;
  192. m_curNumTerrainIndices+=2;
  193. }
  194. j++;
  195. if (j<height) {
  196. *curIb++ = j*yOffset + yOffset;
  197. m_curNumTerrainIndices++;
  198. for (i=1; i<width; i++) {
  199. if (m_curNumTerrainIndices+2 > m_indexTerrainSize) return;
  200. *curIb++ = j*yOffset + i;
  201. *curIb++ = j*yOffset + i+yOffset;
  202. m_curNumTerrainIndices+=2;
  203. }
  204. }
  205. }
  206. }
  207. }
  208. //=============================================================================
  209. // W3DTerrainBackground::fillVBRecursive
  210. //=============================================================================
  211. /** Fills in vertex & index buffers.
  212. */
  213. Bool W3DTerrainBackground::advanceLeft(ICoord2D &left, Int xOffset, Int yOffset, Int width)
  214. {
  215. while (left.y < yOffset+width) {
  216. left.y++;
  217. if (m_map->getFlipState(left.x+m_xOrigin, left.y+m_yOrigin)) {
  218. return true;
  219. }
  220. }
  221. while (left.x < xOffset+width-1) {
  222. left.x++;
  223. if (m_map->getFlipState(left.x+m_xOrigin, left.y+m_yOrigin)) {
  224. return true;
  225. }
  226. }
  227. return false;
  228. }
  229. //=============================================================================
  230. // W3DTerrainBackground::fillVBRecursive
  231. //=============================================================================
  232. /** Fills in vertex & index buffers.
  233. */
  234. Bool W3DTerrainBackground::advanceRight(ICoord2D &right, Int xOffset, Int yOffset, Int width)
  235. {
  236. while (right.x < xOffset+width) {
  237. right.x++;
  238. if (m_map->getFlipState(right.x+m_xOrigin, right.y+m_yOrigin)) {
  239. return true;
  240. }
  241. }
  242. while (right.y < yOffset+width-1) {
  243. right.y++;
  244. if (m_map->getFlipState(right.x+m_xOrigin, right.y+m_yOrigin)) {
  245. return true;
  246. }
  247. }
  248. return false;
  249. }
  250. //=============================================================================
  251. // W3DTerrainBackground::fillVBRecursive
  252. //=============================================================================
  253. /** Fills in vertex & index buffers.
  254. */
  255. void W3DTerrainBackground::fillVBRecursive(UnsignedShort *ib, Int xOffset, Int yOffset,
  256. Int width, UnsignedShort *ndx, Int &curIndex)
  257. {
  258. Int bottomLeftNdx = ndx[xOffset+yOffset*(m_width+1)];
  259. Int topRightNdx = ndx[xOffset+width + (yOffset+width)*(m_width+1)];
  260. Int limitX = m_map->getXExtent()-1;
  261. Int limitY = m_map->getYExtent()-1;
  262. Int i, j;
  263. Bool match = true;
  264. Int minX = m_xOrigin+xOffset;
  265. Int minY = m_yOrigin+yOffset;
  266. Int cornerHeight = m_map->getHeight(minX, minY);
  267. for (i=0; i<=width; i++) {
  268. for (j=0; j<=width; j++) {
  269. Int k = minX+i;
  270. k = k<limitX?k:limitX;
  271. Int l = minY+j;
  272. l = l<limitY?l:limitY;
  273. if (cornerHeight!=m_map->getHeight(k, l)) {
  274. match = false;
  275. break;
  276. }
  277. }
  278. }
  279. if (width==1) {
  280. match = true;
  281. }
  282. if (match) {
  283. UnsignedShort prevNdxLeft;
  284. UnsignedShort prevNdxRight;
  285. ICoord2D left;
  286. left.x = xOffset;
  287. left.y = yOffset;
  288. ICoord2D right;
  289. right.x = xOffset;
  290. right.y = yOffset;
  291. advanceLeft(left, xOffset, yOffset, width);
  292. advanceRight(right, xOffset, yOffset, width);
  293. if (ib) {
  294. ib[curIndex] = bottomLeftNdx;
  295. }
  296. curIndex++;
  297. prevNdxRight = ndx[right.x+right.y*(m_width+1)];
  298. if (ib) {
  299. ib[curIndex] = prevNdxRight;
  300. }
  301. curIndex++;
  302. prevNdxLeft = ndx[left.x+left.y*(m_width+1)];
  303. if (ib) {
  304. ib[curIndex] = prevNdxLeft;
  305. }
  306. curIndex++;
  307. Bool didLeft = true;
  308. Bool didRight = true;
  309. while (didLeft || didRight) {
  310. didLeft = advanceLeft(left, xOffset, yOffset, width);
  311. if (didLeft) {
  312. if (ib) {
  313. ib[curIndex] = prevNdxLeft;
  314. }
  315. curIndex++;
  316. if (ib) {
  317. ib[curIndex] = prevNdxRight;
  318. }
  319. curIndex++;
  320. prevNdxLeft = ndx[left.x+left.y*(m_width+1)];
  321. if (ib) {
  322. ib[curIndex] = prevNdxLeft;
  323. }
  324. curIndex++;
  325. }
  326. didRight = advanceRight(right, xOffset, yOffset, width);
  327. if (didRight) {
  328. if (ib) {
  329. ib[curIndex] = prevNdxLeft;
  330. }
  331. curIndex++;
  332. if (ib) {
  333. ib[curIndex] = prevNdxRight;
  334. }
  335. curIndex++;
  336. prevNdxRight = ndx[right.x+right.y*(m_width+1)];
  337. if (ib) {
  338. ib[curIndex] = prevNdxRight;
  339. }
  340. curIndex++;
  341. }
  342. }
  343. if (ib) {
  344. ib[curIndex] = prevNdxLeft;
  345. }
  346. curIndex++;
  347. if (ib) {
  348. ib[curIndex] = prevNdxRight;
  349. }
  350. curIndex++;
  351. if (ib) {
  352. ib[curIndex] = topRightNdx;
  353. }
  354. curIndex++;
  355. return;
  356. }
  357. Int halfWidth = width/2;
  358. fillVBRecursive(ib, xOffset, yOffset, halfWidth, ndx, curIndex);
  359. fillVBRecursive(ib, xOffset, yOffset+halfWidth, halfWidth, ndx, curIndex);
  360. fillVBRecursive(ib, xOffset+halfWidth, yOffset, halfWidth, ndx, curIndex);
  361. fillVBRecursive(ib, xOffset+halfWidth, yOffset+halfWidth, halfWidth, ndx, curIndex);
  362. }
  363. //=============================================================================
  364. // W3DTerrainBackground::fillVBRecursive
  365. //=============================================================================
  366. /** Fills in vertex & index buffers.
  367. */
  368. void W3DTerrainBackground::setFlipRecursive(Int xOffset, Int yOffset, Int width)
  369. {
  370. Int limitX = m_map->getXExtent()-1;
  371. Int limitY = m_map->getYExtent()-1;
  372. Int i, j;
  373. Bool match = true;
  374. Int minX = m_xOrigin+xOffset;
  375. Int minY = m_yOrigin+yOffset;
  376. Int cornerHeight = m_map->getHeight(minX, minY);
  377. for (i=0; i<=width; i++) {
  378. for (j=0; j<=width; j++) {
  379. Int k = minX+i;
  380. k = k<limitX?k:limitX;
  381. Int l = minY+j;
  382. l = l<limitY?l:limitY;
  383. if (cornerHeight!=m_map->getHeight(k, l)) {
  384. match = false;
  385. break;
  386. }
  387. }
  388. }
  389. if (width==1) {
  390. match = true;
  391. }
  392. if (match) {
  393. m_map->setFlipState(minX, minY, true);
  394. m_map->setFlipState(minX+width, minY, true);
  395. m_map->setFlipState(minX+width, minY+width, true);
  396. m_map->setFlipState(minX, minY+width, true);
  397. return;
  398. }
  399. Int halfWidth = width/2;
  400. setFlipRecursive(xOffset, yOffset, halfWidth);
  401. setFlipRecursive(xOffset, yOffset+halfWidth, halfWidth);
  402. setFlipRecursive(xOffset+halfWidth, yOffset, halfWidth);
  403. setFlipRecursive(xOffset+halfWidth, yOffset+halfWidth, halfWidth);
  404. }
  405. //=============================================================================
  406. // W3DTerrainBackground::doTesselatedUpdate
  407. //=============================================================================
  408. /** Updates a partial block of vertices from [x0,y0 to x1,y1]
  409. The coordinates in partialRange are map cell coordinates, relative to the entire map.
  410. The vertex coordinates and texture coordinates, as well as static lighting are updated.
  411. */
  412. void W3DTerrainBackground::doTesselatedUpdate(const IRegion2D &partialRange, WorldHeightMap *htMap, Bool doTextures )
  413. {
  414. if (m_map==NULL) return;
  415. if (htMap) {
  416. REF_PTR_SET(m_map, htMap);
  417. }
  418. if (!m_initialized) {
  419. return;
  420. }
  421. Int minX = m_xOrigin;
  422. Int minY = m_yOrigin;
  423. Int maxX = m_xOrigin + m_width;
  424. Int maxY = m_yOrigin + m_width;
  425. Int limitX = m_map->getXExtent()-1;
  426. Int limitY = m_map->getYExtent()-1;
  427. if (partialRange.lo.x > maxX) return;
  428. if (partialRange.lo.y > maxY) return;
  429. if (partialRange.hi.x < minX) return;
  430. if (partialRange.hi.y < minY) return;
  431. setFlip(htMap);
  432. Int count = (m_width+1)*(m_width+1);
  433. UnsignedShort *ndx = new UnsignedShort[count];
  434. Int requiredVertex = 0;
  435. Int i, j;
  436. for (j=minY; j<=maxY; j++) {
  437. for (i=minX; i<=maxX; i++) {
  438. Int ndxNdx = i-minX + (m_width+1)*(j-minY);
  439. DEBUG_ASSERTCRASH(ndxNdx<count, ("Bad ndxNdx"));
  440. ndx[ndxNdx] = 0;
  441. if (m_map->getFlipState(i, j)) {
  442. requiredVertex++;
  443. }
  444. }
  445. }
  446. if (m_vertexTerrainSize<requiredVertex || m_vertexTerrain==NULL) {
  447. m_vertexTerrainSize = requiredVertex;
  448. REF_PTR_RELEASE(m_vertexTerrain);
  449. m_vertexTerrain=NEW_REF(DX8VertexBufferClass,(DX8_FVF_XYZDUV2,m_vertexTerrainSize+4,DX8VertexBufferClass::USAGE_DEFAULT));
  450. }
  451. m_curNumTerrainVertices = 0;
  452. VertexFormatXYZDUV2 *vb;
  453. // Lock the buffer.
  454. DX8VertexBufferClass::WriteLockClass lockVtxBuffer(m_vertexTerrain);
  455. vb=(VertexFormatXYZDUV2*)lockVtxBuffer.Get_Vertex_Array();
  456. VertexFormatXYZDUV2 *curVb = vb;
  457. // Add to the vertex buffer.
  458. for (j=minY; j<=maxY; j++) {
  459. for (i=minX; i<=maxX; i++) {
  460. if (m_map->getFlipState(i, j)) {
  461. curVb->diffuse = (0<<24)|TheTerrainRenderObject->getStaticDiffuse(i,j);
  462. Vector3 pos;
  463. Int k = i<limitX?i:limitX;
  464. Int l = j<limitY?j:limitY;
  465. pos.Z = ((float)m_map->getHeight(k,l)*MAP_HEIGHT_SCALE);
  466. pos.X = (i)*MAP_XY_FACTOR - m_map->getBorderSizeInline()*MAP_XY_FACTOR;
  467. pos.Y = (j)*MAP_XY_FACTOR - m_map->getBorderSizeInline()*MAP_XY_FACTOR;
  468. curVb->u1 = (float)(i-minX)/(float)(m_width);
  469. curVb->v1 = 1.0f - (float)(j-minY)/(float)(m_width);
  470. curVb->x = pos.X;
  471. curVb->y = pos.Y;
  472. curVb->z = pos.Z;
  473. curVb++;
  474. Int ndxNdx = i-minX + (m_width+1)*(j-minY);
  475. DEBUG_ASSERTCRASH(ndxNdx<count, ("Bad ndxNdx"));
  476. ndx[ndxNdx] = m_curNumTerrainVertices;
  477. m_curNumTerrainVertices++;
  478. }
  479. }
  480. }
  481. Int requiredIndex = 0;
  482. fillVBRecursive(NULL, 0, 0, m_width, ndx, requiredIndex);
  483. if (m_indexTerrainSize<requiredIndex || m_indexTerrain==NULL) {
  484. m_indexTerrainSize = requiredIndex;
  485. REF_PTR_RELEASE(m_indexTerrain);
  486. m_indexTerrain=NEW_REF(DX8IndexBufferClass,(m_indexTerrainSize+4,DX8IndexBufferClass::USAGE_DEFAULT));
  487. }
  488. m_curNumTerrainIndices = 0;
  489. UnsignedShort *ib;
  490. DX8IndexBufferClass::WriteLockClass lockIdxBuffer(m_indexTerrain);
  491. ib = lockIdxBuffer.Get_Index_Array();
  492. fillVBRecursive(ib, 0, 0, m_width, ndx, m_curNumTerrainIndices);
  493. delete ndx;
  494. ndx = NULL;
  495. MinMaxAABoxClass bounds;
  496. bounds.Init_Empty();
  497. for (j=minY; j<=maxY; j+=1) {
  498. for (i=minX; i<=maxX; i+=1) {
  499. Vector3 pos;
  500. Int k = i<limitX?i:limitX;
  501. Int l = j<limitY?j:limitY;
  502. pos.Z = ((float)m_map->getHeight(k,l)*MAP_HEIGHT_SCALE);
  503. pos.X = (i)*MAP_XY_FACTOR - m_map->getBorderSizeInline()*MAP_XY_FACTOR;
  504. pos.Y = (j)*MAP_XY_FACTOR - m_map->getBorderSizeInline()*MAP_XY_FACTOR;
  505. bounds.Add_Point(pos);
  506. }
  507. }
  508. m_bounds.Init(bounds);
  509. if (m_terrainTexture == NULL || doTextures) {
  510. REF_PTR_RELEASE(m_terrainTexture);
  511. REF_PTR_RELEASE(m_terrainTexture2X);
  512. REF_PTR_RELEASE(m_terrainTexture4X);
  513. m_terrainTexture = m_map->getFlatTexture(m_xOrigin, m_yOrigin, m_width, PIXELS_PER_GRID);
  514. // DEBUG ONLY. jba. m_terrainTexture = (TerrainTextureClass *)NEW_REF(TextureClass, ("TBBib.tga"));
  515. m_terrainTexture->Get_Filter().Set_U_Addr_Mode(TextureFilterClass::TEXTURE_ADDRESS_CLAMP);
  516. m_terrainTexture->Get_Filter().Set_V_Addr_Mode(TextureFilterClass::TEXTURE_ADDRESS_CLAMP);
  517. }
  518. }
  519. //-----------------------------------------------------------------------------
  520. // Public Functions
  521. //-----------------------------------------------------------------------------
  522. //=============================================================================
  523. // W3DTerrainBackground::~W3DTerrainBackground
  524. //=============================================================================
  525. /** Destructor. Releases w3d assets. */
  526. //=============================================================================
  527. W3DTerrainBackground::~W3DTerrainBackground(void)
  528. {
  529. freeTerrainBuffers();
  530. REF_PTR_RELEASE(m_terrainTexture);
  531. REF_PTR_RELEASE(m_terrainTexture2X);
  532. REF_PTR_RELEASE(m_terrainTexture4X);
  533. }
  534. //=============================================================================
  535. // W3DTerrainBackground::W3DTerrainBackground
  536. //=============================================================================
  537. /** Constructor. Sets m_initialized to true if it finds the w3d models it needs
  538. for the bibs. */
  539. //=============================================================================
  540. W3DTerrainBackground::W3DTerrainBackground(void):
  541. m_vertexTerrain(NULL),
  542. m_vertexTerrainSize(0),
  543. m_initialized(FALSE),
  544. m_indexTerrain(NULL),
  545. m_indexTerrainSize(0),
  546. m_terrainTexture(NULL),
  547. m_terrainTexture2X(NULL),
  548. m_terrainTexture4X(NULL),
  549. m_cullStatus(CULL_STATUS_UNKNOWN),
  550. m_texMultiplier(TEX1X)
  551. {
  552. }
  553. //=============================================================================
  554. // W3DTerrainBackground::freeTerrainBuffers
  555. //=============================================================================
  556. /** Frees the index and vertex buffers. */
  557. //=============================================================================
  558. void W3DTerrainBackground::freeTerrainBuffers(void)
  559. {
  560. REF_PTR_RELEASE(m_vertexTerrain);
  561. REF_PTR_RELEASE(m_indexTerrain);
  562. m_curNumTerrainVertices=0;
  563. m_curNumTerrainIndices=0;
  564. m_initialized = false;
  565. REF_PTR_RELEASE(m_map);
  566. REF_PTR_RELEASE(m_map);
  567. }
  568. //=============================================================================
  569. // W3DTerrainBackground::allocateTerrainBuffers
  570. //=============================================================================
  571. /** Allocates the index and vertex buffers. */
  572. //=============================================================================
  573. void W3DTerrainBackground::allocateTerrainBuffers(WorldHeightMap *htMap, Int xOrigin, Int yOrigin, Int width)
  574. {
  575. if (htMap==NULL) return;
  576. freeTerrainBuffers(); // in case already allocated. jba [3/24/2003]
  577. m_curNumTerrainVertices=0;
  578. m_curNumTerrainIndices=0;
  579. m_xOrigin = xOrigin;
  580. m_yOrigin = yOrigin;
  581. m_width = width;
  582. m_initialized = true;
  583. REF_PTR_SET(m_map, htMap);
  584. }
  585. //=============================================================================
  586. // W3DTerrainBackground::updateCenter
  587. //=============================================================================
  588. /** Updates the culling status. */
  589. //=============================================================================
  590. void W3DTerrainBackground::updateCenter(CameraClass *camera)
  591. {
  592. if (camera->Cull_Box(m_bounds)) {
  593. m_cullStatus = CULL_STATUS_INVISIBLE;
  594. } else {
  595. m_cullStatus = CULL_STATUS_VISIBLE;
  596. }
  597. if (m_cullStatus==CULL_STATUS_INVISIBLE) {
  598. REF_PTR_RELEASE(m_terrainTexture2X);
  599. REF_PTR_RELEASE(m_terrainTexture4X);
  600. m_texMultiplier = TEX1X;
  601. return;
  602. }
  603. Vector3 cameraPos = camera->Get_Position();
  604. const Real mipDistance = 310;
  605. const Real mipSlop = 40;
  606. const Real mip4xDistanceSqr = sqr(mipDistance+mipSlop);
  607. const Real mip2xDistanceSqr = sqr(2*mipDistance+mipSlop);
  608. const Real mipLODDistanceSqr = sqr(4*mipDistance+mipSlop);
  609. Real minDistSqr = 2*mip2xDistanceSqr;
  610. Int i, j, k;
  611. for (i=-1; i<2; i++) {
  612. for (j=-1; j<2; j++) {
  613. for (k=-1; k<2; k++) {
  614. Vector3 corner = m_bounds.Center;
  615. corner.X += m_bounds.Extent.X * i;
  616. corner.Y += m_bounds.Extent.Y * j;
  617. corner.Z += m_bounds.Extent.Z * k;
  618. Real distSqr = (cameraPos-corner).Length2();
  619. if (distSqr<minDistSqr) minDistSqr = distSqr;
  620. }
  621. }
  622. }
  623. m_texMultiplier = TEX1X;
  624. if (minDistSqr<mip4xDistanceSqr) {
  625. m_texMultiplier = TEX4X;
  626. } else if (minDistSqr<mip2xDistanceSqr) {
  627. m_texMultiplier = TEX2X;
  628. } else {
  629. REF_PTR_RELEASE(m_terrainTexture4X);
  630. REF_PTR_RELEASE(m_terrainTexture2X);
  631. Int LOD = 0;
  632. if (minDistSqr>mipLODDistanceSqr) {
  633. LOD = 1;
  634. }
  635. m_terrainTexture->setLOD(LOD);
  636. }
  637. }
  638. //=============================================================================
  639. // W3DTerrainBackground::updateCenter
  640. //=============================================================================
  641. /** Updates the culling status. */
  642. //=============================================================================
  643. void W3DTerrainBackground::updateTexture(void)
  644. {
  645. if (m_cullStatus==CULL_STATUS_INVISIBLE) {
  646. REF_PTR_RELEASE(m_terrainTexture2X);
  647. REF_PTR_RELEASE(m_terrainTexture4X);
  648. return;
  649. }
  650. if (m_texMultiplier == TEX4X) {
  651. REF_PTR_RELEASE(m_terrainTexture2X);
  652. if (m_terrainTexture4X == NULL) {
  653. m_terrainTexture4X = m_map->getFlatTexture(m_xOrigin, m_yOrigin, m_width, 4*PIXELS_PER_GRID);
  654. m_terrainTexture4X->Get_Filter().Set_U_Addr_Mode(TextureFilterClass::TEXTURE_ADDRESS_CLAMP);
  655. m_terrainTexture4X->Get_Filter().Set_V_Addr_Mode(TextureFilterClass::TEXTURE_ADDRESS_CLAMP);
  656. }
  657. } else if (m_texMultiplier == TEX2X) {
  658. REF_PTR_RELEASE(m_terrainTexture4X);
  659. if (m_terrainTexture2X == NULL) {
  660. m_terrainTexture2X = m_map->getFlatTexture(m_xOrigin, m_yOrigin, m_width, 2*PIXELS_PER_GRID);
  661. m_terrainTexture2X->Get_Filter().Set_U_Addr_Mode(TextureFilterClass::TEXTURE_ADDRESS_CLAMP);
  662. m_terrainTexture2X->Get_Filter().Set_V_Addr_Mode(TextureFilterClass::TEXTURE_ADDRESS_CLAMP);
  663. }
  664. } else {
  665. REF_PTR_RELEASE(m_terrainTexture4X);
  666. REF_PTR_RELEASE(m_terrainTexture2X);
  667. }
  668. }
  669. //=============================================================================
  670. // W3DTerrainBackground::renderTerrain
  671. //=============================================================================
  672. //=============================================================================
  673. void W3DTerrainBackground::drawVisiblePolys(RenderInfoClass & rinfo, Bool disableTextures)
  674. {
  675. #if 1
  676. if (m_curNumTerrainIndices == 0) {
  677. return;
  678. }
  679. if (m_cullStatus==CULL_STATUS_INVISIBLE) {
  680. return;
  681. }
  682. // Setup the vertex buffer, shader & texture.
  683. DX8Wrapper::Set_Index_Buffer(m_indexTerrain,0);
  684. DX8Wrapper::Set_Vertex_Buffer(m_vertexTerrain);
  685. if (!disableTextures) {
  686. if (m_terrainTexture4X) {
  687. DX8Wrapper::Set_Texture(1, m_terrainTexture4X);
  688. } else if (m_terrainTexture2X) {
  689. DX8Wrapper::Set_Texture(1, m_terrainTexture2X);
  690. } else {
  691. DX8Wrapper::Set_Texture(1, m_terrainTexture);
  692. }
  693. }
  694. DX8Wrapper::Draw_Triangles( 0, m_curNumTerrainIndices/3, 0, m_curNumTerrainVertices);
  695. #else
  696. if (m_curNumTerrainIndices == 0) {
  697. return;
  698. }
  699. if (m_cullStatus==CULL_STATUS_INVISIBLE) {
  700. return;
  701. }
  702. // Setup the vertex buffer, shader & texture.
  703. DX8Wrapper::Set_Index_Buffer(m_indexTerrain,0);
  704. DX8Wrapper::Set_Vertex_Buffer(m_vertexTerrain);
  705. if (!disableTextures) {
  706. if (m_terrainTexture4X) {
  707. DX8Wrapper::Set_Texture(0, m_terrainTexture4X);
  708. } else if (m_terrainTexture2X) {
  709. DX8Wrapper::Set_Texture(0, m_terrainTexture2X);
  710. } else {
  711. DX8Wrapper::Set_Texture(0, m_terrainTexture);
  712. }
  713. }
  714. DX8Wrapper::Draw_Triangles( 0, m_curNumTerrainIndices/3, 0, m_curNumTerrainVertices);
  715. #endif
  716. }