HeightMap.cpp 87 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461
  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: Heightmap.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: Heightmap.cpp
  36. //
  37. // Created: Mark W., John Ahlquist, April/May 2001
  38. //
  39. // Desc: Draw the terrain and scorchmarks in a scene.
  40. //
  41. //-----------------------------------------------------------------------------
  42. //-----------------------------------------------------------------------------
  43. // Includes
  44. //-----------------------------------------------------------------------------
  45. #include "W3DDevice/GameClient/heightmap.h"
  46. #ifndef USE_FLAT_HEIGHT_MAP // Flat height map uses flattened textures. jba. [3/20/2003]
  47. #include <stdio.h>
  48. #include <stdlib.h>
  49. #include <string.h>
  50. #include <assetmgr.h>
  51. #include <texture.h>
  52. #include <tri.h>
  53. #include <colmath.h>
  54. #include <coltest.h>
  55. #include <rinfo.h>
  56. #include <camera.h>
  57. #include <d3dx8core.h>
  58. #include "Common/GlobalData.h"
  59. #include "Common/PerfTimer.h"
  60. #include "GameClient/TerrainVisual.h"
  61. #include "GameClient/View.h"
  62. #include "GameClient/Water.h"
  63. #include "GameLogic/AIPathfind.h"
  64. #include "GameLogic/TerrainLogic.h"
  65. #include "W3DDevice/GameClient/TerrainTex.h"
  66. #include "W3DDevice/GameClient/W3DDynamicLight.h"
  67. #include "W3DDevice/GameClient/W3DScene.h"
  68. #include "W3DDevice/GameClient/W3DTerrainTracks.h"
  69. #include "W3DDevice/GameClient/W3DBibBuffer.h"
  70. #include "W3DDevice/GameClient/W3DTreeBuffer.h"
  71. #include "W3DDevice/GameClient/W3DPropBuffer.h"
  72. #include "W3DDevice/GameClient/W3DRoadBuffer.h"
  73. #include "W3DDevice/GameClient/W3DBridgeBuffer.h"
  74. #include "W3DDevice/GameClient/W3DWaypointBuffer.h"
  75. #include "W3DDevice/GameClient/W3DCustomEdging.h"
  76. #include "W3DDevice/GameClient/WorldHeightMap.h"
  77. #include "W3DDevice/GameClient/W3DShaderManager.h"
  78. #include "W3DDevice/GameClient/W3DShadow.h"
  79. #include "W3DDevice/GameClient/W3DWater.h"
  80. #include "W3DDevice/GameClient/W3DShroud.h"
  81. #include "WW3D2/DX8Wrapper.h"
  82. #include "WW3D2/Light.h"
  83. #include "WW3D2/Scene.h"
  84. #include "W3DDevice/GameClient/W3DPoly.h"
  85. #include "W3DDevice/GameClient/W3DCustomScene.h"
  86. #include "Common/PerfTimer.h"
  87. #include "Common/UnitTimings.h" //Contains the DO_UNIT_TIMINGS define jba.
  88. #ifdef _INTERNAL
  89. // for occasional debugging...
  90. //#pragma optimize("", off)
  91. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  92. #endif
  93. #define no_OPTIMIZED_HEIGHTMAP_LIGHTING 01
  94. // Doesn't work well. jba.
  95. const Bool HALF_RES_MESH = false;
  96. HeightMapRenderObjClass *TheHeightMap = NULL;
  97. //-----------------------------------------------------------------------------
  98. // Private Data
  99. //-----------------------------------------------------------------------------
  100. #define SC_DETAIL_BLEND ( SHADE_CNST(ShaderClass::PASS_LEQUAL, ShaderClass::DEPTH_WRITE_ENABLE, ShaderClass::COLOR_WRITE_ENABLE, ShaderClass::SRCBLEND_ONE, \
  101. ShaderClass::DSTBLEND_ZERO, ShaderClass::FOG_DISABLE, ShaderClass::GRADIENT_MODULATE, ShaderClass::SECONDARY_GRADIENT_DISABLE, ShaderClass::TEXTURING_ENABLE, \
  102. ShaderClass::ALPHATEST_DISABLE, ShaderClass::CULL_MODE_ENABLE, ShaderClass::DETAILCOLOR_SCALE, ShaderClass::DETAILALPHA_DISABLE) )
  103. static ShaderClass detailOpaqueShader(SC_DETAIL_BLEND);
  104. #define DEFAULT_MAX_FRAME_EXTRABLEND_TILES 256 //default number of terrain tiles rendered per call (must fit in one VB)
  105. #define DEFAULT_MAX_MAP_EXTRABLEND_TILES 2048 //default size of array allocated to hold all map extra blend tiles.
  106. #define DEFAULT_MAX_BATCH_SHORELINE_TILES 512 //maximum number of terrain tiles rendered per call (must fit in one VB)
  107. #define DEFAULT_MAX_MAP_SHORELINE_TILES 4096 //default size of array allocated to hold all map shoreline tiles.
  108. #define ADJUST_FROM_INDEX_TO_REAL(k) ((k-m_map->getBorderSizeInline())*MAP_XY_FACTOR)
  109. inline Int IABS(Int x) { if (x>=0) return x; return -x;};
  110. //-----------------------------------------------------------------------------
  111. // Private Functions
  112. //-----------------------------------------------------------------------------
  113. //=============================================================================
  114. // HeightMapRenderObjClass::freeIndexVertexBuffers
  115. //=============================================================================
  116. /** Frees the w3d resources used to draw the terrain. */
  117. //=============================================================================
  118. void HeightMapRenderObjClass::freeIndexVertexBuffers(void)
  119. {
  120. REF_PTR_RELEASE(m_indexBuffer);
  121. if (m_vertexBufferTiles) {
  122. for (int i=0; i<m_numVertexBufferTiles; i++)
  123. REF_PTR_RELEASE(m_vertexBufferTiles[i]);
  124. delete m_vertexBufferTiles;
  125. m_vertexBufferTiles = NULL;
  126. }
  127. if (m_vertexBufferBackup) {
  128. for (int i=0; i<m_numVertexBufferTiles; i++)
  129. delete m_vertexBufferBackup[i];
  130. delete m_vertexBufferBackup;
  131. m_vertexBufferBackup = NULL;
  132. }
  133. m_numVertexBufferTiles = 0;
  134. }
  135. //=============================================================================
  136. // HeightMapRenderObjClass::freeMapResources
  137. //=============================================================================
  138. /** Frees the w3d resources used to draw the terrain. */
  139. //=============================================================================
  140. Int HeightMapRenderObjClass::freeMapResources(void)
  141. {
  142. BaseHeightMapRenderObjClass::freeMapResources();
  143. freeIndexVertexBuffers();
  144. return 0;
  145. }
  146. //=============================================================================
  147. // HeightMapRenderObjClass::doTheDynamicLight
  148. //=============================================================================
  149. /** Calculates the diffuse lighting as affected by dynamic lighting. */
  150. //=============================================================================
  151. UnsignedInt HeightMapRenderObjClass::doTheDynamicLight(VERTEX_FORMAT *vb, VERTEX_FORMAT *vbMirror, Vector3*light, Vector3*normal, W3DDynamicLight *pLights[], Int numLights)
  152. {
  153. #ifdef USE_NORMALS
  154. return;
  155. #else
  156. Real shadeR, shadeG, shadeB;
  157. Int diffuse = vbMirror->diffuse;
  158. #ifdef _DEBUG
  159. //vbMirror->diffuse += 30; // Shows which vertexes are geting touched by dynamic light. debug only.
  160. #endif
  161. // (gth) avoiding the extra divides (compiler unfortunately didn't do this automatically...)
  162. const float oo255 = (1.0f/255.0f);
  163. shadeR = ((diffuse>>16)&0x00FF) * oo255;
  164. shadeG = ((diffuse>>8)&0x00FF) * oo255;
  165. shadeB = (diffuse&0x00FF) * oo255;
  166. Int alpha = (diffuse>>24)&0x00FF;
  167. Int k;
  168. for (k=0; k<numLights; k++) {
  169. W3DDynamicLight *pLight = pLights[k];
  170. if (!pLight->isEnabled()) {
  171. continue; // he is turned off.
  172. }
  173. Vector3 lightDirection(vbMirror->x, vbMirror->y, vbMirror->z);
  174. Real factor = 1.0f;
  175. switch(pLight->Get_Type()) {
  176. case LightClass::POINT:
  177. case LightClass::SPOT: {
  178. Vector3 lightLoc = pLight->Get_Position();
  179. lightDirection -= lightLoc;
  180. double range, midRange;
  181. pLight->Get_Far_Attenuation_Range(midRange, range);
  182. Real dist = lightDirection.Length();
  183. if (dist >= range) continue;
  184. if (midRange < 0.1) continue;
  185. factor = 1.0f - (dist - midRange) / (range - midRange);
  186. factor = WWMath::Clamp(factor,0.0f,1.0f);
  187. // (gth) normalize here since we have the length
  188. lightDirection /= dist;
  189. }
  190. break;
  191. case LightClass::DIRECTIONAL:
  192. pLight->Get_Spot_Direction(lightDirection);
  193. factor = 1.0;
  194. break;
  195. };
  196. // (gth) unneeded due to above normalization
  197. //lightDirection.Normalize();
  198. Vector3 lightRay(-lightDirection.X, -lightDirection.Y, -lightDirection.Z);
  199. Real shade = Vector3::Dot_Product(lightRay, *normal);
  200. shade *= factor;
  201. Vector3 diffuse;
  202. pLight->Get_Diffuse(&diffuse);
  203. Vector3 ambient;
  204. pLight->Get_Ambient(&ambient);
  205. if (shade > 1.0) shade = 1.0;
  206. if(shade < 0.0f) shade = 0.0f;
  207. shadeR += shade*diffuse.X;
  208. shadeG += shade*diffuse.Y;
  209. shadeB += shade*diffuse.Z;
  210. shadeR += factor*ambient.X;
  211. shadeG += factor*ambient.Y;
  212. shadeB += factor*ambient.Z;
  213. }
  214. if (shadeR > 1.0) shadeR = 1.0;
  215. if(shadeR < 0.0f) shadeR = 0.0f;
  216. if (shadeG > 1.0) shadeG = 1.0;
  217. if(shadeG < 0.0f) shadeG = 0.0f;
  218. if (shadeB > 1.0) shadeB = 1.0;
  219. if(shadeB < 0.0f) shadeB = 0.0f;
  220. shadeR*=255.0f;
  221. shadeG*=255.0f;
  222. shadeB*=255.0f;
  223. // (gth) faster float to int conversion, return the result so we can re-use it.
  224. // vb->diffuse=REAL_TO_INT(shadeB) | (REAL_TO_INT(shadeG) << 8) | (REAL_TO_INT(shadeR) << 16) | ((int)alpha << 24);
  225. UnsignedInt light_val = WWMath::Float_To_Int_Chop(shadeB) | (WWMath::Float_To_Int_Chop(shadeG) << 8) | (WWMath::Float_To_Int_Chop(shadeR) << 16) | ((int)alpha << 24);
  226. vb->diffuse = light_val;
  227. return light_val;
  228. #endif
  229. }
  230. //=============================================================================
  231. // HeightMapRenderObjClass::getXWithOrigin
  232. //=============================================================================
  233. /** Gets the x index that corresponds to the data. For example, if the columns
  234. are shifted by 3, index 3 is actually the first row of polygons, or 0. Yes it
  235. is confusing, but it makes sliding the map 10x faster. */
  236. //=============================================================================
  237. Int HeightMapRenderObjClass::getXWithOrigin(Int x)
  238. {
  239. x -= m_originX;
  240. if (x<0) x+= m_x-1;
  241. if (x>= m_x-1) x-=m_x-1;
  242. #ifdef _DEBUG
  243. DEBUG_ASSERTCRASH (x>=0, ("X out of range."));
  244. DEBUG_ASSERTCRASH (x<m_x-1, ("X out of range."));
  245. #endif
  246. if (x<0) x = 0;
  247. if (x>= m_x-1) x=m_x-1;
  248. return x;
  249. }
  250. //=============================================================================
  251. // HeightMapRenderObjClass::getYWithOrigin
  252. //=============================================================================
  253. /** Gets the y index that corresponds to the data. For example, if the rows
  254. are shifted by 3, index 3 is actually the first row of polygons, or 0. Yes it
  255. is confusing, but it makes sliding the map 10x faster. */
  256. //=============================================================================
  257. Int HeightMapRenderObjClass::getYWithOrigin(Int y)
  258. {
  259. y -= m_originY;
  260. if (y<0) y+= m_y-1;
  261. if (y>= m_y-1) y-=m_y-1;
  262. #ifdef _DEBUG
  263. DEBUG_ASSERTCRASH (y>=0, ("Y out of range."));
  264. DEBUG_ASSERTCRASH (y<m_y-1, ("Y out of range."));
  265. #endif
  266. if (y<0) y = 0;
  267. if (y>= m_y-1) y=m_y-1;
  268. return y;
  269. }
  270. //=============================================================================
  271. // HeightMapRenderObjClass::updateVB
  272. //=============================================================================
  273. /** Update a rectangular block of the given Vertex Buffer.
  274. data is expected to be an array same dimensions as current heightmap
  275. mapped into this VB.
  276. */
  277. //=============================================================================
  278. Int HeightMapRenderObjClass::updateVB(DX8VertexBufferClass *pVB, char *data, Int x0, Int y0, Int x1, Int y1, Int originX, Int originY, WorldHeightMap *pMap, RefRenderObjListIterator *pLightsIterator)
  279. {
  280. Int i,j;
  281. Vector3 lightRay[MAX_GLOBAL_LIGHTS];
  282. const Coord3D *lightPos;
  283. Int xCoord, yCoord;
  284. Int vn0,un0,vp1,up1;
  285. Vector3 l2r,n2f,normalAtTexel;
  286. Int vertsPerRow=(VERTEX_BUFFER_TILE_LENGTH)*4; //vertices per row of VB
  287. Int cellOffset = 1;
  288. if (HALF_RES_MESH) {
  289. cellOffset = 2;
  290. }
  291. REF_PTR_SET(m_map, pMap); //update our heightmap pointer in case it changed since last call.
  292. if (m_vertexBufferTiles && pMap)
  293. {
  294. #ifdef _DEBUG
  295. assert(x0 >= originX && y0 >= originY && x1>x0 && y1>y0 && x1<=originX+VERTEX_BUFFER_TILE_LENGTH && y1<=originY+VERTEX_BUFFER_TILE_LENGTH);
  296. #endif
  297. DX8VertexBufferClass::WriteLockClass lockVtxBuffer(pVB);
  298. VERTEX_FORMAT *vbHardware = (VERTEX_FORMAT*)lockVtxBuffer.Get_Vertex_Array();
  299. VERTEX_FORMAT *vBase = (VERTEX_FORMAT*)data;
  300. // Note that we are building the vertex buffer data in the memory buffer, data.
  301. // At the bottom, we will copy the final vertex data for one cell into the
  302. // hardware vertex buffer.
  303. for (j=y0; j<y1; j++)
  304. {
  305. VERTEX_FORMAT *vb = vBase;
  306. if (HALF_RES_MESH) {
  307. if (j&1) continue;
  308. vb += ((j-originY)/2)*vertsPerRow/2; //skip to correct row in vertex buffer
  309. vb += ((x0-originX)/2)*4; //skip to correct vertex in row.
  310. } else {
  311. vb += (j-originY)*vertsPerRow; //skip to correct row in vertex buffer
  312. vb += (x0-originX)*4; //skip to correct vertex in row.
  313. }
  314. vn0 = getYWithOrigin(j)-cellOffset;
  315. if (vn0 < -pMap->getDrawOrgY())
  316. vn0=-pMap->getDrawOrgY();
  317. vp1 = getYWithOrigin(j+cellOffset)+cellOffset;
  318. if (vp1 >= pMap->getYExtent()-pMap->getDrawOrgY())
  319. vp1=pMap->getYExtent()-pMap->getDrawOrgY()-1;
  320. yCoord = getYWithOrigin(j)+pMap->getDrawOrgY();
  321. for (i=x0; i<x1; i++)
  322. {
  323. if (HALF_RES_MESH) {
  324. if (i&1) continue;
  325. }
  326. un0 = getXWithOrigin(i)-cellOffset;
  327. if (un0 < -pMap->getDrawOrgX())
  328. un0=-pMap->getDrawOrgX();
  329. up1 = getXWithOrigin(i+cellOffset)+cellOffset;
  330. if (up1 >= pMap->getXExtent()-pMap->getDrawOrgX())
  331. up1=pMap->getXExtent()-pMap->getDrawOrgX()-1;
  332. xCoord = getXWithOrigin(i)+pMap->getDrawOrgX();
  333. //update the 4 vertices in this block
  334. float U[4], V[4];
  335. UnsignedByte alpha[4];
  336. float UA[4], VA[4];
  337. Bool flipForBlend = false; // True if the blend needs the triangles flipped.
  338. if (pMap) {
  339. pMap->getUVData(getXWithOrigin(i),getYWithOrigin(j),U, V, HALF_RES_MESH);
  340. pMap->getAlphaUVData(getXWithOrigin(i),getYWithOrigin(j), UA, VA, alpha, &flipForBlend, HALF_RES_MESH);
  341. }
  342. for (Int lightIndex=0; lightIndex < TheGlobalData->m_numGlobalLights; lightIndex++)
  343. {
  344. lightPos=&TheGlobalData->m_terrainLightPos[lightIndex];
  345. lightRay[lightIndex].Set(-lightPos->x,-lightPos->y, -lightPos->z);
  346. }
  347. //top-left sample
  348. l2r.Set(2*MAP_XY_FACTOR,0,MAP_HEIGHT_SCALE*(pMap->getDisplayHeight(getXWithOrigin(i)+cellOffset, getYWithOrigin(j)) - pMap->getDisplayHeight(un0, getYWithOrigin(j))));
  349. n2f.Set(0,2*MAP_XY_FACTOR,MAP_HEIGHT_SCALE*(pMap->getDisplayHeight(getXWithOrigin(i), (getYWithOrigin(j)+cellOffset)) - pMap->getDisplayHeight(getXWithOrigin(i), vn0)));
  350. #ifdef ALLOW_TEMPORARIES
  351. normalAtTexel= Normalize(Vector3::Cross_Product(l2r,n2f));
  352. #else
  353. Vector3::Normalized_Cross_Product(l2r, n2f, &normalAtTexel);
  354. #endif
  355. vb->x=xCoord;
  356. vb->y=yCoord;
  357. vb->z= ((float)pMap->getDisplayHeight(getXWithOrigin(i), getYWithOrigin(j)))*MAP_HEIGHT_SCALE;
  358. vb->x = ADJUST_FROM_INDEX_TO_REAL(vb->x);
  359. vb->y = ADJUST_FROM_INDEX_TO_REAL(vb->y);
  360. vb->u1=U[0];
  361. vb->v1=V[0];
  362. vb->u2=UA[0];
  363. vb->v2=VA[0];
  364. doTheLight(vb, lightRay, &normalAtTexel, pLightsIterator, alpha[0]);
  365. vb++;
  366. //top-right sample
  367. l2r.Set(2*MAP_XY_FACTOR,0,MAP_HEIGHT_SCALE*(pMap->getDisplayHeight(up1 , getYWithOrigin(j) ) - pMap->getDisplayHeight(getXWithOrigin(i) , getYWithOrigin(j) )));
  368. n2f.Set(0,2*MAP_XY_FACTOR,MAP_HEIGHT_SCALE*(pMap->getDisplayHeight(getXWithOrigin(i)+cellOffset , (getYWithOrigin(j)+cellOffset) ) - pMap->getDisplayHeight(getXWithOrigin(i)+cellOffset , vn0 )));
  369. #ifdef ALLOW_TEMPORARIES
  370. normalAtTexel= Normalize(Vector3::Cross_Product(l2r,n2f));
  371. #else
  372. Vector3::Normalized_Cross_Product(l2r, n2f, &normalAtTexel);
  373. #endif
  374. vb->x=xCoord+cellOffset;
  375. vb->y=yCoord;
  376. vb->z= ((float)pMap->getDisplayHeight(getXWithOrigin(i)+cellOffset, getYWithOrigin(j)))*MAP_HEIGHT_SCALE;
  377. vb->x = ADJUST_FROM_INDEX_TO_REAL(vb->x);
  378. vb->y = ADJUST_FROM_INDEX_TO_REAL(vb->y);
  379. vb->u1=U[1];
  380. vb->v1=V[1];
  381. vb->u2=UA[1];
  382. vb->v2=VA[1];
  383. doTheLight(vb, lightRay, &normalAtTexel, pLightsIterator, alpha[1]);
  384. vb++;
  385. //bottom-right sample
  386. l2r.Set(2*MAP_XY_FACTOR,0,MAP_HEIGHT_SCALE*(pMap->getDisplayHeight(up1 , (getYWithOrigin(j)+cellOffset) ) - pMap->getDisplayHeight(getXWithOrigin(i) , (getYWithOrigin(j)+cellOffset) )));
  387. n2f.Set(0,2*MAP_XY_FACTOR,MAP_HEIGHT_SCALE*(pMap->getDisplayHeight(getXWithOrigin(i)+cellOffset , vp1 ) - pMap->getDisplayHeight(getXWithOrigin(i)+cellOffset , getYWithOrigin(j) )));
  388. #ifdef ALLOW_TEMPORARIES
  389. normalAtTexel= Normalize(Vector3::Cross_Product(l2r,n2f));
  390. #else
  391. Vector3::Normalized_Cross_Product(l2r, n2f, &normalAtTexel);
  392. #endif
  393. vb->x=xCoord+cellOffset;
  394. if (yCoord + 1 == pMap->getDrawOrgY() + m_y - 1) {
  395. vb->y=yCoord+1;
  396. } else {
  397. vb->y=yCoord+cellOffset;
  398. }
  399. vb->z= ((float)pMap->getDisplayHeight(getXWithOrigin(i)+cellOffset, getYWithOrigin(j)+cellOffset))*MAP_HEIGHT_SCALE;
  400. vb->x = ADJUST_FROM_INDEX_TO_REAL(vb->x);
  401. vb->y = ADJUST_FROM_INDEX_TO_REAL(vb->y);
  402. vb->u1=U[2];
  403. vb->v1=V[2];
  404. vb->u2=UA[2];
  405. vb->v2=VA[2];
  406. doTheLight(vb, lightRay, &normalAtTexel, pLightsIterator, alpha[2]);
  407. vb++;
  408. //bottom-left sample
  409. l2r.Set(2*MAP_XY_FACTOR,0,MAP_HEIGHT_SCALE*(pMap->getDisplayHeight(getXWithOrigin(i)+cellOffset , (getYWithOrigin(j)+cellOffset) ) - pMap->getDisplayHeight(un0 , (getYWithOrigin(j)+cellOffset) )));
  410. n2f.Set(0,2*MAP_XY_FACTOR,MAP_HEIGHT_SCALE*(pMap->getDisplayHeight(getXWithOrigin(i) , vp1 ) - pMap->getDisplayHeight(getXWithOrigin(i) , getYWithOrigin(j) )));
  411. #ifdef ALLOW_TEMPORARIES
  412. normalAtTexel= Normalize(Vector3::Cross_Product(l2r,n2f));
  413. #else
  414. Vector3::Normalized_Cross_Product(l2r, n2f, &normalAtTexel);
  415. #endif
  416. if (xCoord == pMap->getDrawOrgX()) {
  417. vb->x=xCoord;
  418. //if (vb->x < 0) vb->x = 0;
  419. } else {
  420. vb->x=xCoord;
  421. }
  422. if (yCoord + 1 == pMap->getDrawOrgY() + m_y - 1) {
  423. vb->y=yCoord+1;
  424. } else {
  425. vb->y=yCoord+cellOffset;
  426. }
  427. vb->z= ((float)pMap->getDisplayHeight(getXWithOrigin(i), getYWithOrigin(j)+cellOffset))*MAP_HEIGHT_SCALE;
  428. vb->x = ADJUST_FROM_INDEX_TO_REAL(vb->x);
  429. vb->y = ADJUST_FROM_INDEX_TO_REAL(vb->y);
  430. vb->u1=U[3];
  431. vb->v1=V[3];
  432. vb->u2=UA[3];
  433. vb->v2=VA[3];
  434. doTheLight(vb, lightRay, &normalAtTexel, pLightsIterator, alpha[3]);
  435. vb++;
  436. VERTEX_FORMAT *pCurVertices = vb-4;
  437. #ifdef FLIP_TRIANGLES // jba - reduces "diamonding" in some cases, not others. Better cliffs, though.
  438. VERTEX_FORMAT tmpVertex;
  439. if (flipForBlend) {
  440. tmpVertex = pCurVertices[0];
  441. pCurVertices[0] = pCurVertices[1];
  442. pCurVertices[1] = pCurVertices[2];
  443. pCurVertices[2] = pCurVertices[3];
  444. pCurVertices[3] = tmpVertex;
  445. }
  446. #endif
  447. if (m_showImpassableAreas) {
  448. // Color impassable cells "red"
  449. DEBUG_ASSERTCRASH(PATHFIND_CELL_SIZE_F == MAP_XY_FACTOR, ("Pathfind must be terrain cell size, or this code needs reworking. John A."));
  450. Real borderHiX = (pMap->getXExtent()-2*pMap->getBorderSizeInline())*MAP_XY_FACTOR;
  451. Real borderHiY = (pMap->getYExtent()-2*pMap->getBorderSizeInline())*MAP_XY_FACTOR;
  452. Bool border = pCurVertices[0].x == -MAP_XY_FACTOR || pCurVertices[0].y == -MAP_XY_FACTOR;
  453. Bool cliffMapped = pMap->isCliffMappedTexture(getXWithOrigin(i), getYWithOrigin(j));
  454. if (pCurVertices[0].x == borderHiX) {
  455. border = true;
  456. }
  457. if (pCurVertices[0].y == borderHiY) {
  458. border = true;
  459. }
  460. Bool isCliff = pMap->getCliffState(getXWithOrigin(i)+pMap->getDrawOrgX(), getYWithOrigin(j)+pMap->getDrawOrgY())
  461. || showAsVisibleCliff(getXWithOrigin(i) + pMap->getDrawOrgX(), getYWithOrigin(j)+pMap->getDrawOrgY());
  462. if ( isCliff || border || cliffMapped) {
  463. Int cellX, cellY;
  464. for (cellX=0; cellX<2; cellX++) {
  465. for (cellY=0; cellY<2; cellY++) {
  466. Int vertex = cellX+2*cellY;
  467. if (border) {
  468. Bool doBorder = false;
  469. if (pCurVertices[vertex].y >= 0 && pCurVertices[vertex].y <= borderHiY) {
  470. if (pCurVertices[vertex].x == 0 || pCurVertices[vertex].x == borderHiX) {
  471. doBorder = true;
  472. }
  473. }
  474. if (pCurVertices[vertex].x >= 0 && pCurVertices[vertex].x <= borderHiX) {
  475. if (pCurVertices[vertex].y == 0 || pCurVertices[vertex].y == borderHiY) {
  476. doBorder = true;
  477. }
  478. }
  479. if (doBorder) {
  480. pCurVertices[vertex].diffuse &= 0xFF0000ff; // blue with alpha.
  481. }
  482. } else if (isCliff) {
  483. pCurVertices[vertex].diffuse &= 0xFFFF0000; // red with alpha.
  484. }
  485. if (cliffMapped && vertex==0) {
  486. pCurVertices[vertex].diffuse &= 0xFF000000; // Black.
  487. pCurVertices[vertex].diffuse |= 0xff00; // Add green.
  488. }
  489. }
  490. }
  491. }
  492. }
  493. // Note - We have been building the vertex buffer in the memory location.
  494. // Now copy the set of vertices into the hardware buffer.
  495. // We don't copy the whole vertex buffer because we often update only
  496. // a couple of rows and its a lot faster to just copy the ones that change.
  497. Int offset = pCurVertices - vBase;
  498. memcpy(vbHardware+offset, pCurVertices, 4*sizeof(VERTEX_FORMAT));
  499. }
  500. }
  501. return 0; //success.
  502. }
  503. return -1;
  504. }
  505. //=============================================================================
  506. // HeightMapRenderObjClass::updateVBForLight
  507. //=============================================================================
  508. /** Update the dynamic lighting values only in a rectangular block of the given Vertex Buffer.
  509. The vertex locations and texture coords are unchanged.
  510. */
  511. Int HeightMapRenderObjClass::updateVBForLight(DX8VertexBufferClass *pVB, char *data, Int x0, Int y0, Int x1, Int y1, Int originX, Int originY, W3DDynamicLight *pLights[], Int numLights)
  512. {
  513. #if (OPTIMIZED_HEIGHTMAP_LIGHTING) // (gth) if optimizations are enabled, jump over to the "optimized" version of this function.
  514. return updateVBForLightOptimized( pVB, data, x0, y0, x1, y1, originX, originY, pLights, numLights );
  515. #endif
  516. Int i,j,k;
  517. Int vn0,un0,vp1,up1;
  518. Vector3 l2r,n2f,normalAtTexel;
  519. Int vertsPerRow=(VERTEX_BUFFER_TILE_LENGTH)*4; //vertices per row of VB
  520. if (m_vertexBufferTiles && m_map)
  521. {
  522. #ifdef _DEBUG
  523. assert(x0 >= originX && y0 >= originY && x1>x0 && y1>y0 && x1<=originX+VERTEX_BUFFER_TILE_LENGTH && y1<=originY+VERTEX_BUFFER_TILE_LENGTH);
  524. #endif
  525. DX8VertexBufferClass::WriteLockClass lockVtxBuffer(pVB);
  526. VERTEX_FORMAT *vBase = (VERTEX_FORMAT*)lockVtxBuffer.Get_Vertex_Array();
  527. VERTEX_FORMAT *vb;
  528. for (j=y0; j<y1; j++)
  529. {
  530. if (HALF_RES_MESH) {
  531. if (j&1) continue;
  532. }
  533. Int yCoord = getYWithOrigin(j)+m_map->getDrawOrgY()-m_map->getBorderSizeInline();
  534. Bool intersect = false;
  535. for (k=0; k<numLights; k++) {
  536. if (pLights[k]->m_minY <= yCoord+1 &&
  537. pLights[k]->m_maxY >= yCoord) {
  538. intersect = true;
  539. }
  540. if (pLights[k]->m_prevMinY <= yCoord+1 &&
  541. pLights[k]->m_prevMaxY >= yCoord) {
  542. intersect = true;
  543. }
  544. }
  545. if (!intersect) {
  546. continue;
  547. }
  548. vn0 = getYWithOrigin(j)-1;
  549. if (vn0 < -m_map->getDrawOrgY())
  550. vn0=-m_map->getDrawOrgY();
  551. vp1 = getYWithOrigin(j+1)+1;
  552. if (vp1 >= m_map->getYExtent()-m_map->getDrawOrgY())
  553. vp1=m_map->getYExtent()-m_map->getDrawOrgY()-1;
  554. for (i=x0; i<x1; i++)
  555. {
  556. if (HALF_RES_MESH) {
  557. if (i&1) continue;
  558. }
  559. Int xCoord = getXWithOrigin(i)+m_map->getDrawOrgX()-m_map->getBorderSizeInline();
  560. Bool intersect = false;
  561. for (k=0; k<numLights; k++) {
  562. if (pLights[k]->m_minX <= xCoord+1 &&
  563. pLights[k]->m_maxX >= xCoord &&
  564. pLights[k]->m_minY <= yCoord+1 &&
  565. pLights[k]->m_maxY >= yCoord) {
  566. intersect = true;
  567. }
  568. if (pLights[k]->m_prevMinX <= xCoord+1 &&
  569. pLights[k]->m_prevMaxX >= xCoord &&
  570. pLights[k]->m_prevMinY <= yCoord+1 &&
  571. pLights[k]->m_prevMaxY >= yCoord) {
  572. intersect = true;
  573. }
  574. }
  575. if (!intersect) {
  576. continue;
  577. }
  578. // vb is the pointer to the vertex in the hardware dx8 vertex buffer.
  579. Int offset = (j-originY)*vertsPerRow+4*(i-originX);
  580. if (HALF_RES_MESH) {
  581. offset = (j-originY)*vertsPerRow/4+2*(i-originX);
  582. }
  583. vb = vBase + offset; //skip to correct row in vertex buffer
  584. // vbMirror is the pointer to the vertex in our memory based copy.
  585. // The important point is that we can read out of our copy to get the original
  586. // diffuse color, and xyz location. It is VERY SLOW to read out of the
  587. // hardware vertex buffer, possibly worse... jba.
  588. VERTEX_FORMAT *vbMirror = ((VERTEX_FORMAT*)data) + offset;
  589. un0 = getXWithOrigin(i)-1;
  590. if (un0 < -m_map->getDrawOrgX())
  591. un0=-m_map->getDrawOrgX();
  592. up1 = getXWithOrigin(i+1)+1;
  593. if (up1 >= m_map->getXExtent()-m_map->getDrawOrgX())
  594. up1=m_map->getXExtent()-m_map->getDrawOrgX()-1;
  595. Vector3 lightRay(0,0,0);
  596. //top-left sample
  597. l2r.Set(2*MAP_XY_FACTOR,0,MAP_HEIGHT_SCALE*(m_map->getDisplayHeight(getXWithOrigin(i)+1, getYWithOrigin(j)) - m_map->getDisplayHeight(un0, getYWithOrigin(j))));
  598. n2f.Set(0,2*MAP_XY_FACTOR,MAP_HEIGHT_SCALE*(m_map->getDisplayHeight(getXWithOrigin(i), (getYWithOrigin(j)+1)) - m_map->getDisplayHeight(getXWithOrigin(i), vn0)));
  599. #ifdef ALLOW_TEMPORARIES
  600. normalAtTexel= Normalize(Vector3::Cross_Product(l2r,n2f));
  601. #else
  602. Vector3::Normalized_Cross_Product(l2r, n2f, &normalAtTexel);
  603. #endif
  604. doTheDynamicLight(vb, vbMirror, &lightRay, &normalAtTexel, pLights, numLights);
  605. vb++; vbMirror++;
  606. //top-right sample
  607. l2r.Set(2*MAP_XY_FACTOR,0,MAP_HEIGHT_SCALE*(m_map->getDisplayHeight(up1 , getYWithOrigin(j) ) - m_map->getDisplayHeight(getXWithOrigin(i) , getYWithOrigin(j) )));
  608. n2f.Set(0,2*MAP_XY_FACTOR,MAP_HEIGHT_SCALE*(m_map->getDisplayHeight(getXWithOrigin(i)+1 , (getYWithOrigin(j)+1) ) - m_map->getDisplayHeight(getXWithOrigin(i)+1 , vn0 )));
  609. #ifdef ALLOW_TEMPORARIES
  610. normalAtTexel= Normalize(Vector3::Cross_Product(l2r,n2f));
  611. #else
  612. Vector3::Normalized_Cross_Product(l2r, n2f, &normalAtTexel);
  613. #endif
  614. doTheDynamicLight(vb, vbMirror, &lightRay, &normalAtTexel, pLights, numLights);
  615. vb++; vbMirror++;
  616. //bottom-right sample
  617. l2r.Set(2*MAP_XY_FACTOR,0,MAP_HEIGHT_SCALE*(m_map->getDisplayHeight(up1 , (getYWithOrigin(j)+1) ) - m_map->getDisplayHeight(getXWithOrigin(i) , (getYWithOrigin(j)+1) )));
  618. n2f.Set(0,2*MAP_XY_FACTOR,MAP_HEIGHT_SCALE*(m_map->getDisplayHeight(getXWithOrigin(i)+1 , vp1 ) - m_map->getDisplayHeight(getXWithOrigin(i)+1 , getYWithOrigin(j) )));
  619. #ifdef ALLOW_TEMPORARIES
  620. normalAtTexel= Normalize(Vector3::Cross_Product(l2r,n2f));
  621. #else
  622. Vector3::Normalized_Cross_Product(l2r, n2f, &normalAtTexel);
  623. #endif
  624. doTheDynamicLight(vb, vbMirror, &lightRay, &normalAtTexel, pLights, numLights);
  625. vb++; vbMirror++;
  626. //bottom-left sample
  627. l2r.Set(2*MAP_XY_FACTOR,0,MAP_HEIGHT_SCALE*(m_map->getDisplayHeight(getXWithOrigin(i)+1 , (getYWithOrigin(j)+1) ) - m_map->getDisplayHeight(un0 , (getYWithOrigin(j)+1) )));
  628. n2f.Set(0,2*MAP_XY_FACTOR,MAP_HEIGHT_SCALE*(m_map->getDisplayHeight(getXWithOrigin(i) , vp1 ) - m_map->getDisplayHeight(getXWithOrigin(i) , getYWithOrigin(j) )));
  629. #ifdef ALLOW_TEMPORARIES
  630. normalAtTexel= Normalize(Vector3::Cross_Product(l2r,n2f));
  631. #else
  632. Vector3::Normalized_Cross_Product(l2r, n2f, &normalAtTexel);
  633. #endif
  634. doTheDynamicLight(vb, vbMirror, &lightRay, &normalAtTexel, pLights, numLights);
  635. vb++; vbMirror++;
  636. }
  637. }
  638. return 0; //success.
  639. }
  640. return -1;
  641. }
  642. Int HeightMapRenderObjClass::updateVBForLightOptimized(DX8VertexBufferClass *pVB, char *data, Int x0, Int y0, Int x1, Int y1, Int originX, Int originY, W3DDynamicLight *pLights[], Int numLights)
  643. {
  644. Int i,j,k;
  645. Int vn0,un0,vp1,up1;
  646. Vector3 l2r,n2f,normalAtTexel;
  647. Int vertsPerRow=(VERTEX_BUFFER_TILE_LENGTH)*4; //vertices per row of VB
  648. if (m_vertexBufferTiles && m_map)
  649. {
  650. #ifdef _DEBUG
  651. assert(x0 >= originX && y0 >= originY && x1>x0 && y1>y0 && x1<=originX+VERTEX_BUFFER_TILE_LENGTH && y1<=originY+VERTEX_BUFFER_TILE_LENGTH);
  652. #endif
  653. DX8VertexBufferClass::WriteLockClass lockVtxBuffer(pVB);
  654. VERTEX_FORMAT *vBase = (VERTEX_FORMAT*)lockVtxBuffer.Get_Vertex_Array();
  655. VERTEX_FORMAT *vb;
  656. //
  657. // (gth) the optimization in this function is to take advantage of verts in the same
  658. // x,y position who have already computed their lighting. To do this, we need to set up
  659. // some offsets in the vertex buffer. I've computed these offsets to be consistent with
  660. // the formula's that Generals is using but in the case of the "half-res-mesh" I'm not
  661. // sure things are correct...
  662. //
  663. Int quad_right_offset;
  664. Int quad_below_offset;
  665. Int quad_below_right_offset;
  666. if (HALF_RES_MESH == false) {
  667. // offset = (j-originY)*vertsPerRow+4*(i-originX);
  668. quad_right_offset = 4;
  669. quad_below_offset = vertsPerRow;
  670. quad_below_right_offset = vertsPerRow + 4;
  671. } else {
  672. // offset = (j-originY)*vertsPerRow/4+2*(i-originX);
  673. quad_right_offset = 2;
  674. quad_below_offset = vertsPerRow/4;
  675. quad_below_right_offset = vertsPerRow/4 + 2;
  676. }
  677. //
  678. // i,j loop over the quads affected by the light. Each quad has its *own* 4 vertices. This
  679. // means that for any vertex position on the map, there are actually 4 copies of the vertex.
  680. //
  681. for (j=y0; j<y1; j++)
  682. {
  683. if (HALF_RES_MESH) {
  684. if (j&1) continue;
  685. }
  686. Int yCoord = getYWithOrigin(j)+m_map->getDrawOrgY()-m_map->getBorderSizeInline();
  687. Bool intersect = false;
  688. for (k=0; k<numLights; k++) {
  689. if (pLights[k]->m_minY <= yCoord+1 &&
  690. pLights[k]->m_maxY >= yCoord) {
  691. intersect = true;
  692. }
  693. if (pLights[k]->m_prevMinY <= yCoord+1 &&
  694. pLights[k]->m_prevMaxY >= yCoord) {
  695. intersect = true;
  696. }
  697. }
  698. if (!intersect) {
  699. continue;
  700. }
  701. vn0 = getYWithOrigin(j)-1;
  702. if (vn0 < -m_map->getDrawOrgY())
  703. vn0=-m_map->getDrawOrgY();
  704. vp1 = getYWithOrigin(j+1)+1;
  705. if (vp1 >= m_map->getYExtent()-m_map->getDrawOrgY())
  706. vp1=m_map->getYExtent()-m_map->getDrawOrgY()-1;
  707. for (i=x0; i<x1; i++)
  708. {
  709. if (HALF_RES_MESH) {
  710. if (i&1) continue;
  711. }
  712. Int xCoord = getXWithOrigin(i)+m_map->getDrawOrgX()-m_map->getBorderSizeInline();
  713. Bool intersect = false;
  714. for (k=0; k<numLights; k++) {
  715. if (pLights[k]->m_minX <= xCoord+1 &&
  716. pLights[k]->m_maxX >= xCoord &&
  717. pLights[k]->m_minY <= yCoord+1 &&
  718. pLights[k]->m_maxY >= yCoord) {
  719. intersect = true;
  720. }
  721. if (pLights[k]->m_prevMinX <= xCoord+1 &&
  722. pLights[k]->m_prevMaxX >= xCoord &&
  723. pLights[k]->m_prevMinY <= yCoord+1 &&
  724. pLights[k]->m_prevMaxY >= yCoord) {
  725. intersect = true;
  726. }
  727. }
  728. if (!intersect) {
  729. continue;
  730. }
  731. // vb is the pointer to the vertex in the hardware dx8 vertex buffer.
  732. Int offset = (j-originY)*vertsPerRow+4*(i-originX);
  733. if (HALF_RES_MESH) {
  734. offset = (j-originY)*vertsPerRow/4+2*(i-originX);
  735. }
  736. vb = vBase + offset; //skip to correct row in vertex buffer
  737. // vbMirror is the pointer to the vertex in our memory based copy.
  738. // The important point is that we can read out of our copy to get the original
  739. // diffuse color, and xyz location. It is VERY SLOW to read out of the
  740. // hardware vertex buffer, possibly worse... jba.
  741. VERTEX_FORMAT *vbMirror = ((VERTEX_FORMAT*)data) + offset;
  742. VERTEX_FORMAT *vbaseMirror = ((VERTEX_FORMAT*)data);
  743. un0 = getXWithOrigin(i)-1;
  744. if (un0 < -m_map->getDrawOrgX())
  745. un0=-m_map->getDrawOrgX();
  746. up1 = getXWithOrigin(i+1)+1;
  747. if (up1 >= m_map->getXExtent()-m_map->getDrawOrgX())
  748. up1=m_map->getXExtent()-m_map->getDrawOrgX()-1;
  749. Vector3 lightRay(0,0,0);
  750. //
  751. // (gth) Following the set of rules below lets us take advantage of lighting values that have
  752. // been previously computed. The idea is to copy them ahead to future quads that will need them
  753. // and then not compute them when we get to those quads. This also avoids having to read-back
  754. // from the vertex buffer but we do jump around in memory... probably bad anyway, maybe we should
  755. // compute into a temporary buffer and copy all at once...
  756. //
  757. unsigned long light_copy;
  758. // top-left sample -> only compute when i==0 and j==0
  759. if ((i==x0) && (j==y0)) {
  760. l2r.Set(2*MAP_XY_FACTOR,0,MAP_HEIGHT_SCALE*(m_map->getDisplayHeight(getXWithOrigin(i)+1, getYWithOrigin(j)) - m_map->getDisplayHeight(un0, getYWithOrigin(j))));
  761. n2f.Set(0,2*MAP_XY_FACTOR,MAP_HEIGHT_SCALE*(m_map->getDisplayHeight(getXWithOrigin(i), (getYWithOrigin(j)+1)) - m_map->getDisplayHeight(getXWithOrigin(i), vn0)));
  762. Vector3::Normalized_Cross_Product(l2r, n2f, &normalAtTexel);
  763. doTheDynamicLight(vb, vbMirror, &lightRay, &normalAtTexel, pLights, numLights);
  764. }
  765. vb++; vbMirror++;
  766. //top-right sample -> compute when j==0, then copy to (right,0)
  767. if (j==y0) {
  768. l2r.Set(2*MAP_XY_FACTOR,0,MAP_HEIGHT_SCALE*(m_map->getDisplayHeight(up1 , getYWithOrigin(j) ) - m_map->getDisplayHeight(getXWithOrigin(i) , getYWithOrigin(j) )));
  769. n2f.Set(0,2*MAP_XY_FACTOR,MAP_HEIGHT_SCALE*(m_map->getDisplayHeight(getXWithOrigin(i)+1 , (getYWithOrigin(j)+1) ) - m_map->getDisplayHeight(getXWithOrigin(i)+1 , vn0 )));
  770. Vector3::Normalized_Cross_Product(l2r, n2f, &normalAtTexel);
  771. light_copy = doTheDynamicLight(vb, vbMirror, &lightRay, &normalAtTexel, pLights, numLights);
  772. if (i < x1-1) {
  773. // copy light to (right,0)
  774. (vBase + offset + quad_right_offset)->diffuse = (light_copy&0x00FFFFFF) | ((vbaseMirror + offset + quad_right_offset)->diffuse&0xff000000) ;
  775. }
  776. }
  777. vb++; vbMirror++;
  778. //bottom-right sample -> always compute, then copy to (right,3), (down,1), (down+right,0)
  779. l2r.Set(2*MAP_XY_FACTOR,0,MAP_HEIGHT_SCALE*(m_map->getDisplayHeight(up1 , (getYWithOrigin(j)+1) ) - m_map->getDisplayHeight(getXWithOrigin(i) , (getYWithOrigin(j)+1) )));
  780. n2f.Set(0,2*MAP_XY_FACTOR,MAP_HEIGHT_SCALE*(m_map->getDisplayHeight(getXWithOrigin(i)+1 , vp1 ) - m_map->getDisplayHeight(getXWithOrigin(i)+1 , getYWithOrigin(j) )));
  781. Vector3::Normalized_Cross_Product(l2r, n2f, &normalAtTexel);
  782. light_copy = doTheDynamicLight(vb, vbMirror, &lightRay, &normalAtTexel, pLights, numLights);
  783. if (i < x1-1) {
  784. // copy light to (right,3)
  785. //(vBase + offset + quad_right_offset + 3)->diffuse = light_copy;
  786. (vBase + offset + quad_right_offset + 3)->diffuse = (light_copy&0x00FFFFFF) | ((vbaseMirror + offset + quad_right_offset + 3)->diffuse&0xff000000) ;
  787. }
  788. if (j < y1-1) {
  789. // copy light to (down,1)
  790. //(vBase + offset + quad_below_offset + 1)->diffuse = light_copy;
  791. (vBase + offset + quad_right_offset + 1)->diffuse = (light_copy&0x00FFFFFF) | ((vbaseMirror + offset + quad_right_offset + 1)->diffuse&0xff000000) ;
  792. }
  793. if ((i < x1-1) && (j < y1-1)) {
  794. // copy light to (right+down,0)
  795. //(vBase + offset + quad_below_right_offset)->diffuse = light_copy;
  796. (vBase + offset + quad_right_offset)->diffuse = (light_copy&0x00FFFFFF) | ((vbaseMirror + offset + quad_right_offset)->diffuse&0xff000000) ;
  797. }
  798. vb++; vbMirror++;
  799. //bottom-left sample -> compute when i==0, otherwise copy from (left,2)
  800. if (i==x0) {
  801. l2r.Set(2*MAP_XY_FACTOR,0,MAP_HEIGHT_SCALE*(m_map->getDisplayHeight(getXWithOrigin(i)+1 , (getYWithOrigin(j)+1) ) - m_map->getDisplayHeight(un0 , (getYWithOrigin(j)+1) )));
  802. n2f.Set(0,2*MAP_XY_FACTOR,MAP_HEIGHT_SCALE*(m_map->getDisplayHeight(getXWithOrigin(i) , vp1 ) - m_map->getDisplayHeight(getXWithOrigin(i) , getYWithOrigin(j) )));
  803. Vector3::Normalized_Cross_Product(l2r, n2f, &normalAtTexel);
  804. light_copy = doTheDynamicLight(vb, vbMirror, &lightRay, &normalAtTexel, pLights, numLights);
  805. if (j < y1-1) {
  806. // copy light to (down,0)
  807. //(vBase + offset + quad_below_offset)->diffuse = light_copy;
  808. (vBase + offset + quad_below_offset)->diffuse = (light_copy&0x00FFFFFF) | ((vbaseMirror + offset + quad_below_offset)->diffuse&0xff000000) ;
  809. }
  810. }
  811. vb++; vbMirror++;
  812. }
  813. }
  814. return 0; //success.
  815. }
  816. return -1;
  817. }
  818. //=============================================================================
  819. // HeightMapRenderObjClass::doPartialUpdate
  820. //=============================================================================
  821. /** Updates a partial block of vertices from [x0,y0 to x1,y1]
  822. The coordinates in partialRange are map cell coordinates, relative to the entire map.
  823. The vertex coordinates and texture coordinates, as well as static lighting are updated.
  824. */
  825. void HeightMapRenderObjClass::doPartialUpdate(const IRegion2D &partialRange, WorldHeightMap *htMap, RefRenderObjListIterator *pLightsIterator)
  826. {
  827. // Adjust range into the current drawn map range.
  828. Int minX = partialRange.lo.x - htMap->getDrawOrgX();
  829. Int maxX = partialRange.hi.x - htMap->getDrawOrgX();
  830. Int minY = partialRange.lo.y - htMap->getDrawOrgY();
  831. Int maxY = partialRange.hi.y - htMap->getDrawOrgY();
  832. if (minX<0) minX = 0;
  833. if (minY<0) minY = 0;
  834. if (maxX > m_x-1) maxX = m_x-1;
  835. if (maxY > m_y-1) maxY = m_y-1;
  836. if (maxX < minX) return;
  837. if (maxY < minY) return;
  838. if (m_originX == 0 && m_originY == 0) {
  839. // simple case.
  840. updateBlock(minX, minY, maxX, maxY,
  841. htMap, pLightsIterator);
  842. }
  843. else
  844. {
  845. minY = minY+m_originY;
  846. maxY = maxY+m_originY;
  847. if (minY> m_y-1) {
  848. minY -= m_y-1;
  849. maxY -= m_y-1;
  850. }
  851. if (maxY > m_y-1) {
  852. maxY -= m_y-1;
  853. updateBlock(0, minY, m_x-1, m_y-1, htMap, pLightsIterator);
  854. updateBlock(0, 0, m_x-1, maxY, htMap, pLightsIterator);
  855. } else {
  856. updateBlock(0, minY, m_x-1, maxY, htMap, pLightsIterator);
  857. }
  858. }
  859. if (!m_extraBlendTilePositions)
  860. { //Need to allocate memory
  861. m_extraBlendTilePositions = NEW Int[DEFAULT_MAX_MAP_EXTRABLEND_TILES];
  862. m_extraBlendTilePositionsSize = DEFAULT_MAX_MAP_EXTRABLEND_TILES;
  863. }
  864. //Find list of all extra blend tiles used on map. These are tiles with 3 materials/textures
  865. //over the same tile and require an extra render pass.
  866. Int i, j;
  867. //First remove any existing extra blend tiles within this partial region
  868. for (j=0; j<m_numExtraBlendTiles; j++)
  869. { Int x = m_extraBlendTilePositions[j] & 0xffff;
  870. Int y = m_extraBlendTilePositions[j] >> 16;
  871. if (x >= partialRange.lo.x && x < partialRange.hi.x &&
  872. y >= partialRange.lo.y && y < partialRange.hi.y)
  873. { //this tile is inside region being updated so remove it by shifting tile array
  874. memcpy(m_extraBlendTilePositions+j,m_extraBlendTilePositions+j+1,(m_numExtraBlendTiles-1-j)*sizeof(Int));
  875. m_numExtraBlendTiles--;
  876. j--; //need to look at index j again because this tile was removed
  877. }
  878. }
  879. for (j=partialRange.lo.y; j<partialRange.hi.y; j++)
  880. for (i=partialRange.lo.x; i<partialRange.hi.x; i++)
  881. {
  882. if (j<0 || i<0) continue;
  883. Real U[4],V[4];
  884. UnsignedByte alpha[4];
  885. Bool flipState,cliffState;
  886. if (htMap->getExtraAlphaUVData(i,j,U,V,alpha,&flipState, &cliffState))
  887. { if (m_numExtraBlendTiles >= m_extraBlendTilePositionsSize)
  888. { //no more room to store extra blend tiles so enlarge the buffer.
  889. Int *tempPositions=NEW Int[m_extraBlendTilePositionsSize+512];
  890. memcpy(tempPositions, m_extraBlendTilePositions, m_extraBlendTilePositionsSize*sizeof(Int));
  891. delete [] m_extraBlendTilePositions;
  892. //enlarge by more tiles to reduce memory trashing
  893. m_extraBlendTilePositions = tempPositions;
  894. m_extraBlendTilePositionsSize += 512;
  895. }
  896. //Pack x and y position into single integer since maps are limited in size
  897. m_extraBlendTilePositions[m_numExtraBlendTiles]=i | (j <<16);
  898. m_numExtraBlendTiles++;
  899. }
  900. }
  901. updateShorelineTiles(partialRange.lo.x,partialRange.lo.y,partialRange.hi.x,partialRange.hi.y,htMap);
  902. updateViewImpassableAreas(TRUE, minX, maxX, minY, maxY);
  903. }
  904. //=============================================================================
  905. // HeightMapRenderObjClass::updateBlock
  906. //=============================================================================
  907. /** Updates a block of vertices from [x0,y0 to x1,y1]
  908. The vertex coordinates and texture coordinates, as well as static lighting are updated.
  909. */
  910. Int HeightMapRenderObjClass::updateBlock(Int x0, Int y0, Int x1, Int y1, WorldHeightMap *pMap, RefRenderObjListIterator *pLightsIterator)
  911. {
  912. #ifdef _DEBUG
  913. DEBUG_ASSERTCRASH(x0>=0, ("HeightMapRenderObjClass::UpdateBlock parameters extend beyond left edge."));
  914. DEBUG_ASSERTCRASH(y0>=0, ("HeightMapRenderObjClass::UpdateBlock parameters extend beyond bottom edge."));
  915. DEBUG_ASSERTCRASH(x1<m_x, ("HeightMapRenderObjClass::UpdateBlock parameters extend beyond right edge."));
  916. DEBUG_ASSERTCRASH(y1<m_y, ("HeightMapRenderObjClass::UpdateBlock parameters extend beyond top edge."));
  917. DEBUG_ASSERTCRASH(x0<=x1, ("HeightMapRenderObjClass::UpdateBlock parameters have inside-out rectangle (on X)."));
  918. DEBUG_ASSERTCRASH(y0<=y1, ("HeightMapRenderObjClass::UpdateBlock parameters have inside-out rectangle (on Y)."));
  919. #endif
  920. Invalidate_Cached_Bounding_Volumes();
  921. if (pMap) {
  922. REF_PTR_SET(m_stageZeroTexture, pMap->getTerrainTexture());
  923. REF_PTR_SET(m_stageOneTexture, pMap->getAlphaTerrainTexture());
  924. }
  925. Int i,j;
  926. DX8VertexBufferClass **pVB;
  927. Int originX,originY;
  928. //step through each vertex buffer that needs updating
  929. for (j=0; j<m_numVBTilesY; j++)
  930. {
  931. originY=j*VERTEX_BUFFER_TILE_LENGTH; //location of this VB on the large full-size heightmap
  932. Int yMin, yMax;
  933. yMin = originY;
  934. if (y0>yMin) yMin = y0;
  935. yMax = originY+VERTEX_BUFFER_TILE_LENGTH;
  936. if (y1<yMax) yMax = y1;
  937. if (yMin >= yMax) {
  938. continue;
  939. }
  940. for (i=0; i<m_numVBTilesX; i++)
  941. {
  942. originX=i*VERTEX_BUFFER_TILE_LENGTH; //location of this VB on the large full-size heightmap
  943. Int xMin, xMax;
  944. xMin = originX;
  945. if (xMin<x0) xMin = x0;
  946. xMax = originX+VERTEX_BUFFER_TILE_LENGTH;
  947. if (xMax>x1) xMax = x1;
  948. if (xMin >= xMax) {
  949. continue;
  950. }
  951. pVB=m_vertexBufferTiles+j*m_numVBTilesX+i; //point to correct row/column of vertex buffers
  952. char **pData = m_vertexBufferBackup+j*m_numVBTilesX+i;
  953. updateVB(*pVB, *pData, xMin, yMin, xMax, yMax, originX, originY, pMap, pLightsIterator);
  954. }
  955. }
  956. return 0;
  957. }
  958. //-----------------------------------------------------------------------------
  959. // Public Functions
  960. //-----------------------------------------------------------------------------
  961. //=============================================================================
  962. // HeightMapRenderObjClass::~HeightMapRenderObjClass
  963. //=============================================================================
  964. /** Destructor. Releases w3d assets. */
  965. //=============================================================================
  966. HeightMapRenderObjClass::~HeightMapRenderObjClass(void)
  967. {
  968. freeMapResources();
  969. if (m_extraBlendTilePositions) {
  970. delete [] m_extraBlendTilePositions;
  971. m_extraBlendTilePositions = NULL;
  972. }
  973. }
  974. //=============================================================================
  975. // HeightMapRenderObjClass::HeightMapRenderObjClass
  976. //=============================================================================
  977. /** Constructor. Mostly nulls out the member variables. */
  978. //=============================================================================
  979. HeightMapRenderObjClass::HeightMapRenderObjClass(void):
  980. m_extraBlendTilePositions(NULL),
  981. m_numExtraBlendTiles(0),
  982. m_numVisibleExtraBlendTiles(0),
  983. m_extraBlendTilePositionsSize(0),
  984. m_vertexBufferTiles(NULL),
  985. m_vertexBufferBackup(NULL),
  986. m_originX(0),
  987. m_originY(0),
  988. m_indexBuffer(NULL),
  989. m_numVBTilesX(0),
  990. m_numVBTilesY(0),
  991. m_numVertexBufferTiles(0),
  992. m_numBlockColumnsInLastVB(0),
  993. m_numBlockRowsInLastVB(0)
  994. {
  995. TheHeightMap = this;
  996. }
  997. //=============================================================================
  998. // HeightMapRenderObjClass::adjustTerrainLOD
  999. //=============================================================================
  1000. /** Adjust the terrain Level Of Detail. If adj > 0 , increases LOD 1 step, if
  1001. adj < 0 decreases it one step, if adj==0, then just sets up for the current LOD */
  1002. //=============================================================================
  1003. void HeightMapRenderObjClass::adjustTerrainLOD(Int adj)
  1004. {
  1005. BaseHeightMapRenderObjClass::adjustTerrainLOD(adj);
  1006. return;
  1007. #if 0
  1008. if (adj>0 && TheGlobalData->m_terrainLOD<TERRAIN_LOD_MAX) TheWritableGlobalData->m_terrainLOD=(TerrainLOD)(TheGlobalData->m_terrainLOD+1);
  1009. if (adj<0 && TheGlobalData->m_terrainLOD>TERRAIN_LOD_MIN) TheWritableGlobalData->m_terrainLOD=(TerrainLOD)(TheGlobalData->m_terrainLOD-1);
  1010. switch (TheGlobalData->m_terrainLOD) {
  1011. case TERRAIN_LOD_MIN: TheWritableGlobalData->m_useCloudMap = false;
  1012. TheWritableGlobalData->m_useLightMap = false ;
  1013. TheWritableGlobalData->m_useWaterPlane = false;
  1014. TheWritableGlobalData->m_stretchTerrain = false;
  1015. TheWritableGlobalData->m_useHalfHeightMap = true;
  1016. break;
  1017. case TERRAIN_LOD_HALF_CLOUDS: TheWritableGlobalData->m_useCloudMap = true;
  1018. TheWritableGlobalData->m_useLightMap = true;
  1019. TheWritableGlobalData->m_useWaterPlane = false;
  1020. TheWritableGlobalData->m_stretchTerrain = false;
  1021. TheWritableGlobalData->m_useHalfHeightMap = true;
  1022. break;
  1023. case TERRAIN_LOD_STRETCH_NO_CLOUDS: TheWritableGlobalData->m_useCloudMap = false;
  1024. TheWritableGlobalData->m_useLightMap = false;
  1025. TheWritableGlobalData->m_useWaterPlane = false;
  1026. TheWritableGlobalData->m_stretchTerrain = true;
  1027. TheWritableGlobalData->m_useHalfHeightMap = false;
  1028. break;
  1029. case TERRAIN_LOD_STRETCH_CLOUDS: TheWritableGlobalData->m_useCloudMap = true;
  1030. TheWritableGlobalData->m_useLightMap = true;
  1031. TheWritableGlobalData->m_useWaterPlane = false;
  1032. TheWritableGlobalData->m_stretchTerrain = true;
  1033. TheWritableGlobalData->m_useHalfHeightMap = false;
  1034. break;
  1035. case TERRAIN_LOD_NO_CLOUDS: TheWritableGlobalData->m_useCloudMap = false;
  1036. TheWritableGlobalData->m_useLightMap = false;
  1037. TheWritableGlobalData->m_useWaterPlane = false;
  1038. TheWritableGlobalData->m_stretchTerrain = false;
  1039. TheWritableGlobalData->m_useHalfHeightMap = false;
  1040. break;
  1041. default:
  1042. case TERRAIN_LOD_NO_WATER: TheWritableGlobalData->m_useCloudMap = true;
  1043. TheWritableGlobalData->m_useLightMap = true;
  1044. TheWritableGlobalData->m_useWaterPlane = false;
  1045. TheWritableGlobalData->m_stretchTerrain = false;
  1046. TheWritableGlobalData->m_useHalfHeightMap = false;
  1047. break;
  1048. case TERRAIN_LOD_MAX: TheWritableGlobalData->m_useCloudMap = true;
  1049. TheWritableGlobalData->m_useLightMap = true;
  1050. TheWritableGlobalData->m_useWaterPlane = true;
  1051. TheWritableGlobalData->m_stretchTerrain = false;
  1052. TheWritableGlobalData->m_useHalfHeightMap = false;
  1053. break;
  1054. }
  1055. if (m_map==NULL) return;
  1056. m_map->setDrawOrg(m_map->getDrawOrgX(), m_map->getDrawOrgX());
  1057. if (m_shroud)
  1058. m_shroud->reset(); //need reset here since initHeightData will load new shroud.
  1059. this->initHeightData(m_map->getDrawWidth(),
  1060. m_map->getDrawHeight(), m_map, NULL);
  1061. staticLightingChanged();
  1062. if (TheTacticalView) {
  1063. TheTacticalView->setAngle(TheTacticalView->getAngle() + 1);
  1064. TheTacticalView->setAngle(TheTacticalView->getAngle() - 1);
  1065. }
  1066. #endif
  1067. }
  1068. //=============================================================================
  1069. // HeightMapRenderObjClass::ReleaseResources
  1070. //=============================================================================
  1071. /** Releases all w3d assets, to prepare for Reset device call. */
  1072. //=============================================================================
  1073. void HeightMapRenderObjClass::ReleaseResources(void)
  1074. {
  1075. BaseHeightMapRenderObjClass::ReleaseResources();
  1076. }
  1077. //=============================================================================
  1078. // HeightMapRenderObjClass::ReAcquireResources
  1079. //=============================================================================
  1080. /** Reallocates all W3D assets after a reset.. */
  1081. //=============================================================================
  1082. void HeightMapRenderObjClass::ReAcquireResources(void)
  1083. {
  1084. BaseHeightMapRenderObjClass::ReAcquireResources();
  1085. }
  1086. //=============================================================================
  1087. // HeightMapRenderObjClass::reset
  1088. //=============================================================================
  1089. /** Updates the macro noise/lightmap texture (pass 3) */
  1090. //=============================================================================
  1091. void HeightMapRenderObjClass::reset(void)
  1092. {
  1093. BaseHeightMapRenderObjClass::reset();
  1094. }
  1095. //=============================================================================
  1096. // HeightMapRenderObjClass::oversizeTerrain
  1097. //=============================================================================
  1098. /** Sets the terrain oversize amount. */
  1099. //=============================================================================
  1100. void HeightMapRenderObjClass::oversizeTerrain(Int tilesToOversize)
  1101. {
  1102. Int width = WorldHeightMap::NORMAL_DRAW_WIDTH;
  1103. Int height = WorldHeightMap::NORMAL_DRAW_HEIGHT;
  1104. if (tilesToOversize>0 && tilesToOversize<5)
  1105. {
  1106. width += 32*tilesToOversize;
  1107. height += 32*tilesToOversize;
  1108. if (width>m_map->getXExtent())
  1109. width = m_map->getXExtent();
  1110. if (height>m_map->getYExtent())
  1111. height = m_map->getYExtent();
  1112. }
  1113. Int dx = width-m_map->getDrawWidth();
  1114. Int dy = height-m_map->getDrawHeight();
  1115. m_map->setDrawWidth(width);
  1116. m_map->setDrawHeight(height);
  1117. dx /= 2;
  1118. dy /= 2;
  1119. Int newOrgX = m_map->getDrawOrgX()-dx;
  1120. Int newOrgy = m_map->getDrawOrgY()-dy;
  1121. if (newOrgX<0) newOrgX=0;
  1122. if (newOrgy<0) newOrgy=0;
  1123. m_map->setDrawOrg(newOrgX,newOrgy);
  1124. m_originX = 0;
  1125. m_originY = 0;
  1126. if (m_shroud)
  1127. m_shroud->reset();
  1128. //delete m_shroud;
  1129. //m_shroud = NULL;
  1130. initHeightData(m_map->getDrawWidth(), m_map->getDrawHeight(), m_map, NULL, FALSE);
  1131. m_needFullUpdate = true;
  1132. }
  1133. //=============================================================================
  1134. // HeightMapRenderObjClass::initHeightData
  1135. //=============================================================================
  1136. /** Allocate a heightmap of x by y vertices and fill with initial height values.
  1137. Also allocates all rendering resources such as vertex buffers, index buffers,
  1138. shaders, and materials.*/
  1139. //=============================================================================
  1140. Int HeightMapRenderObjClass::initHeightData(Int x, Int y, WorldHeightMap *pMap, RefRenderObjListIterator *pLightsIterator, Bool updateExtraPassTiles)
  1141. {
  1142. BaseHeightMapRenderObjClass::initHeightData(x, y, pMap, pLightsIterator, updateExtraPassTiles);
  1143. Int i,j;
  1144. // Int vertsPerRow=x*2-2;
  1145. // Int vertsPerColumn=y*2-2;
  1146. HeightSampleType *data = NULL;
  1147. if (pMap) {
  1148. data = pMap->getDataPtr();
  1149. }
  1150. if (updateExtraPassTiles)
  1151. {
  1152. m_numExtraBlendTiles = 0;
  1153. //Do some preprocessing on map to extract useful data
  1154. if (pMap)
  1155. {
  1156. Int m_mapDX=pMap->getXExtent();
  1157. Int m_mapDY=pMap->getYExtent();
  1158. if (!m_extraBlendTilePositions)
  1159. { //Need to allocate memory
  1160. m_extraBlendTilePositions = NEW Int[DEFAULT_MAX_MAP_EXTRABLEND_TILES];
  1161. m_extraBlendTilePositionsSize = DEFAULT_MAX_MAP_EXTRABLEND_TILES;
  1162. }
  1163. //Find list of all extra blend tiles used on map. These are tiles with 3 materials/textures
  1164. //over the same tile and require an extra render pass.
  1165. for (j=0; j<(m_mapDY-1); j++)
  1166. for (i=0; i<(m_mapDX-1); i++)
  1167. {
  1168. Real U[4],V[4];
  1169. UnsignedByte alpha[4];
  1170. Bool flipState,cliffState;
  1171. if (pMap->getExtraAlphaUVData(i,j,U,V,alpha,&flipState, &cliffState))
  1172. { if (m_numExtraBlendTiles >= m_extraBlendTilePositionsSize)
  1173. { //no more room to store extra blend tiles so enlarge the buffer.
  1174. Int *tempPositions=NEW Int[m_extraBlendTilePositionsSize+512];
  1175. memcpy(tempPositions, m_extraBlendTilePositions, m_extraBlendTilePositionsSize*sizeof(Int));
  1176. delete [] m_extraBlendTilePositions;
  1177. //enlarge by more tiles to reduce memory trashing
  1178. m_extraBlendTilePositions = tempPositions;
  1179. m_extraBlendTilePositionsSize += 512;
  1180. }
  1181. //Pack x and y position into single integer since maps are limited in size
  1182. m_extraBlendTilePositions[m_numExtraBlendTiles]=i | (j <<16);
  1183. m_numExtraBlendTiles++;
  1184. }
  1185. }
  1186. }
  1187. }
  1188. m_originX = 0;
  1189. m_originY = 0;
  1190. m_needFullUpdate = true;
  1191. // If the size changed, we need to allocate.
  1192. Bool needToAllocate = (x != m_x || y != m_y);
  1193. // If the textures aren't allocated (usually because of a hardware reset) need to allocate.
  1194. if (m_stageOneTexture == NULL) {
  1195. needToAllocate = true;
  1196. }
  1197. if (data && needToAllocate)
  1198. { //requested heightmap different from old one.
  1199. freeIndexVertexBuffers();
  1200. //Create static index buffers. These will index the vertex buffers holding the map.
  1201. m_indexBuffer=NEW_REF(DX8IndexBufferClass,(VERTEX_BUFFER_TILE_LENGTH*VERTEX_BUFFER_TILE_LENGTH*2*3));
  1202. // Fill up the IB
  1203. DX8IndexBufferClass::WriteLockClass lockIdxBuffer(m_indexBuffer);
  1204. UnsignedShort *ib=lockIdxBuffer.Get_Index_Array();
  1205. for (j=0; j<(VERTEX_BUFFER_TILE_LENGTH*VERTEX_BUFFER_TILE_LENGTH*4); j+=VERTEX_BUFFER_TILE_LENGTH*4)
  1206. {
  1207. for (i=j; i<(j+VERTEX_BUFFER_TILE_LENGTH*4); i+=4) //4 vertices per 2x2 block
  1208. {
  1209. ib[0]=i;
  1210. ib[1]=i+2;
  1211. ib[2]=i+3;
  1212. ib[3]=i;
  1213. ib[4]=i+1;
  1214. ib[5]=i+2;
  1215. ib+=6; //skip the 6 indices we just filled
  1216. }
  1217. }
  1218. //Get number of vertex buffers needed to hold current map
  1219. //First round dimensions to next multiple of VERTEX_BUFFER_TILE_LENGTH since that's our
  1220. //blocksize
  1221. m_numVBTilesX=1;
  1222. for (i=VERTEX_BUFFER_TILE_LENGTH+1; i<x;)
  1223. { i+=VERTEX_BUFFER_TILE_LENGTH;
  1224. m_numVBTilesX++;
  1225. }
  1226. m_numVBTilesY=1;
  1227. for (j=VERTEX_BUFFER_TILE_LENGTH+1; j<y;)
  1228. { j+=VERTEX_BUFFER_TILE_LENGTH;
  1229. m_numVBTilesY++;
  1230. }
  1231. m_numBlockColumnsInLastVB=(x-1)%VERTEX_BUFFER_TILE_LENGTH; //right border within last VB
  1232. m_numBlockRowsInLastVB=(y-1)%VERTEX_BUFFER_TILE_LENGTH; //bottom border within last VB
  1233. m_numVertexBufferTiles=m_numVBTilesX*m_numVBTilesY;
  1234. m_x=x;
  1235. m_y=y;
  1236. m_vertexBufferTiles = NEW DX8VertexBufferClass*[m_numVertexBufferTiles];
  1237. m_vertexBufferBackup = NEW char *[m_numVertexBufferTiles];
  1238. Int numVertex = VERTEX_BUFFER_TILE_LENGTH*2*VERTEX_BUFFER_TILE_LENGTH*2;
  1239. for (i=0; i<m_numVertexBufferTiles; i++) {
  1240. #ifdef USE_NORMALS
  1241. m_vertexBufferTiles[i]=NEW_REF(DX8VertexBufferClass,(DX8_FVF_XYZNUV2,numVertex,DX8VertexBufferClass::USAGE_DEFAULT));
  1242. #else
  1243. m_vertexBufferTiles[i]=NEW_REF(DX8VertexBufferClass,(DX8_VERTEX_FORMAT,numVertex,DX8VertexBufferClass::USAGE_DEFAULT));
  1244. #endif
  1245. m_vertexBufferBackup[i] = NEW char[numVertex*sizeof(VERTEX_FORMAT)];
  1246. }
  1247. //go with a preset material for now.
  1248. }
  1249. updateBlock(0,0,x-1,y-1,pMap,pLightsIterator);
  1250. return 0;
  1251. }
  1252. //=============================================================================
  1253. // HeightMapRenderObjClass::On_Frame_Update
  1254. //=============================================================================
  1255. /** Updates the diffuse color values in the vertices as affected by the dynamic lights.*/
  1256. //=============================================================================
  1257. void HeightMapRenderObjClass::On_Frame_Update(void)
  1258. {
  1259. BaseHeightMapRenderObjClass::On_Frame_Update();
  1260. Int i,j,k;
  1261. DX8VertexBufferClass **pVB;
  1262. Int originX,originY;
  1263. if (Scene==NULL) return;
  1264. RTS3DScene *pMyScene = (RTS3DScene *)Scene;
  1265. RefRenderObjListIterator pDynamicLightsIterator(pMyScene->getDynamicLights());
  1266. if (m_map == NULL) {
  1267. return;
  1268. }
  1269. #ifdef DO_UNIT_TIMINGS
  1270. #pragma MESSAGE("*** WARNING *** DOING DO_UNIT_TIMINGS!!!!")
  1271. return;
  1272. #endif
  1273. #ifdef EXTENDED_STATS
  1274. if (DX8Wrapper::stats.m_disableTerrain) {
  1275. return;
  1276. }
  1277. #endif
  1278. Int numDynaLights=0;
  1279. W3DDynamicLight *enabledLights[MAX_ENABLED_DYNAMIC_LIGHTS];
  1280. Int yCoordMin = m_map->getDrawOrgY();
  1281. Int yCoordMax = m_y+m_map->getDrawOrgY();
  1282. Int xCoordMin = m_map->getDrawOrgX();
  1283. Int xCoordMax = m_x+m_map->getDrawOrgX();
  1284. for (pDynamicLightsIterator.First(); !pDynamicLightsIterator.Is_Done(); pDynamicLightsIterator.Next())
  1285. {
  1286. W3DDynamicLight *pLight = (W3DDynamicLight*)pDynamicLightsIterator.Peek_Obj();
  1287. pLight->m_processMe = false;
  1288. if (pLight->m_enabled || pLight->m_priorEnable) {
  1289. Real range = pLight->Get_Attenuation_Range();
  1290. if (pLight->m_priorEnable) {
  1291. pLight->m_prevMinX = pLight->m_minX;
  1292. pLight->m_prevMinY = pLight->m_minY;
  1293. pLight->m_prevMaxX = pLight->m_maxX;
  1294. pLight->m_prevMaxY = pLight->m_maxY;
  1295. }
  1296. Vector3 pos = pLight->Get_Position();
  1297. pLight->m_minX = (pos.X-range)/MAP_XY_FACTOR;
  1298. pLight->m_maxX = (pos.X+range)/MAP_XY_FACTOR+1.0f;
  1299. pLight->m_minY = (pos.Y-range)/MAP_XY_FACTOR;
  1300. pLight->m_maxY = (pos.Y+range)/MAP_XY_FACTOR+1.0f;
  1301. if (!pLight->m_priorEnable) {
  1302. pLight->m_prevMinX = pLight->m_minX;
  1303. pLight->m_prevMinY = pLight->m_minY;
  1304. pLight->m_prevMaxX = pLight->m_maxX;
  1305. pLight->m_prevMaxY = pLight->m_maxY;
  1306. }
  1307. if (pLight->m_minX < xCoordMax &&
  1308. pLight->m_minY < yCoordMax &&
  1309. pLight->m_maxX > xCoordMin &&
  1310. pLight->m_maxY > yCoordMin) {
  1311. pLight->m_processMe = TRUE;
  1312. } else if (pLight->m_prevMinX < xCoordMax &&
  1313. pLight->m_prevMinY < yCoordMax &&
  1314. pLight->m_prevMaxX > xCoordMin &&
  1315. pLight->m_prevMaxY > yCoordMin) {
  1316. pLight->m_processMe = TRUE;
  1317. } else {
  1318. pLight->m_processMe = false;
  1319. }
  1320. if (pLight->m_processMe) {
  1321. enabledLights[numDynaLights] = pLight;
  1322. numDynaLights++;
  1323. if (numDynaLights == MAX_ENABLED_DYNAMIC_LIGHTS) {
  1324. break;
  1325. }
  1326. }
  1327. }
  1328. pLight->m_priorEnable = pLight->m_enabled;
  1329. }
  1330. if (numDynaLights > 0) {
  1331. //step through each vertex buffer that needs updating
  1332. for (j=0; j<m_numVBTilesY; j++)
  1333. {
  1334. originY=j*VERTEX_BUFFER_TILE_LENGTH; //location of this VB on the large full-size heightmap
  1335. Int yMin, yMax;
  1336. yMin = originY;
  1337. yMax = originY+VERTEX_BUFFER_TILE_LENGTH;
  1338. Bool intersect = false;
  1339. Int yCoordMin = getYWithOrigin(yMin)+m_map->getDrawOrgY()-m_map->getBorderSizeInline();
  1340. Int yCoordMax = getYWithOrigin(yMax-1)+m_map->getDrawOrgY()+1-m_map->getBorderSizeInline();
  1341. if (yCoordMax>yCoordMin) {
  1342. // no wrap occurred.
  1343. for (k=0; k<numDynaLights; k++) {
  1344. if (enabledLights[k]->m_minY < yCoordMax &&
  1345. enabledLights[k]->m_maxY > yCoordMin) {
  1346. intersect = true;
  1347. break;
  1348. }
  1349. if (enabledLights[k]->m_prevMinY < yCoordMax &&
  1350. enabledLights[k]->m_prevMaxY > yCoordMin) {
  1351. intersect = true;
  1352. break;
  1353. }
  1354. }
  1355. } else {
  1356. // wrap occurred, so we are outside of this range.
  1357. int tmp=yCoordMin;
  1358. yCoordMin = yCoordMax;
  1359. yCoordMax = tmp;
  1360. for (k=0; k<numDynaLights; k++) {
  1361. if (enabledLights[k]->m_minY <= yCoordMin ||
  1362. enabledLights[k]->m_maxY >= yCoordMax) {
  1363. intersect = true;
  1364. break;
  1365. }
  1366. if (enabledLights[k]->m_prevMinY <= yCoordMin ||
  1367. enabledLights[k]->m_prevMaxY >= yCoordMax) {
  1368. intersect = true;
  1369. break;
  1370. }
  1371. }
  1372. }
  1373. if (!intersect) {
  1374. continue;
  1375. }
  1376. for (i=0; i<m_numVBTilesX; i++)
  1377. {
  1378. originX=i*VERTEX_BUFFER_TILE_LENGTH; //location of this VB on the large full-size heightmap
  1379. Int xMin, xMax;
  1380. xMin = originX;
  1381. xMax = originX+VERTEX_BUFFER_TILE_LENGTH;
  1382. Bool intersect = false;
  1383. Int xCoordMin = getXWithOrigin(xMin)+m_map->getDrawOrgX()-m_map->getBorderSizeInline();
  1384. Int xCoordMax = getXWithOrigin(xMax-1)+m_map->getDrawOrgX()+1-m_map->getBorderSizeInline();
  1385. if (xCoordMax>xCoordMin) {
  1386. // no wrap occurred.
  1387. for (k=0; k<numDynaLights; k++) {
  1388. if (enabledLights[k]->m_minX < xCoordMax &&
  1389. enabledLights[k]->m_maxX > xCoordMin) {
  1390. intersect = true;
  1391. break;
  1392. }
  1393. if (enabledLights[k]->m_prevMinX < xCoordMax &&
  1394. enabledLights[k]->m_prevMaxX > xCoordMin) {
  1395. intersect = true;
  1396. break;
  1397. }
  1398. }
  1399. } else {
  1400. // wrap occurred, so we are outside of this range.
  1401. int tmp=xCoordMin;
  1402. xCoordMin = xCoordMax;
  1403. xCoordMax = tmp;
  1404. for (k=0; k<numDynaLights; k++) {
  1405. if (enabledLights[k]->m_minX <= xCoordMin ||
  1406. enabledLights[k]->m_maxX >= xCoordMax) {
  1407. intersect = true;
  1408. break;
  1409. }
  1410. if (enabledLights[k]->m_prevMinX <= xCoordMin ||
  1411. enabledLights[k]->m_prevMaxX >= xCoordMax) {
  1412. intersect = true;
  1413. break;
  1414. }
  1415. }
  1416. }
  1417. if (!intersect) {
  1418. continue;
  1419. }
  1420. pVB=m_vertexBufferTiles+j*m_numVBTilesX+i; //point to correct row/column of vertex buffers
  1421. char **pData = m_vertexBufferBackup+j*m_numVBTilesX+i;
  1422. updateVBForLight(*pVB, *pData, xMin, yMin, xMax, yMax, originX,originY, enabledLights, numDynaLights);
  1423. }
  1424. }
  1425. }
  1426. }
  1427. //=============================================================================
  1428. // HeightMapRenderObjClass::staticLightingChanged
  1429. //=============================================================================
  1430. /** Notification that all lighting needs to be recalculated. */
  1431. //=============================================================================
  1432. void HeightMapRenderObjClass::staticLightingChanged( void )
  1433. {
  1434. BaseHeightMapRenderObjClass::staticLightingChanged();
  1435. }
  1436. #define CENTER_LIMIT 2
  1437. #define BIG_JUMP 16
  1438. #define WIDE_STEP 32
  1439. static Int visMinX, visMinY, visMaxX, visMaxY;
  1440. static Bool check(const FrustumClass & frustum, WorldHeightMap *pMap, Int x, Int y)
  1441. {
  1442. if (x<0 || y<0) return(false);
  1443. if (x>= pMap->getXExtent() || y>= pMap->getYExtent()) return(false);
  1444. if (x >= visMinX && y >= visMinY && x <=visMaxX && y <= visMaxY) {
  1445. return(true);
  1446. }
  1447. Int height = pMap->getHeight(x, y);
  1448. Vector3 loc((x-pMap->getBorderSizeInline())*MAP_XY_FACTOR, (y-pMap->getBorderSizeInline())*MAP_XY_FACTOR, height*MAP_HEIGHT_SCALE);
  1449. if (CollisionMath::Overlap_Test(frustum,loc) == CollisionMath::INSIDE) {
  1450. if (x<visMinX) visMinX=x;
  1451. if (x>visMaxX) visMaxX=x;
  1452. if (y<visMinY) visMinY=y;
  1453. if (y>visMaxY) visMaxY=y;
  1454. return(true);
  1455. }
  1456. return(false);
  1457. }
  1458. static void calcVis(const FrustumClass & frustum, WorldHeightMap *pMap, Int minX, Int minY, Int maxX, Int maxY, Int limit)
  1459. {
  1460. if (maxX-minX<2) return;
  1461. if (maxY-minY<2) return;
  1462. if (minX >=visMinX && minY >= visMinY && maxX <=visMaxX && maxY <= visMaxY) {
  1463. return;
  1464. }
  1465. Int midX = (minX+maxX)/2;
  1466. Int midY = (minY+maxY)/2;
  1467. Bool recurse1 = maxX-minX>=limit;
  1468. Bool recurse2 = recurse1;
  1469. Bool recurse3 = recurse1;
  1470. Bool recurse4 = recurse1;
  1471. /* boxes are:
  1472. 1 2
  1473. 3 4 */
  1474. if (check(frustum, pMap, midX, maxY)) {
  1475. recurse1=true;
  1476. recurse2=true;
  1477. }
  1478. if (check(frustum, pMap, midX, minY)) {
  1479. recurse3=true;
  1480. recurse4=true;
  1481. }
  1482. if (check(frustum, pMap, midX, midY)) {
  1483. recurse1=true;
  1484. recurse2=true;
  1485. recurse3=true;
  1486. recurse4=true;
  1487. }
  1488. if (check(frustum, pMap, minX, midY)) {
  1489. recurse1=true;
  1490. recurse3=true;
  1491. }
  1492. if (check(frustum, pMap, maxX, midY)) {
  1493. recurse2=true;
  1494. recurse4=true;
  1495. }
  1496. if (recurse1) {
  1497. calcVis(frustum, pMap, minX, midY, midX, maxY, limit);
  1498. }
  1499. if (recurse2) {
  1500. calcVis(frustum, pMap, midX, midY, maxX, maxY, limit);
  1501. }
  1502. if (recurse3) {
  1503. calcVis(frustum, pMap, minX, minY, midX, midY, limit);
  1504. }
  1505. if (recurse4) {
  1506. calcVis(frustum, pMap, midX, minY, maxX, midY, limit);
  1507. }
  1508. }
  1509. //=============================================================================
  1510. // HeightMapRenderObjClass::updateCenter
  1511. //=============================================================================
  1512. /** Updates the positioning of the drawn portion of the height map in the
  1513. heightmap. As the view slides around, this determines what is the actually
  1514. rendered portion of the terrain. Only a 96x96 section is rendered at any time,
  1515. even though maps can be up to 1024x1024. This function determines which subset
  1516. is rendered. */
  1517. //=============================================================================
  1518. void HeightMapRenderObjClass::updateCenter(CameraClass *camera , RefRenderObjListIterator *pLightsIterator)
  1519. {
  1520. if (m_map==NULL) {
  1521. return;
  1522. }
  1523. if (m_updating) {
  1524. return;
  1525. }
  1526. if (m_vertexBufferTiles ==NULL)
  1527. return; //did not initialize resources yet.
  1528. BaseHeightMapRenderObjClass::updateCenter(camera, pLightsIterator);
  1529. m_updating = true;
  1530. if (m_needFullUpdate)
  1531. {
  1532. m_needFullUpdate = false;
  1533. updateBlock(0, 0, m_x-1, m_y-1, m_map, pLightsIterator);
  1534. m_updating = false;
  1535. return;
  1536. }
  1537. if (m_x >= m_map->getXExtent() && m_y >= m_map->getYExtent())
  1538. {
  1539. m_updating = false;
  1540. return; // no need to center.
  1541. }
  1542. Int cellOffset = 1;
  1543. if (HALF_RES_MESH) {
  1544. cellOffset = 2;
  1545. }
  1546. // determine the ray corresponding to the camera and distance to projection plane
  1547. Matrix3D camera_matrix = camera->Get_Transform();
  1548. Vector3 camera_location = camera->Get_Position();
  1549. Vector3 rayLocation;
  1550. Vector3 rayDirection;
  1551. Vector3 rayDirectionPt;
  1552. // the projected ray has the same origin as the camera
  1553. rayLocation = camera_location;
  1554. // determine the location of the screen coordinate in camera-model space
  1555. const ViewportClass &viewport = camera->Get_Viewport();
  1556. Int i, j, minHt;
  1557. Real intersectionZ;
  1558. minHt = m_map->getMaxHeightValue();
  1559. for (i=0; i<m_x; i++) {
  1560. for (j=0; j<m_y; j++) {
  1561. Short cur = m_map->getDisplayHeight(i,j);
  1562. if (cur<minHt) minHt = cur;
  1563. }
  1564. }
  1565. intersectionZ = (float)minHt;
  1566. // float aspect = camera->Get_Aspect_Ratio();
  1567. Vector2 min,max;
  1568. camera->Get_View_Plane(min,max);
  1569. float xscale = (max.X - min.X);
  1570. float yscale = (max.Y - min.Y);
  1571. float zmod = -1.0; // Scene->vpd; // Note: view plane distance is now always 1.0 from the camera
  1572. float minX = 200000;
  1573. float maxX = -minX;
  1574. float minY = 200000;
  1575. float maxY = -minY;
  1576. for (i=0; i<2; i++) {
  1577. for (j=0; j<2; j++) {
  1578. float xmod = (-i + 0.5 + viewport.Min.X) * zmod * xscale;// / aspect;
  1579. float ymod = (j - 0.5 - viewport.Min.Y) * zmod * yscale;// * aspect;
  1580. // transform the screen coordinates by the camera's matrix into world coordinates.
  1581. float x = zmod * camera_matrix[0][2] + xmod * camera_matrix[0][0] + ymod * camera_matrix[0][1];
  1582. float y = zmod * camera_matrix[1][2] + xmod * camera_matrix[1][0] + ymod * camera_matrix[1][1];
  1583. float z = zmod * camera_matrix[2][2] + xmod * camera_matrix[2][0] + ymod * camera_matrix[2][1];
  1584. rayDirection.Set(x,y,z);
  1585. rayDirection.Normalize();
  1586. rayDirectionPt = rayLocation+rayDirection;
  1587. x = Vector3::Find_X_At_Z(intersectionZ, rayLocation, rayDirectionPt);
  1588. y = Vector3::Find_Y_At_Z(intersectionZ, rayLocation, rayDirectionPt);
  1589. if (x<minX) minX = x;
  1590. if (x>maxX) maxX = x;
  1591. if (y<minY) minY = y;
  1592. if (y>maxY) maxY = y;
  1593. }
  1594. }
  1595. // convert back to cell indexes.
  1596. minX /= MAP_XY_FACTOR;
  1597. maxX /= MAP_XY_FACTOR;
  1598. minY /= MAP_XY_FACTOR;
  1599. maxY /= MAP_XY_FACTOR;
  1600. minX += m_map->getBorderSizeInline();
  1601. maxX += m_map->getBorderSizeInline();
  1602. minY += m_map->getBorderSizeInline();
  1603. maxY += m_map->getBorderSizeInline();
  1604. visMinX = m_map->getXExtent();
  1605. visMinY = m_map->getYExtent();
  1606. visMaxX = 0;
  1607. visMaxY = 0;
  1608. ///< @todo find out why values go out of range
  1609. if (minX<0) minX=0;
  1610. if (minY<0) minY=0;
  1611. if (maxX > visMinX) maxX = visMinX;
  1612. if (maxY > visMinY) maxY = visMinY;
  1613. const FrustumClass & frustum = camera->Get_Frustum();
  1614. Int limit = (maxX-minX)/2;
  1615. if (limit > WIDE_STEP/2) {
  1616. limit=WIDE_STEP/2;
  1617. }
  1618. calcVis(frustum, m_map, minX-WIDE_STEP/2, minY-WIDE_STEP/2, maxX+WIDE_STEP/2, maxY+WIDE_STEP/2, limit);
  1619. if (m_map) {
  1620. Int newOrgX;
  1621. if (visMaxX-visMinX > m_x) {
  1622. newOrgX = (maxX+minX)/2-m_x/2.0;
  1623. } else {
  1624. newOrgX = (visMaxX+visMinX)/2-m_x/2.0;
  1625. }
  1626. Int newOrgY;
  1627. if (visMaxY - visMinY > m_y) {
  1628. newOrgY = visMinY+1;
  1629. } else {
  1630. newOrgY = (visMaxY+visMinY)/2-m_y/2.0;
  1631. }
  1632. if (TheTacticalView->getFieldOfView() != 0) {
  1633. newOrgX = (visMaxX+visMinX)/2-m_x/2.0;
  1634. newOrgY = (visMaxY+visMinY)/2-m_y/2.0;
  1635. }
  1636. if (HALF_RES_MESH) {
  1637. newOrgX &= 0xFFFFFFFE;
  1638. newOrgY &= 0xFFFFFFFE;
  1639. }
  1640. Int deltaX = newOrgX - m_map->getDrawOrgX();
  1641. Int deltaY = newOrgY - m_map->getDrawOrgY();
  1642. if (IABS(deltaX) > m_x/2 || IABS(deltaY)>m_x/2) {
  1643. m_map->setDrawOrg(newOrgX, newOrgY);
  1644. m_originY = 0;
  1645. m_originX = 0;
  1646. updateBlock(0, 0, m_x-1, m_y-1, m_map, pLightsIterator);
  1647. m_updating = false;
  1648. return;
  1649. }
  1650. if (abs(deltaX)>CENTER_LIMIT || abs(deltaY)>CENTER_LIMIT) {
  1651. if (abs(deltaY) >= CENTER_LIMIT) {
  1652. if (m_map->setDrawOrg(m_map->getDrawOrgX(), newOrgY)) {
  1653. Int minY = 0;
  1654. Int maxY = 0;
  1655. deltaY -= newOrgY - m_map->getDrawOrgY();
  1656. m_originY += deltaY;
  1657. if (m_originY >= m_y-1) m_originY -= m_y-1;
  1658. if (deltaY<0) {
  1659. minY = m_originY;
  1660. maxY = m_originY-deltaY;
  1661. } else {
  1662. minY = m_originY - deltaY;
  1663. maxY = m_originY;
  1664. }
  1665. minY-=cellOffset;
  1666. if (m_originY < 0) m_originY += m_y-1;
  1667. if (minY<0) {
  1668. minY += m_y-1;
  1669. if (minY<0) minY = 0;
  1670. updateBlock(0, minY, m_x-1, m_y-1, m_map, pLightsIterator);
  1671. updateBlock(0, 0, m_x-1, maxY, m_map, pLightsIterator);
  1672. } else {
  1673. updateBlock(0, minY, m_x-1, maxY, m_map, pLightsIterator);
  1674. }
  1675. }
  1676. // It is much more efficient to update a cople of columns one frame, and then
  1677. // a couple of rows. So if we aren't "jumping" to a new view, and have done X
  1678. // recently, return.
  1679. if (abs(deltaX) < BIG_JUMP && !m_doXNextTime) {
  1680. m_updating = false;
  1681. m_doXNextTime = true;
  1682. return; // Only do the y this frame. Do x next frame. jba.
  1683. }
  1684. }
  1685. if (abs(deltaX) > CENTER_LIMIT) {
  1686. m_doXNextTime = false;
  1687. newOrgX = m_map->getDrawOrgX() + deltaX;
  1688. if (m_map->setDrawOrg(newOrgX, m_map->getDrawOrgY())) {
  1689. Int minX = 0;
  1690. Int maxX = 0;
  1691. deltaX -= newOrgX - m_map->getDrawOrgX();
  1692. m_originX += deltaX;
  1693. if (m_originX >= m_x-1) m_originX -= m_x-1;
  1694. if (deltaX<0) {
  1695. minX = m_originX;
  1696. maxX = m_originX-deltaX;
  1697. } else {
  1698. minX = m_originX - deltaX;
  1699. maxX = m_originX;
  1700. }
  1701. minX-=cellOffset;
  1702. maxX+=cellOffset;
  1703. if (m_originX < 0) m_originX += m_x-1;
  1704. if (minX<0) {
  1705. minX += m_x-1;
  1706. if (minX<0) minX = 0;
  1707. updateBlock(minX,0,m_x-1, m_y-1, m_map, pLightsIterator);
  1708. updateBlock(0,0,maxX, m_y-1, m_map, pLightsIterator);
  1709. } else {
  1710. updateBlock(minX,0,maxX, m_y-1, m_map, pLightsIterator);
  1711. }
  1712. }
  1713. }
  1714. }
  1715. }
  1716. m_updating = false;
  1717. }
  1718. //=============================================================================
  1719. // HeightMapRenderObjClass::Render
  1720. //=============================================================================
  1721. /** Renders (draws) the terrain. */
  1722. //=============================================================================
  1723. //DECLARE_PERF_TIMER(Terrain_Render)
  1724. void HeightMapRenderObjClass::Render(RenderInfoClass & rinfo)
  1725. {
  1726. //USE_PERF_TIMER(Terrain_Render)
  1727. Int i,j,devicePasses;
  1728. W3DShaderManager::ShaderTypes st;
  1729. Bool doCloud = TheGlobalData->m_useCloudMap;
  1730. Matrix3D tm(Transform);
  1731. #if 0 // There is some weirdness sometimes with the dx8 static buffers.
  1732. // This usually fixes terrain flashing. jba.
  1733. static Int delay = 1;
  1734. delay --;
  1735. if (delay<1) {
  1736. delay = 1;
  1737. static Int ndx = -1;
  1738. ndx++;
  1739. if (ndx>=m_numVertexBufferTiles) {
  1740. ndx = 0;
  1741. }
  1742. DX8VertexBufferClass::WriteLockClass lockVtxBuffer(m_vertexBufferTiles[ndx]);
  1743. VERTEX_FORMAT *vb = (VERTEX_FORMAT*)lockVtxBuffer.Get_Vertex_Array();
  1744. vb = 0;
  1745. }
  1746. #endif
  1747. // If there are trees, tell them to draw at the transparent time to draw.
  1748. if (m_treeBuffer) {
  1749. m_treeBuffer->setIsTerrain();
  1750. }
  1751. #ifdef DO_UNIT_TIMINGS
  1752. #pragma MESSAGE("*** WARNING *** DOING DO_UNIT_TIMINGS!!!!")
  1753. return;
  1754. #endif
  1755. #ifdef EXTENDED_STATS
  1756. if (DX8Wrapper::stats.m_disableTerrain) {
  1757. return;
  1758. }
  1759. #endif
  1760. DX8Wrapper::Set_Light_Environment(rinfo.light_environment);
  1761. // Force shaders to update.
  1762. m_stageTwoTexture->restore();
  1763. DX8Wrapper::Set_Texture(0,NULL);
  1764. DX8Wrapper::Set_Texture(1,NULL);
  1765. ShaderClass::Invalidate();
  1766. // tm.Scale(ObjSpaceExtent);
  1767. DX8Wrapper::Set_Transform(D3DTS_WORLD,tm);
  1768. //Apply the shader and material
  1769. DX8Wrapper::Set_Index_Buffer(m_indexBuffer,0);
  1770. Bool doMultiPassWireFrame=FALSE;
  1771. if (((RTS3DScene *)rinfo.Camera.Get_User_Data())->getCustomPassMode() == SCENE_PASS_ALPHA_MASK ||
  1772. ((SceneClass *)rinfo.Camera.Get_User_Data())->Get_Extra_Pass_Polygon_Mode() == SceneClass::EXTRA_PASS_CLEAR_LINE)
  1773. {
  1774. if (WW3D::Is_Texturing_Enabled())
  1775. { //first pass where we just fill the z-buffer
  1776. devicePasses=1; //one pass solid, next in wireframe.
  1777. doMultiPassWireFrame=TRUE;
  1778. if (rinfo.Additional_Pass_Count())
  1779. {
  1780. rinfo.Peek_Additional_Pass(0)->Install_Materials();
  1781. renderTerrainPass(&rinfo.Camera);
  1782. rinfo.Peek_Additional_Pass(0)->UnInstall_Materials();
  1783. return;
  1784. }
  1785. }
  1786. else
  1787. { //wireframe pass
  1788. //Set to vertex diffuse lighting
  1789. DX8Wrapper::Set_Material(m_vertexMaterialClass);
  1790. //Set shader to non-textured solid color from vertex
  1791. DX8Wrapper::Set_Shader(ShaderClass::_PresetOpaqueSolidShader);
  1792. devicePasses=1; //one pass solid, next in wireframe.
  1793. DX8Wrapper::Apply_Render_State_Changes();
  1794. DX8Wrapper::Set_DX8_Texture_Stage_State( 0, D3DTSS_COLORARG2, D3DTA_TFACTOR );
  1795. DX8Wrapper::Set_DX8_Render_State(D3DRS_TEXTUREFACTOR,0xff808080);
  1796. doMultiPassWireFrame=TRUE;
  1797. renderTerrainPass(&rinfo.Camera);
  1798. DX8Wrapper::Set_DX8_Render_State(D3DRS_TEXTUREFACTOR,0xff008000);
  1799. return;
  1800. }
  1801. }
  1802. else
  1803. {
  1804. DX8Wrapper::Set_Material(m_vertexMaterialClass);
  1805. DX8Wrapper::Set_Shader(m_shaderClass);
  1806. if (TheGlobalData->m_timeOfDay == TIME_OF_DAY_NIGHT) {
  1807. doCloud = false;
  1808. }
  1809. st=W3DShaderManager::ST_TERRAIN_BASE; //set default shader
  1810. //set correct shader based on current settings
  1811. if (!ShaderClass::Is_Backface_Culling_Inverted())
  1812. { //not reflection pass
  1813. if (TheGlobalData->m_useLightMap && doCloud)
  1814. { st=W3DShaderManager::ST_TERRAIN_BASE_NOISE12;
  1815. }
  1816. else
  1817. if (TheGlobalData->m_useLightMap)
  1818. { //lightmap only
  1819. st=W3DShaderManager::ST_TERRAIN_BASE_NOISE2;
  1820. }
  1821. else
  1822. if (doCloud)
  1823. { //cloudmap only
  1824. st=W3DShaderManager::ST_TERRAIN_BASE_NOISE1;
  1825. }
  1826. }
  1827. else
  1828. { //reflection pass, just do base texture
  1829. st=W3DShaderManager::ST_TERRAIN_BASE;
  1830. }
  1831. //Find number of passes required to render current shader
  1832. devicePasses=W3DShaderManager::getShaderPasses(st);
  1833. if (m_disableTextures)
  1834. devicePasses=1; //force to 1 lighting-only pass
  1835. //Specify all textures that this shader may need.
  1836. W3DShaderManager::setTexture(0,m_stageZeroTexture);
  1837. W3DShaderManager::setTexture(1,m_stageZeroTexture);
  1838. W3DShaderManager::setTexture(2,m_stageTwoTexture); //cloud
  1839. W3DShaderManager::setTexture(3,m_stageThreeTexture);//noise
  1840. //Disable writes to destination alpha channel (if there is one)
  1841. if (DX8Wrapper::getBackBufferFormat() == WW3D_FORMAT_A8R8G8B8)
  1842. DX8Wrapper::Set_DX8_Render_State(D3DRS_COLORWRITEENABLE,D3DCOLORWRITEENABLE_BLUE|D3DCOLORWRITEENABLE_GREEN|D3DCOLORWRITEENABLE_RED);
  1843. }
  1844. Int pass;
  1845. for (pass=0; pass<devicePasses; pass++) {
  1846. #ifdef TIMING_TESTS
  1847. #endif
  1848. if (!doMultiPassWireFrame) //multi-pass wireframe doesn't use regular shaders.
  1849. {
  1850. if (m_disableTextures ) {
  1851. DX8Wrapper::Set_Shader(ShaderClass::_PresetOpaque2DShader);
  1852. DX8Wrapper::Set_Texture(0,NULL);
  1853. } else {
  1854. W3DShaderManager::setShader(st, pass);
  1855. }
  1856. }
  1857. for (j=0; j<m_numVBTilesY; j++)
  1858. for (i=0; i<m_numVBTilesX; i++)
  1859. {
  1860. static int count = 0;
  1861. count++;
  1862. Int numPolys = VERTEX_BUFFER_TILE_LENGTH*VERTEX_BUFFER_TILE_LENGTH*2;
  1863. Int numVertex = (VERTEX_BUFFER_TILE_LENGTH*2)*(VERTEX_BUFFER_TILE_LENGTH*2);
  1864. if (HALF_RES_MESH) {
  1865. numPolys /= 4;
  1866. numVertex /= 4;
  1867. }
  1868. DX8Wrapper::Set_Vertex_Buffer(m_vertexBufferTiles[j*m_numVBTilesX+i]);
  1869. #ifdef PRE_TRANSFORM_VERTEX
  1870. if (m_xformedVertexBuffer && pass==0) {
  1871. // Note - m_xformedVertexBuffer should only be used for non T&L hardware. jba.
  1872. DX8Wrapper::Apply_Render_State_Changes();
  1873. int code = DX8Wrapper::_Get_D3D_Device8()->ProcessVertices(0, 0, numVertex, m_xformedVertexBuffer[j*m_numVBTilesX+i], 0);
  1874. ::OutputDebugString("did process vertex\n");
  1875. }
  1876. if (m_xformedVertexBuffer) {
  1877. // Note - m_xformedVertexBuffer should only be used for non T&L hardware. jba.
  1878. DX8Wrapper::Apply_Render_State_Changes();
  1879. DX8Wrapper::_Get_D3D_Device8()->SetStreamSource(
  1880. 0,
  1881. m_xformedVertexBuffer[j*m_numVBTilesX+i],
  1882. D3DXGetFVFVertexSize(D3DFVF_XYZRHW |D3DFVF_DIFFUSE|D3DFVF_TEX2));
  1883. DX8Wrapper::_Get_D3D_Device8()->SetVertexShader(D3DFVF_XYZRHW |D3DFVF_DIFFUSE|D3DFVF_TEX2);
  1884. }
  1885. #endif
  1886. if (Is_Hidden() == 0) {
  1887. DX8Wrapper::Draw_Triangles( 0,numPolys, 0, numVertex);
  1888. }
  1889. }
  1890. }
  1891. if (!doMultiPassWireFrame)
  1892. {
  1893. if (pass) //shader was applied at least once?
  1894. W3DShaderManager::resetShader(st);
  1895. //Draw feathered shorelines
  1896. renderShoreLines(&rinfo.Camera);
  1897. //Do additional pass over any tiles that have 3 textures blended together.
  1898. if (TheGlobalData->m_use3WayTerrainBlends)
  1899. renderExtraBlendTiles();
  1900. Int yCoordMin = m_map->getDrawOrgY();
  1901. Int yCoordMax = m_y+m_map->getDrawOrgY()-1;
  1902. Int xCoordMin = m_map->getDrawOrgX();
  1903. Int xCoordMax = m_x+m_map->getDrawOrgX()-1;
  1904. #ifdef TEST_CUSTOM_EDGING
  1905. // Draw edging just before last pass.
  1906. DX8Wrapper::Set_Texture(0,NULL);
  1907. DX8Wrapper::Set_Texture(1,NULL);
  1908. m_stageTwoTexture->restore();
  1909. m_customEdging->drawEdging(m_map, xCoordMin, xCoordMax, yCoordMin, yCoordMax,
  1910. m_stageZeroTexture, doCloud?m_stageTwoTexture:NULL, TheGlobalData->m_useLightMap?m_stageThreeTexture:NULL);
  1911. #endif
  1912. #ifdef DO_ROADS
  1913. DX8Wrapper::Set_Texture(0,NULL);
  1914. DX8Wrapper::Set_Texture(1,NULL);
  1915. m_stageTwoTexture->restore();
  1916. ShaderClass::Invalidate();
  1917. if (!ShaderClass::Is_Backface_Culling_Inverted()) {
  1918. DX8Wrapper::Set_Material(m_vertexMaterialClass);
  1919. if (Scene) {
  1920. RTS3DScene *pMyScene = (RTS3DScene *)Scene;
  1921. RefRenderObjListIterator pDynamicLightsIterator(pMyScene->getDynamicLights());
  1922. m_roadBuffer->drawRoads(&rinfo.Camera, doCloud?m_stageTwoTexture:NULL, TheGlobalData->m_useLightMap?m_stageThreeTexture:NULL,
  1923. m_disableTextures,xCoordMin-m_map->getBorderSizeInline(), xCoordMax-m_map->getBorderSizeInline(), yCoordMin-m_map->getBorderSizeInline(), yCoordMax-m_map->getBorderSizeInline(), &pDynamicLightsIterator);
  1924. }
  1925. }
  1926. #endif
  1927. if (m_propBuffer) {
  1928. m_propBuffer->drawProps(rinfo);
  1929. }
  1930. #ifdef DO_SCORCH
  1931. DX8Wrapper::Set_Texture(0,NULL);
  1932. DX8Wrapper::Set_Texture(1,NULL);
  1933. m_stageTwoTexture->restore();
  1934. ShaderClass::Invalidate();
  1935. if (!ShaderClass::Is_Backface_Culling_Inverted()) {
  1936. drawScorches();
  1937. }
  1938. #endif
  1939. DX8Wrapper::Set_Texture(0,NULL);
  1940. DX8Wrapper::Set_Texture(1,NULL);
  1941. m_stageTwoTexture->restore();
  1942. ShaderClass::Invalidate();
  1943. DX8Wrapper::Apply_Render_State_Changes();
  1944. m_bridgeBuffer->drawBridges(&rinfo.Camera, m_disableTextures, doCloud?m_stageTwoTexture:NULL);
  1945. if (TheTerrainTracksRenderObjClassSystem)
  1946. TheTerrainTracksRenderObjClassSystem->flush();
  1947. if (m_shroud && rinfo.Additional_Pass_Count())
  1948. {
  1949. rinfo.Peek_Additional_Pass(0)->Install_Materials();
  1950. renderTerrainPass(&rinfo.Camera);
  1951. rinfo.Peek_Additional_Pass(0)->UnInstall_Materials();
  1952. }
  1953. ShaderClass::Invalidate();
  1954. DX8Wrapper::Apply_Render_State_Changes();
  1955. }
  1956. else
  1957. m_bridgeBuffer->drawBridges(&rinfo.Camera, m_disableTextures, m_stageTwoTexture);
  1958. if ( m_waypointBuffer )
  1959. m_waypointBuffer->drawWaypoints(rinfo);
  1960. m_bibBuffer->renderBibs();
  1961. // We do some custom blending, so tell the shader class to reset everything.
  1962. DX8Wrapper::Set_Texture(0,NULL);
  1963. DX8Wrapper::Set_Texture(1,NULL);
  1964. m_stageTwoTexture->restore();
  1965. ShaderClass::Invalidate();
  1966. DX8Wrapper::Set_Material(NULL);
  1967. }
  1968. ///Performs additional terrain rendering pass, blending in the black shroud texture.
  1969. void HeightMapRenderObjClass::renderTerrainPass(CameraClass *pCamera)
  1970. {
  1971. DX8Wrapper::Set_Transform(D3DTS_WORLD,Matrix3D(1));
  1972. //Apply the shader and material
  1973. DX8Wrapper::Set_Index_Buffer(m_indexBuffer,0);
  1974. for (Int j=0; j<m_numVBTilesY; j++)
  1975. for (Int i=0; i<m_numVBTilesX; i++)
  1976. {
  1977. static int count = 0;
  1978. count++;
  1979. Int numPolys = VERTEX_BUFFER_TILE_LENGTH*VERTEX_BUFFER_TILE_LENGTH*2;
  1980. Int numVertex = (VERTEX_BUFFER_TILE_LENGTH*2)*(VERTEX_BUFFER_TILE_LENGTH*2);
  1981. if (HALF_RES_MESH) {
  1982. numPolys /= 4;
  1983. numVertex /= 4;
  1984. }
  1985. DX8Wrapper::Set_Vertex_Buffer(m_vertexBufferTiles[j*m_numVBTilesX+i]);
  1986. #ifdef PRE_TRANSFORM_VERTEX
  1987. if (m_xformedVertexBuffer && pass==0) {
  1988. // Note - m_xformedVertexBuffer should only be used for non T&L hardware. jba.
  1989. DX8Wrapper::Apply_Render_State_Changes();
  1990. int code = DX8Wrapper::_Get_D3D_Device8()->ProcessVertices(0, 0, numVertex, m_xformedVertexBuffer[j*m_numVBTilesX+i], 0);
  1991. ::OutputDebugString("did process vertex\n");
  1992. }
  1993. if (m_xformedVertexBuffer) {
  1994. // Note - m_xformedVertexBuffer should only be used for non T&L hardware. jba.
  1995. DX8Wrapper::Apply_Render_State_Changes();
  1996. DX8Wrapper::_Get_D3D_Device8()->SetStreamSource(
  1997. 0,
  1998. m_xformedVertexBuffer[j*m_numVBTilesX+i],
  1999. D3DXGetFVFVertexSize(D3DFVF_XYZRHW |D3DFVF_DIFFUSE|D3DFVF_TEX2));
  2000. DX8Wrapper::_Get_D3D_Device8()->SetVertexShader(D3DFVF_XYZRHW |D3DFVF_DIFFUSE|D3DFVF_TEX2);
  2001. }
  2002. #endif
  2003. if (Is_Hidden() == 0) {
  2004. DX8Wrapper::Draw_Triangles( 0,numPolys, 0, numVertex);
  2005. }
  2006. }
  2007. }
  2008. //=============================================================================
  2009. // HeightMapRenderObjClass::renderExtraBlendTiles
  2010. //=============================================================================
  2011. /** Renders an additoinal terrain pass including only those tiles which have more than 2 textures
  2012. blended together. Used primarily for corner cases where 3 different textures meet.*/
  2013. void HeightMapRenderObjClass::renderExtraBlendTiles(void)
  2014. {
  2015. Int vertexCount = 0;
  2016. Int indexCount = 0;
  2017. Int xExtent = m_map->getXExtent();
  2018. Int border = m_map->getBorderSizeInline();
  2019. static Int maxBlendTiles = DEFAULT_MAX_FRAME_EXTRABLEND_TILES;
  2020. m_numVisibleExtraBlendTiles = 0;
  2021. if (!m_numExtraBlendTiles)
  2022. return; //nothing to draw
  2023. if (maxBlendTiles > 10000) //we can only fit about 10000 tiles into a single VB.
  2024. maxBlendTiles = 10000;
  2025. DynamicVBAccessClass vb_access(BUFFER_TYPE_DYNAMIC_DX8,DX8_FVF_XYZNDUV2,maxBlendTiles*4);
  2026. DynamicIBAccessClass ib_access(BUFFER_TYPE_DYNAMIC_DX8,maxBlendTiles*6);
  2027. {
  2028. DynamicVBAccessClass::WriteLockClass lock(&vb_access);
  2029. VertexFormatXYZNDUV2* vb= lock.Get_Formatted_Vertex_Array();
  2030. DynamicIBAccessClass::WriteLockClass lockib(&ib_access);
  2031. UnsignedShort *ib=lockib.Get_Index_Array();
  2032. if (!vb || !ib) return;
  2033. const UnsignedByte* data = m_map->getDataPtr();
  2034. //Loop over visible terrain and extract all the tiles that need extra blend
  2035. Int drawEdgeY=m_map->getDrawOrgY()+m_map->getDrawHeight()-1;
  2036. Int drawEdgeX=m_map->getDrawOrgX()+m_map->getDrawWidth()-1;
  2037. if (drawEdgeX > (m_map->getXExtent()-1))
  2038. drawEdgeX = m_map->getXExtent()-1;
  2039. if (drawEdgeY > (m_map->getYExtent()-1))
  2040. drawEdgeY = m_map->getYExtent()-1;
  2041. Int drawStartX=m_map->getDrawOrgX();
  2042. Int drawStartY=m_map->getDrawOrgY();
  2043. try {
  2044. for (Int j=0; j<m_numExtraBlendTiles; j++)
  2045. {
  2046. if (vertexCount >= (maxBlendTiles*4))
  2047. break; //no room in vertex buffer
  2048. Real U[4],V[4];
  2049. UnsignedByte alpha[4];
  2050. Bool flipState,cliffState;
  2051. Int x = m_extraBlendTilePositions[j] & 0xffff;
  2052. Int y = m_extraBlendTilePositions[j] >> 16;
  2053. if (x >= drawStartX && x < drawEdgeX &&
  2054. y >= drawStartY && y < drawEdgeY &&
  2055. m_map->getExtraAlphaUVData(x,y,U,V,alpha,&flipState, &cliffState))
  2056. { //this tile is inside visible region and has 3rd blend layer.
  2057. Int idx = x+y*xExtent;
  2058. Real p0=data[idx]*MAP_HEIGHT_SCALE;
  2059. Real p1=data[idx+1]*MAP_HEIGHT_SCALE;
  2060. Real p2=data[idx + 1 + xExtent]*MAP_HEIGHT_SCALE;
  2061. Real p3=data[idx + xExtent]*MAP_HEIGHT_SCALE;
  2062. if (cliffState && abs(p0-p2) > abs(p1-p3)) //cliffs sometimes force a flip
  2063. flipState = TRUE;
  2064. vb->x=(x-border)*MAP_XY_FACTOR;
  2065. vb->y=(y-border)*MAP_XY_FACTOR;
  2066. vb->z=p0;
  2067. vb->nx=0;
  2068. vb->ny=0;
  2069. vb->nz=0;
  2070. vb->diffuse=(alpha[0]<<24)|(getStaticDiffuse(x,y) & 0x00ffffff);
  2071. vb->u1=U[0];
  2072. vb->v1=V[0];
  2073. vb->u2=0;
  2074. vb->v2=0;
  2075. vb++;
  2076. vb->x=(x+1-border)*MAP_XY_FACTOR;
  2077. vb->y=(y-border)*MAP_XY_FACTOR;
  2078. vb->z=p1;
  2079. vb->nx=0;
  2080. vb->ny=0;
  2081. vb->nz=0;
  2082. vb->diffuse=(alpha[1]<<24)|(getStaticDiffuse(x+1,y) & 0x00ffffff);
  2083. vb->u1=U[1];
  2084. vb->v1=V[1];
  2085. vb->u2=0;
  2086. vb->v2=0;
  2087. vb++;
  2088. vb->x=(x+1-border)*MAP_XY_FACTOR;
  2089. vb->y=(y+1-border)*MAP_XY_FACTOR;
  2090. vb->z=p2;
  2091. vb->nx=0;
  2092. vb->ny=0;
  2093. vb->nz=0;
  2094. vb->diffuse=(alpha[2]<<24)|(getStaticDiffuse(x+1,y+1) & 0x00ffffff);
  2095. vb->u1=U[2];
  2096. vb->v1=V[2];
  2097. vb->u2=0;
  2098. vb->v2=0;
  2099. vb++;
  2100. vb->x=(x-border)*MAP_XY_FACTOR;
  2101. vb->y=(y+1-border)*MAP_XY_FACTOR;
  2102. vb->z=p3;
  2103. vb->nx=0;
  2104. vb->ny=0;
  2105. vb->nz=0;
  2106. vb->diffuse=(alpha[3]<<24)|(getStaticDiffuse(x,y+1) & 0x00ffffff);
  2107. vb->u1=U[3];
  2108. vb->v1=V[3];
  2109. vb->u2=0;
  2110. vb->v2=0;
  2111. vb++;
  2112. if (flipState)
  2113. {
  2114. ib[0]=1+vertexCount;
  2115. ib[1]=3+vertexCount;
  2116. ib[2]=0+vertexCount;
  2117. ib[3]=1+vertexCount;
  2118. ib[4]=2+vertexCount;
  2119. ib[5]=3+vertexCount;
  2120. }
  2121. else
  2122. {
  2123. ib[0]=0+vertexCount;
  2124. ib[1]=2+vertexCount;
  2125. ib[2]=3+vertexCount;
  2126. ib[3]=0+vertexCount;
  2127. ib[4]=1+vertexCount;
  2128. ib[5]=2+vertexCount;
  2129. }
  2130. ib += 6;
  2131. vertexCount +=4;
  2132. indexCount +=6;
  2133. }//tile has 3rd blend layer and is visible
  2134. } //for all extre blend tiles
  2135. IndexBufferExceptionFunc();
  2136. } catch(...) {
  2137. IndexBufferExceptionFunc();
  2138. }
  2139. }//unlock vertex buffer
  2140. if (vertexCount)
  2141. {
  2142. //Check if we couldn't fit all blend tiles into vertex buffer so we can enlarge it for next frame.
  2143. if (vertexCount == (maxBlendTiles*4))
  2144. maxBlendTiles += 16; //enlarge by 16 to reduce trashing.
  2145. ShaderClass::Invalidate(); //invalidate to force shader to reset since we directly changed states
  2146. DX8Wrapper::Set_Index_Buffer(ib_access,0);
  2147. DX8Wrapper::Set_Vertex_Buffer(vb_access);
  2148. VertexMaterialClass *vmat=VertexMaterialClass::Get_Preset(VertexMaterialClass::PRELIT_DIFFUSE);
  2149. DX8Wrapper::Set_Material(vmat);
  2150. REF_PTR_RELEASE(vmat);
  2151. ShaderClass shader=ShaderClass::_PresetOpaqueShader;
  2152. shader.Set_Depth_Mask(ShaderClass::DEPTH_WRITE_DISABLE); //disable writes to z
  2153. DX8Wrapper::Set_Shader(shader);
  2154. if (TheGlobalData->m_use3WayTerrainBlends == 2)
  2155. {
  2156. shader.Set_Primary_Gradient(ShaderClass::GRADIENT_DISABLE); //disable lighting.
  2157. shader.Set_Texturing(ShaderClass::TEXTURING_DISABLE); //disable texturing.
  2158. DX8Wrapper::Set_Shader(shader);
  2159. DX8Wrapper::Set_Texture(0,NULL); //debug mode which draws terrain tiles in white.
  2160. if (Is_Hidden() == 0) {
  2161. DX8Wrapper::Draw_Triangles( 0,indexCount/3, 0, vertexCount); //draw a quad, 2 triangles, 4 verts
  2162. m_numVisibleExtraBlendTiles += indexCount/6;
  2163. }
  2164. }
  2165. else
  2166. {
  2167. W3DShaderManager::setTexture(0,m_stageOneTexture);
  2168. W3DShaderManager::setTexture(1,m_stageTwoTexture); //cloud
  2169. W3DShaderManager::setTexture(2,m_stageThreeTexture); //noise/lightmap
  2170. W3DShaderManager::ShaderTypes st = W3DShaderManager::ST_ROAD_BASE;
  2171. Bool doCloud = TheGlobalData->m_useCloudMap;
  2172. if (TheGlobalData->m_timeOfDay == TIME_OF_DAY_NIGHT) {
  2173. doCloud = false;
  2174. }
  2175. if (TheGlobalData->m_useLightMap && doCloud)
  2176. {
  2177. st = W3DShaderManager::ST_ROAD_BASE_NOISE12;
  2178. }
  2179. else if (TheGlobalData->m_useLightMap)
  2180. { //lightmap only
  2181. st = W3DShaderManager::ST_ROAD_BASE_NOISE2;
  2182. }
  2183. else if (doCloud)
  2184. { //cloudmap only
  2185. st = W3DShaderManager::ST_ROAD_BASE_NOISE1;
  2186. }
  2187. Int devicePasses=W3DShaderManager::getShaderPasses(st);
  2188. for (Int pass=0; pass < devicePasses; pass++)
  2189. {
  2190. W3DShaderManager::setShader(st, pass);
  2191. if (Is_Hidden() == 0) {
  2192. DX8Wrapper::Draw_Triangles( 0,indexCount/3, 0, vertexCount); //draw a quad, 2 triangles, 4 verts
  2193. m_numVisibleExtraBlendTiles += indexCount/6;
  2194. }
  2195. }
  2196. W3DShaderManager::resetShader(st);
  2197. }
  2198. }
  2199. }
  2200. #endif