BaseHeightMap.cpp 101 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022
  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 <stdio.h>
  46. #include <stdlib.h>
  47. #include <string.h>
  48. #include <assetmgr.h>
  49. #include <texture.h>
  50. #include <tri.h>
  51. #include <colmath.h>
  52. #include <coltest.h>
  53. #include <rinfo.h>
  54. #include <camera.h>
  55. #include <d3dx8core.h>
  56. #include "Common/GlobalData.h"
  57. #include "Common/PerfTimer.h"
  58. #include "GameClient/TerrainVisual.h"
  59. #include "GameClient/View.h"
  60. #include "GameClient/Water.h"
  61. #include "GameLogic/AIPathfind.h"
  62. #include "GameLogic/TerrainLogic.h"
  63. #include "W3DDevice/GameClient/TerrainTex.h"
  64. #include "W3DDevice/GameClient/W3DDynamicLight.h"
  65. #include "W3DDevice/GameClient/W3DScene.h"
  66. #include "W3DDevice/GameClient/W3DTerrainTracks.h"
  67. #include "W3DDevice/GameClient/W3DBibBuffer.h"
  68. #include "W3DDevice/GameClient/W3DPropBuffer.h"
  69. #include "W3DDevice/GameClient/W3DTreeBuffer.h"
  70. #include "W3DDevice/GameClient/W3DRoadBuffer.h"
  71. #include "W3DDevice/GameClient/W3DBridgeBuffer.h"
  72. #include "W3DDevice/GameClient/W3DWaypointBuffer.h"
  73. #include "W3DDevice/GameClient/W3DCustomEdging.h"
  74. #include "W3DDevice/GameClient/WorldHeightMap.h"
  75. #include "W3DDevice/GameClient/W3DShaderManager.h"
  76. #include "W3DDevice/GameClient/W3DShadow.h"
  77. #include "W3DDevice/GameClient/W3DWater.h"
  78. #include "W3DDevice/GameClient/W3DShroud.h"
  79. #include "WW3D2/DX8Wrapper.h"
  80. #include "WW3D2/Light.h"
  81. #include "WW3D2/Scene.h"
  82. #include "W3DDevice/GameClient/W3DPoly.h"
  83. #include "W3DDevice/GameClient/W3DCustomScene.h"
  84. #include "Common/PerfTimer.h"
  85. #include "Common/UnitTimings.h" //Contains the DO_UNIT_TIMINGS define jba.
  86. #include "W3DDevice/GameClient/BaseHeightMap.h"
  87. #include "W3DDevice/GameClient/HeightMap.h"
  88. #include "W3DDevice/GameClient/FlatHeightMap.h"
  89. #include "W3DDevice/GameClient/W3DSmudge.h"
  90. #include "W3DDevice/GameClient/W3DSnow.h"
  91. #ifdef _INTERNAL
  92. // for occasional debugging...
  93. //#pragma optimize("", off)
  94. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  95. #endif
  96. extern FlatHeightMapRenderObjClass *TheFlatHeightMap;
  97. extern HeightMapRenderObjClass *TheHeightMap;
  98. //-----------------------------------------------------------------------------
  99. // Private Data
  100. //-----------------------------------------------------------------------------
  101. #define SC_DETAIL_BLEND ( SHADE_CNST(ShaderClass::PASS_LEQUAL, ShaderClass::DEPTH_WRITE_ENABLE, ShaderClass::COLOR_WRITE_ENABLE, ShaderClass::SRCBLEND_ONE, \
  102. ShaderClass::DSTBLEND_ZERO, ShaderClass::FOG_DISABLE, ShaderClass::GRADIENT_MODULATE, ShaderClass::SECONDARY_GRADIENT_DISABLE, ShaderClass::TEXTURING_ENABLE, \
  103. ShaderClass::ALPHATEST_DISABLE, ShaderClass::CULL_MODE_ENABLE, ShaderClass::DETAILCOLOR_SCALE, ShaderClass::DETAILALPHA_DISABLE) )
  104. static ShaderClass detailOpaqueShader(SC_DETAIL_BLEND);
  105. //-----------------------------------------------------------------------------
  106. // Global Functions & Data
  107. //-----------------------------------------------------------------------------
  108. /// The one-of for the terrain rendering object.
  109. BaseHeightMapRenderObjClass *TheTerrainRenderObject=NULL;
  110. /** Entry point so that trees can be drawn at the appropriate point in the rendering pipe for
  111. transparent objects. */
  112. void DoTrees(RenderInfoClass & rinfo)
  113. {
  114. if (TheTerrainRenderObject) {
  115. TheTerrainRenderObject->renderTrees(&rinfo.Camera);
  116. }
  117. }
  118. void oversizeTheTerrain(Int amount)
  119. {
  120. if (TheTerrainRenderObject)
  121. {
  122. TheTerrainRenderObject->oversizeTerrain(amount);
  123. }
  124. }
  125. #define DEFAULT_MAX_BATCH_SHORELINE_TILES 512 //maximum number of terrain tiles rendered per call (must fit in one VB)
  126. #define DEFAULT_MAX_MAP_SHORELINE_TILES 4096 //default size of array allocated to hold all map shoreline tiles.
  127. #define ADJUST_FROM_INDEX_TO_REAL(k) ((k-m_map->getBorderSizeInline())*MAP_XY_FACTOR)
  128. inline Int IABS(Int x) { if (x>=0) return x; return -x;};
  129. //-----------------------------------------------------------------------------
  130. // Private Functions
  131. //-----------------------------------------------------------------------------
  132. //=============================================================================
  133. // BaseHeightMapRenderObjClass::freeMapResources
  134. //=============================================================================
  135. /** Frees the w3d resources used to draw the terrain. */
  136. //=============================================================================
  137. Int BaseHeightMapRenderObjClass::freeMapResources(void)
  138. {
  139. #ifdef DO_SCORCH
  140. freeScorchBuffers();
  141. #endif
  142. REF_PTR_RELEASE(m_vertexMaterialClass);
  143. REF_PTR_RELEASE(m_stageZeroTexture);
  144. REF_PTR_RELEASE(m_stageOneTexture);
  145. REF_PTR_RELEASE(m_stageTwoTexture);
  146. REF_PTR_RELEASE(m_stageThreeTexture);
  147. REF_PTR_RELEASE(m_destAlphaTexture);
  148. REF_PTR_RELEASE(m_map);
  149. return 0;
  150. }
  151. #ifdef DO_SCORCH
  152. //=============================================================================
  153. // BaseHeightMapRenderObjClass::drawScorches
  154. //=============================================================================
  155. /** Draws the scorch marks. */
  156. //=============================================================================
  157. void BaseHeightMapRenderObjClass::drawScorches(void)
  158. {
  159. updateScorches();
  160. if (m_curNumScorchIndices == 0) {
  161. return;
  162. }
  163. DX8Wrapper::Set_Index_Buffer(m_indexScorch,0);
  164. DX8Wrapper::Set_Vertex_Buffer(m_vertexScorch);
  165. DX8Wrapper::Set_Shader(ShaderClass::_PresetAlphaShader);
  166. DX8Wrapper::Set_Texture(0,m_scorchTexture);
  167. if (Is_Hidden() == 0) {
  168. DX8Wrapper::Draw_Triangles( 0,m_curNumScorchIndices/3, 0, m_curNumScorchVertices);
  169. }
  170. }
  171. #endif
  172. //-----------------------------------------------------------------------------
  173. // Public Functions
  174. //-----------------------------------------------------------------------------
  175. //=============================================================================
  176. // BaseHeightMapRenderObjClass::~BaseHeightMapRenderObjClass
  177. //=============================================================================
  178. /** Destructor. Releases w3d assets. */
  179. //=============================================================================
  180. BaseHeightMapRenderObjClass::~BaseHeightMapRenderObjClass(void)
  181. {
  182. freeMapResources();
  183. if (m_treeBuffer) {
  184. delete m_treeBuffer;
  185. m_treeBuffer = NULL;
  186. }
  187. if (m_propBuffer) {
  188. delete m_propBuffer;
  189. m_propBuffer = NULL;
  190. }
  191. if (m_bibBuffer) {
  192. delete m_bibBuffer;
  193. m_bibBuffer = NULL;
  194. }
  195. #ifdef DO_ROADS
  196. if (m_roadBuffer) {
  197. delete m_roadBuffer;
  198. m_roadBuffer = NULL;
  199. }
  200. #endif
  201. if (m_bridgeBuffer) {
  202. delete m_bridgeBuffer;
  203. }
  204. if( m_waypointBuffer )
  205. {
  206. delete m_waypointBuffer;
  207. m_waypointBuffer = NULL;
  208. }
  209. if (m_shroud) {
  210. delete m_shroud;
  211. m_shroud = NULL;
  212. }
  213. if (m_shoreLineTilePositions) {
  214. delete [] m_shoreLineTilePositions;
  215. m_shoreLineTilePositions = NULL;
  216. }
  217. if (m_shoreLineSortInfos)
  218. {
  219. delete [] m_shoreLineSortInfos;
  220. m_shoreLineSortInfos = NULL;
  221. }
  222. }
  223. //=============================================================================
  224. // BaseHeightMapRenderObjClass::BaseHeightMapRenderObjClass
  225. //=============================================================================
  226. /** Constructor. Mostly nulls out the member variables. */
  227. //=============================================================================
  228. BaseHeightMapRenderObjClass::BaseHeightMapRenderObjClass(void)
  229. {
  230. m_x=0;
  231. m_y=0;
  232. m_needFullUpdate = false;
  233. m_showImpassableAreas = false;
  234. m_updating = false;
  235. //Set height to the maximum value that can be stored.
  236. //We should refine this with actual value.
  237. m_maxHeight=(pow(256.0, sizeof(HeightSampleType))-1.0)*MAP_HEIGHT_SCALE;
  238. m_minHeight=0;
  239. m_shoreLineTilePositions=NULL;
  240. m_numShoreLineTiles=0;
  241. m_shoreLineSortInfos=NULL;
  242. m_shoreLineSortInfosSize=0;
  243. m_shoreLineSortInfosXMajor=TRUE;
  244. m_shoreLineTileSortMaxCoordinate=0;
  245. m_shoreLineTileSortMinCoordinate=0;
  246. m_numVisibleShoreLineTiles=0;
  247. m_shoreLineTilePositionsSize=0;
  248. m_currentMinWaterOpacity = -1.0f;
  249. m_vertexMaterialClass=NULL;
  250. m_stageZeroTexture=NULL;
  251. m_stageOneTexture=NULL;
  252. m_stageTwoTexture=NULL;
  253. m_stageThreeTexture=NULL;
  254. m_destAlphaTexture=NULL;
  255. m_map=NULL;
  256. m_depthFade.X = 0.0f;
  257. m_depthFade.Y = 0.0f;
  258. m_depthFade.Z = 0.0f;
  259. m_useDepthFade = false;
  260. m_disableTextures = false;
  261. TheTerrainRenderObject = this;
  262. m_treeBuffer = NULL;
  263. m_treeBuffer = NEW W3DTreeBuffer;
  264. m_propBuffer = NULL;
  265. m_propBuffer = NEW W3DPropBuffer;
  266. m_bibBuffer = NULL;
  267. m_bibBuffer = NEW W3DBibBuffer;
  268. m_curImpassableSlope = 45.0f; // default to 45 degrees.
  269. m_bridgeBuffer = NULL;
  270. m_bridgeBuffer = NEW W3DBridgeBuffer;
  271. m_waypointBuffer = NEW W3DWaypointBuffer;
  272. #ifdef DO_ROADS
  273. m_roadBuffer = NULL;
  274. m_roadBuffer = NEW W3DRoadBuffer;
  275. #endif
  276. #ifdef DO_SCORCH
  277. m_vertexScorch = NULL;
  278. m_indexScorch = NULL;
  279. m_scorchTexture = NULL;
  280. clearAllScorches();
  281. #endif
  282. #if defined(_DEBUG) || defined(_INTERNAL)
  283. if (TheGlobalData->m_shroudOn)
  284. m_shroud = NEW W3DShroud;
  285. else
  286. m_shroud = NULL;
  287. #else
  288. m_shroud = NEW W3DShroud;
  289. #endif
  290. DX8Wrapper::SetCleanupHook(this);
  291. }
  292. void BaseHeightMapRenderObjClass::setTextureLOD(Int lod)
  293. {
  294. if (m_treeBuffer)
  295. m_treeBuffer->setTextureLOD(lod);
  296. if (m_map)
  297. m_map->setTextureLOD(lod);
  298. }
  299. //=============================================================================
  300. // BaseHeightMapRenderObjClass::adjustTerrainLOD
  301. //=============================================================================
  302. /** Adjust the terrain Level Of Detail. If adj > 0 , increases LOD 1 step, if
  303. adj < 0 decreases it one step, if adj==0, then just sets up for the current LOD */
  304. //=============================================================================
  305. void BaseHeightMapRenderObjClass::adjustTerrainLOD(Int adj)
  306. {
  307. if (adj>0 && TheGlobalData->m_terrainLOD<TERRAIN_LOD_MAX) TheWritableGlobalData->m_terrainLOD=(TerrainLOD)(TheGlobalData->m_terrainLOD+1);
  308. if (adj<0 && TheGlobalData->m_terrainLOD>TERRAIN_LOD_MIN) TheWritableGlobalData->m_terrainLOD=(TerrainLOD)(TheGlobalData->m_terrainLOD-1);
  309. if (TheGlobalData->m_terrainLOD ==TERRAIN_LOD_AUTOMATIC) {
  310. TheWritableGlobalData->m_terrainLOD=TERRAIN_LOD_MAX;
  311. }
  312. if (m_map==NULL) return;
  313. if (m_shroud)
  314. m_shroud->reset(); //need reset here since initHeightData will load new shroud.
  315. BaseHeightMapRenderObjClass *newROBJ = NULL;
  316. if (TheGlobalData->m_terrainLOD==7) {
  317. newROBJ = TheHeightMap;
  318. if (newROBJ==NULL) {
  319. newROBJ = NEW_REF( HeightMapRenderObjClass, () );
  320. }
  321. } else {
  322. newROBJ = TheFlatHeightMap;
  323. if (newROBJ==NULL) {
  324. newROBJ = NEW_REF( FlatHeightMapRenderObjClass, () );
  325. }
  326. }
  327. if (TheGlobalData->m_terrainLOD == 5)
  328. newROBJ = NULL;
  329. RTS3DScene *pMyScene = (RTS3DScene *)Scene;
  330. if (pMyScene) {
  331. pMyScene->Remove_Render_Object(this);
  332. pMyScene->Unregister(this, SceneClass::ON_FRAME_UPDATE);
  333. // add our terrain render object to the scene
  334. if (newROBJ) {
  335. pMyScene->Add_Render_Object( newROBJ );
  336. pMyScene->Register(newROBJ,SceneClass::ON_FRAME_UPDATE);
  337. }
  338. }
  339. if (newROBJ) {
  340. // apply the heightmap to the terrain render object
  341. newROBJ->initHeightData( m_map->getDrawWidth(),
  342. m_map->getDrawHeight(),
  343. m_map,
  344. NULL);
  345. TheTerrainRenderObject = newROBJ;
  346. newROBJ->staticLightingChanged();
  347. newROBJ->m_roadBuffer->loadRoads();
  348. }
  349. if (TheTacticalView) {
  350. TheTacticalView->setAngle(TheTacticalView->getAngle() + 1);
  351. TheTacticalView->setAngle(TheTacticalView->getAngle() - 1);
  352. }
  353. }
  354. //=============================================================================
  355. // BaseHeightMapRenderObjClass::ReleaseResources
  356. //=============================================================================
  357. /** Releases all w3d assets, to prepare for Reset device call. */
  358. //=============================================================================
  359. void BaseHeightMapRenderObjClass::ReleaseResources(void)
  360. {
  361. if (m_treeBuffer) {
  362. m_treeBuffer->freeTreeBuffers();
  363. }
  364. if (m_bibBuffer) {
  365. m_bibBuffer->freeBibBuffers();
  366. }
  367. if (m_bridgeBuffer) {
  368. m_bridgeBuffer->freeBridgeBuffers();
  369. }
  370. if( m_waypointBuffer )
  371. {
  372. m_waypointBuffer->freeWaypointBuffers();
  373. }
  374. // We need to save the map.
  375. WorldHeightMap *pMap=NULL;
  376. REF_PTR_SET(pMap, m_map);
  377. freeMapResources();
  378. m_map = pMap; // ref_ptr_set has already incremented the ref count.
  379. if (TheWaterRenderObj)
  380. TheWaterRenderObj->ReleaseResources();
  381. if (TheTerrainTracksRenderObjClassSystem)
  382. TheTerrainTracksRenderObjClassSystem->ReleaseResources();
  383. if (TheW3DShadowManager)
  384. TheW3DShadowManager->ReleaseResources();
  385. if (m_shroud)
  386. { m_shroud->reset();
  387. m_shroud->ReleaseResources();
  388. }
  389. if (TheSmudgeManager)
  390. TheSmudgeManager->ReleaseResources();
  391. if (TheSnowManager)
  392. ((W3DSnowManager *)TheSnowManager)->ReleaseResources();
  393. //Release any resources that may be used by custom pixel/vertex shaders
  394. W3DShaderManager::shutdown();
  395. #ifdef DO_ROADS
  396. if (m_roadBuffer) {
  397. m_roadBuffer->freeRoadBuffers();
  398. }
  399. #endif
  400. }
  401. //=============================================================================
  402. // BaseHeightMapRenderObjClass::ReAcquireResources
  403. //=============================================================================
  404. /** Reallocates all W3D assets after a reset.. */
  405. //=============================================================================
  406. void BaseHeightMapRenderObjClass::ReAcquireResources(void)
  407. {
  408. W3DShaderManager::init(); //reaquire resources which may be needed by custom shaders
  409. if (TheWaterRenderObj)
  410. TheWaterRenderObj->ReAcquireResources();
  411. if (TheTerrainTracksRenderObjClassSystem)
  412. TheTerrainTracksRenderObjClassSystem->ReAcquireResources();
  413. if (TheW3DShadowManager)
  414. TheW3DShadowManager->ReAcquireResources();
  415. if (m_shroud)
  416. m_shroud->ReAcquireResources();
  417. if (m_map)
  418. {
  419. this->initHeightData(m_x,m_y,m_map, NULL);
  420. // Tell lights to update next time through.
  421. m_needFullUpdate = true;
  422. }
  423. if (m_treeBuffer) {
  424. m_treeBuffer->allocateTreeBuffers();
  425. }
  426. if (m_bibBuffer) {
  427. m_bibBuffer->allocateBibBuffers();
  428. }
  429. if (m_bridgeBuffer) {
  430. m_bridgeBuffer->allocateBridgeBuffers();
  431. }
  432. if (TheSmudgeManager)
  433. TheSmudgeManager->ReAcquireResources();
  434. if (TheSnowManager)
  435. ((W3DSnowManager *)TheSnowManager)->ReAcquireResources();
  436. //Waypoint buffers are done dynamically. One line, one node (just rendered multiple times accessing other data).
  437. //Internally creates it if needed.
  438. #ifdef DO_ROADS
  439. if (m_roadBuffer) {
  440. m_roadBuffer->allocateRoadBuffers();
  441. m_roadBuffer->loadRoads();
  442. }
  443. #endif
  444. if (TheTacticalView)
  445. { TheTacticalView->forceRedraw(); //force map to update itself for the current camera position.
  446. //for some reason we need to do it twice otherwise we sometimes end up with a black map until
  447. //the player moves.
  448. TheTacticalView->forceRedraw();
  449. }
  450. }
  451. //=============================================================================
  452. // BaseHeightMapRenderObjClass::doTheLight
  453. //=============================================================================
  454. /** Calculates the diffuse lighting for a vertex in the terrain, taking all of the
  455. static lights into account as well. It is possible to just use the normal in the
  456. vertex and let D3D do the lighting, but it is slower to render, and can only
  457. handle 4 lights at this point. */
  458. //=============================================================================
  459. void BaseHeightMapRenderObjClass::doTheLight(VERTEX_FORMAT *vb, Vector3*light, Vector3*normal, RefRenderObjListIterator *pLightsIterator, UnsignedByte alpha)
  460. {
  461. #ifdef USE_NORMALS
  462. vb->nx = normal->X;
  463. vb->ny = normal->Y;
  464. vb->nz = normal->Z;
  465. #else
  466. Real shadeR, shadeG, shadeB;
  467. Real shade;
  468. shadeR = TheGlobalData->m_terrainAmbient[0].red; //only the first terrain light contributes to ambient
  469. shadeG = TheGlobalData->m_terrainAmbient[0].green;
  470. shadeB = TheGlobalData->m_terrainAmbient[0].blue;
  471. if (pLightsIterator) {
  472. for (pLightsIterator->First(); !pLightsIterator->Is_Done(); pLightsIterator->Next())
  473. {
  474. LightClass *pLight = (LightClass*)pLightsIterator->Peek_Obj();
  475. Vector3 lightDirection(vb->x, vb->y, vb->z);
  476. Real factor = 1.0f;
  477. switch(pLight->Get_Type()) {
  478. case LightClass::POINT:
  479. case LightClass::SPOT: {
  480. Vector3 lightLoc = pLight->Get_Position();
  481. lightDirection -= lightLoc;
  482. double range, midRange;
  483. pLight->Get_Far_Attenuation_Range(midRange, range);
  484. if (vb->x < lightLoc.X-range) continue;
  485. if (vb->x > lightLoc.X+range) continue;
  486. if (vb->y < lightLoc.Y-range) continue;
  487. if (vb->y > lightLoc.Y+range) continue;
  488. Real dist = lightDirection.Length();
  489. if (dist >= range) continue;
  490. if (midRange < 0.1) continue;
  491. #if 1
  492. factor = 1.0f - (dist - midRange) / (range - midRange);
  493. #else
  494. // f = 1.0 / (atten0 + d*atten1 + d*d/atten2);
  495. if (fabs(range-midRange)<1e-5) {
  496. // if the attenuation range is too small assume uniform with cutoff
  497. factor = 1.0;
  498. } else {
  499. factor = 1.0f/(0.1+dist/midRange + 5.0f*dist*dist/(range*range));
  500. }
  501. #endif
  502. factor = WWMath::Clamp(factor,0.0f,1.0f);
  503. }
  504. break;
  505. case LightClass::DIRECTIONAL:
  506. lightDirection = pLight->Get_Transform().Get_Z_Vector();
  507. factor = 1.0;
  508. break;
  509. };
  510. lightDirection.Normalize();
  511. Vector3 lightRay(-lightDirection.X, -lightDirection.Y, -lightDirection.Z);
  512. shade = Vector3::Dot_Product(lightRay, *normal);
  513. shade *= factor;
  514. Vector3 diffuse;
  515. pLight->Get_Diffuse(&diffuse);
  516. Vector3 ambient;
  517. pLight->Get_Ambient(&ambient);
  518. if (shade > 1.0) shade = 1.0;
  519. if(shade < 0.0f) shade = 0.0f;
  520. shadeR += shade*diffuse.X;
  521. shadeG += shade*diffuse.Y;
  522. shadeB += shade*diffuse.Z;
  523. shadeR += factor*ambient.X;
  524. shadeG += factor*ambient.Y;
  525. shadeB += factor*ambient.Z;
  526. }
  527. }
  528. // Add in global diffuse value.
  529. const RGBColor *terrainDiffuse;
  530. for (Int lightIndex=0; lightIndex < TheGlobalData->m_numGlobalLights; lightIndex++)
  531. {
  532. shade = Vector3::Dot_Product(light[lightIndex], *normal);
  533. if (shade > 1.0) shade = 1.0;
  534. if(shade < 0.0f) shade = 0.0f;
  535. terrainDiffuse=&TheGlobalData->m_terrainDiffuse[lightIndex];
  536. shadeR += shade*terrainDiffuse->red;
  537. shadeG += shade*terrainDiffuse->green;
  538. shadeB += shade*terrainDiffuse->blue;
  539. }
  540. if (shadeR > 1.0) shadeR = 1.0;
  541. if(shadeR < 0.0f) shadeR = 0.0f;
  542. if (shadeG > 1.0) shadeG = 1.0;
  543. if(shadeG < 0.0f) shadeG = 0.0f;
  544. if (shadeB > 1.0) shadeB = 1.0;
  545. if(shadeB < 0.0f) shadeB = 0.0f;
  546. if (m_useDepthFade && vb->z <= TheGlobalData->m_waterPositionZ)
  547. { //height is below water level
  548. //reduce lighting values based on light fall off as it travels through water.
  549. float depthScale = (1.4f - vb->z)/TheGlobalData->m_waterPositionZ;
  550. shadeR *= 1.0f - depthScale * (1.0f-m_depthFade.X);
  551. shadeG *= 1.0f - depthScale * (1.0f-m_depthFade.Y);
  552. shadeB *= 1.0f - depthScale * (1.0f-m_depthFade.Z);
  553. }
  554. shadeR*=255.0f;
  555. shadeG*=255.0f;
  556. shadeB*=255.0f;
  557. vb->diffuse = REAL_TO_INT(shadeB) | (REAL_TO_INT(shadeG) << 8) | (REAL_TO_INT(shadeR) << 16) | ((Int)alpha << 24);
  558. #endif
  559. }
  560. //=============================================================================
  561. // BaseHeightMapRenderObjClass::updateMacroTexture
  562. //=============================================================================
  563. /** Updates the macro noise/lightmap texture (pass 3) */
  564. //=============================================================================
  565. void BaseHeightMapRenderObjClass::updateMacroTexture(AsciiString textureName)
  566. {
  567. m_macroTextureName = textureName;
  568. // Release texture.
  569. REF_PTR_RELEASE(m_stageThreeTexture);
  570. // Reallocate texture.
  571. m_stageThreeTexture=NEW LightMapTerrainTextureClass(m_macroTextureName);
  572. }
  573. //=============================================================================
  574. // BaseHeightMapRenderObjClass::reset
  575. //=============================================================================
  576. /** Updates the macro noise/lightmap texture (pass 3) */
  577. //=============================================================================
  578. void BaseHeightMapRenderObjClass::reset(void)
  579. {
  580. if (m_treeBuffer) {
  581. m_treeBuffer->clearAllTrees();
  582. }
  583. if (m_propBuffer) {
  584. m_propBuffer->clearAllProps();
  585. }
  586. clearAllScorches();
  587. #ifdef TEST_CUSTOM_EDGING
  588. m_customEdging ->clearAllEdging();
  589. #endif
  590. #ifdef DO_ROADS
  591. if (m_roadBuffer) {
  592. m_roadBuffer->clearAllRoads();
  593. }
  594. #endif
  595. if (m_bridgeBuffer) {
  596. m_bridgeBuffer->clearAllBridges();
  597. }
  598. if (m_bibBuffer) {
  599. m_bibBuffer->clearAllBibs();
  600. }
  601. m_showAsVisibleCliff.clear();
  602. if (m_shroud)
  603. { m_shroud->reset();
  604. m_shroud->setBorderShroudLevel((W3DShroudLevel)TheGlobalData->m_shroudAlpha); //assume border is always black at start.
  605. }
  606. }
  607. /**@todo: Ray intersection needs to be optimized with some sort of grid-tracing
  608. (ala line drawing). We should also try making the search in a front->back order
  609. relative to the ray so we can early exit as soon as we have a hit.
  610. *
  611. //=============================================================================
  612. // BaseHeightMapRenderObjClass::Cast_Ray
  613. //=============================================================================
  614. /** Return intersection of a ray with the heightmap mesh.
  615. This is a quick version that just checks every polygon inside
  616. a 2D bounding rectangle of the ray projected onto the heightfield plane.
  617. For most of our view-picking cases the ray in almost perpendicular to the
  618. map plane so this is very quick (small bounding box). But it can become slow
  619. for arbitrary rays such as those used in AI visbility checks.(2 units on
  620. opposite corners of the map would check every polygon in the map).
  621. */
  622. //=============================================================================
  623. bool BaseHeightMapRenderObjClass::Cast_Ray(RayCollisionTestClass & raytest)
  624. {
  625. TriClass tri;
  626. Bool hit = false;
  627. Int X,Y;
  628. Vector3 normal,P0,P1,P2,P3;
  629. if (!m_map)
  630. return false; //need valid pointer to heightmap samples
  631. //HeightSampleType *pData = m_map->getDataPtr();
  632. //Clip ray to extents of heightfield
  633. AABoxClass hbox;
  634. LineSegClass lineseg,lineseg2;
  635. CastResultStruct result;
  636. Int StartCellX = 0;
  637. Int EndCellX = 0;
  638. Int StartCellY = 0;
  639. Int EndCellY = 0;
  640. const Int overhang = 2*32+m_map->getBorderSizeInline(); // Allow picking past the edge for scrolling & objects.
  641. Vector3 minPt(MAP_XY_FACTOR*(-overhang), MAP_XY_FACTOR*(-overhang), -MAP_XY_FACTOR);
  642. Vector3 maxPt(MAP_XY_FACTOR*(m_map->getXExtent()+overhang),
  643. MAP_XY_FACTOR*(m_map->getYExtent()+overhang), MAP_HEIGHT_SCALE*m_map->getMaxHeightValue()+MAP_XY_FACTOR);
  644. MinMaxAABoxClass mmbox(minPt, maxPt);
  645. hbox.Init(mmbox);
  646. lineseg=raytest.Ray;
  647. //Set initial ray endpoints
  648. P0 = raytest.Ray.Get_P0();
  649. P1 = raytest.Ray.Get_P1();
  650. result.ComputeContactPoint=true;
  651. Int p;
  652. for (p=0; p<3; p++) {
  653. //find intersection point of ray and terrain bounding box
  654. result.Reset();
  655. result.ComputeContactPoint=true;
  656. if (CollisionMath::Collide(lineseg,hbox,&result))
  657. { //ray intersects terrain or starts inside the terrain.
  658. if (!result.StartBad) //check if start point inside terrain
  659. P0 = result.ContactPoint; //make intersection point the new start of the ray.
  660. //reverse direction of original ray and clip again to extent of
  661. //heightmap
  662. result.Fraction=1.0f; //reset the result
  663. result.StartBad=false;
  664. lineseg2.Set(lineseg.Get_P1(),lineseg.Get_P0()); //reverse line segment
  665. if (CollisionMath::Collide(lineseg2,hbox,&result))
  666. { if (!result.StartBad) //check if end point inside terrain
  667. P1 = result.ContactPoint; //make intersection point the new end pont of ray
  668. }
  669. } else {
  670. if (p==0) return(false);
  671. break;
  672. }
  673. // Take the 2D bounding box of ray and check heights
  674. // inside this box for intersection.
  675. if (P0.X > P1.X) { //flip start/end points
  676. StartCellX = REAL_TO_INT_FLOOR(P1.X/MAP_XY_FACTOR);
  677. EndCellX = REAL_TO_INT_CEIL(P0.X/MAP_XY_FACTOR);
  678. } else {
  679. StartCellX = REAL_TO_INT_FLOOR(P0.X/MAP_XY_FACTOR);
  680. EndCellX = REAL_TO_INT_CEIL(P1.X/MAP_XY_FACTOR);
  681. }
  682. if (P0.Y > P1.Y) { //flip start/end points
  683. StartCellY = REAL_TO_INT_FLOOR(P1.Y/MAP_XY_FACTOR);
  684. EndCellY = REAL_TO_INT_CEIL(P0.Y/MAP_XY_FACTOR);
  685. } else {
  686. StartCellY = REAL_TO_INT_FLOOR(P0.Y/MAP_XY_FACTOR);
  687. EndCellY = REAL_TO_INT_CEIL(P1.Y/MAP_XY_FACTOR);
  688. }
  689. Int i, j, minHt, maxHt;
  690. minHt = m_map->getMaxHeightValue();
  691. maxHt = 0;
  692. for (j=StartCellY; j<=EndCellY; j++) {
  693. for (i=StartCellX; i<=EndCellX; i++) {
  694. Short cur = getClipHeight(i+m_map->getBorderSizeInline(),j+m_map->getBorderSizeInline());
  695. if (cur<minHt) minHt = cur;
  696. if (maxHt<cur) maxHt = cur;
  697. }
  698. }
  699. Vector3 minPt(MAP_XY_FACTOR*(StartCellX-1), MAP_XY_FACTOR*(StartCellY-1), MAP_HEIGHT_SCALE*(minHt-1));
  700. Vector3 maxPt(MAP_XY_FACTOR*(EndCellX+1), MAP_XY_FACTOR*(EndCellY+1), MAP_HEIGHT_SCALE*(maxHt+1));
  701. MinMaxAABoxClass mmbox(minPt, maxPt);
  702. hbox.Init(mmbox);
  703. }
  704. raytest.Result->ComputeContactPoint=true; //tell CollisionMath that we need point.
  705. // Adjust indexes into the bordered height map.
  706. StartCellX += m_map->getBorderSizeInline();
  707. EndCellX += m_map->getBorderSizeInline();
  708. StartCellY += m_map->getBorderSizeInline();
  709. EndCellY += m_map->getBorderSizeInline();
  710. Int offset;
  711. for (offset = 1; offset < 5; offset *= 3) {
  712. for (Y=StartCellY-offset; Y<=EndCellY+offset; Y++) {
  713. for (X=StartCellX-offset; X<=EndCellX+offset; X++) {
  714. //test the 2 triangles in this cell
  715. // 3-----2
  716. // | /|
  717. // | / |
  718. // |/ |
  719. // 0-----1
  720. //bottom triangle first
  721. P0.X=ADJUST_FROM_INDEX_TO_REAL(X);
  722. P0.Y=ADJUST_FROM_INDEX_TO_REAL(Y);
  723. P0.Z=MAP_HEIGHT_SCALE*(float)getClipHeight(X, Y);
  724. P1.X=ADJUST_FROM_INDEX_TO_REAL(X+1);
  725. P1.Y=ADJUST_FROM_INDEX_TO_REAL(Y);
  726. P1.Z=MAP_HEIGHT_SCALE*(float)getClipHeight(X+1, Y);
  727. P2.X=ADJUST_FROM_INDEX_TO_REAL(X+1);
  728. P2.Y=ADJUST_FROM_INDEX_TO_REAL(Y+1);
  729. P2.Z=MAP_HEIGHT_SCALE*(float)getClipHeight(X+1, Y+1);
  730. P3.X=ADJUST_FROM_INDEX_TO_REAL(X);
  731. P3.Y=ADJUST_FROM_INDEX_TO_REAL(Y+1);
  732. P3.Z=MAP_HEIGHT_SCALE*(float)getClipHeight(X, Y+1);
  733. tri.V[0] = &P0;
  734. tri.V[1] = &P1;
  735. tri.V[2] = &P2;
  736. tri.N = &normal;
  737. tri.Compute_Normal();
  738. hit = hit || (Bool)CollisionMath::Collide(raytest.Ray, tri, raytest.Result);
  739. if (raytest.Result->StartBad)
  740. return true;
  741. //top triangle
  742. tri.V[0] = &P2;
  743. tri.V[1] = &P3;
  744. tri.V[2] = &P0;
  745. tri.N = &normal;
  746. tri.Compute_Normal();
  747. hit = hit || (Bool)CollisionMath::Collide(raytest.Ray, tri, raytest.Result);
  748. if (hit)
  749. raytest.Result->SurfaceType = SURFACE_TYPE_DEFAULT; ///@todo: WW3D uses this to return dirt, grass, etc. Do we need this?
  750. }
  751. // Don't break. It is possible to intersect 2 triangles, and the second is closer. if (hit) break;
  752. }
  753. // Don't break. It is possible to intersect 2 triangles, and the second is closer. if (hit) break;
  754. }
  755. return hit;
  756. }
  757. //=============================================================================
  758. // BaseHeightMapRenderObjClass::getHeightMapHeight
  759. //=============================================================================
  760. /** return the height and normal of the triangle plane containing given location within heightmap. */
  761. //=============================================================================
  762. Real BaseHeightMapRenderObjClass::getHeightMapHeight(Real x, Real y, Coord3D* normal) const
  763. {
  764. // SORRY, KIDS
  765. // Had to make this function logic safe, so,
  766. // even though this is a renderObject, and is thus classified as client-side
  767. // it is responsible for reporting height map heights (for reasons I can't say)
  768. // but to do so safely, I a going to pass it the logical heighmap from the W3dTerrainVisual
  769. // yes another nosequiter. Ugh!
  770. // M Lorenzen
  771. // by doing it this way the compiler won't call getLogicHeightMap twice...
  772. WorldHeightMap *logicHeightMap = TheTerrainVisual?TheTerrainVisual->getLogicHeightMap():m_map;
  773. if ( !logicHeightMap )
  774. {
  775. if (normal)
  776. {
  777. // return a default normal pointing up
  778. normal->x = 0.0f;
  779. normal->y = 0.0f;
  780. normal->z = 1.0f;
  781. }
  782. return 0;
  783. }
  784. float height;
  785. // 3-----2
  786. // | /|
  787. // | / |
  788. // |/ |
  789. // 0-----1
  790. //Find surrounding grid points
  791. const Real MAP_XY_FACTOR_INV = 1.0f / MAP_XY_FACTOR;
  792. float xdiv = x * MAP_XY_FACTOR_INV;
  793. float ydiv = y * MAP_XY_FACTOR_INV;
  794. float ixf = FAST_REAL_FLOOR(xdiv);
  795. float iyf = FAST_REAL_FLOOR(ydiv);
  796. float fx = xdiv - ixf; //get fraction
  797. float fy = ydiv - iyf; //get fraction
  798. // since ixf & iyf are already floor'ed, we can use the fastest f->i conversion we have...
  799. Int ix = fast_float2long_round(ixf) + logicHeightMap->getBorderSizeInline();
  800. Int iy = fast_float2long_round(iyf) + logicHeightMap->getBorderSizeInline();
  801. Int xExtent = logicHeightMap->getXExtent();
  802. // Check for extent-3, not extent-1: we go into the next row/column of data for smoothed triangle points, so extent-1
  803. // goes off the end...
  804. if (ix > (xExtent-3) || iy > (logicHeightMap->getYExtent()-3) || iy < 1 || ix < 1)
  805. {
  806. // sample point is not on the heightmap
  807. if (normal)
  808. {
  809. // return a default normal pointing up
  810. normal->x = 0.0f;
  811. normal->y = 0.0f;
  812. normal->z = 1.0f;
  813. }
  814. return getClipHeight(ix, iy) * MAP_HEIGHT_SCALE;
  815. }
  816. const UnsignedByte* data = logicHeightMap->getDataPtr();
  817. int idx = ix + iy*xExtent;
  818. float p0 = data[idx];
  819. float p2 = data[idx + xExtent + 1];
  820. if (fy > fx) // test if we are in the upper triangle
  821. {
  822. float p3 = data[idx + xExtent];
  823. height = (p3 + (1.0f-fy)*(p0-p3) + fx*(p2-p3)) * MAP_HEIGHT_SCALE;
  824. }
  825. else
  826. {
  827. // we are in the lower triangle
  828. float p1 = data[idx + 1];
  829. height = (p1 + fy*(p2-p1) + (1.0f-fx)*(p0-p1)) * MAP_HEIGHT_SCALE;
  830. }
  831. // DEBUG_ASSERTCRASH( height < 30, ("SOMEBODY THINKS THE CLIENT HEIGHTMAP IS GOOD ENOUGH FOR LOGIC SAMPLING."));
  832. if (normal) {
  833. // 9 8
  834. //
  835. //10 3-----2 7
  836. // | /|
  837. // | / |
  838. // |/ |
  839. //11 0-----1 6
  840. //
  841. // 4 5
  842. //Find surrounding grid points for smoothed normals.
  843. int idx4 = ix + (iy-1)*xExtent;
  844. int idx0 = ix + iy*xExtent;
  845. int idx3 = ix + iy*xExtent+xExtent;
  846. int idx9 = ix + (iy+2)*xExtent;
  847. UnsignedByte d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11;
  848. d0 = data[idx0];
  849. d1 = data[idx0+1];
  850. d2 = data[idx3+1];
  851. d3 = data[idx3];
  852. d4 = data[idx4];
  853. d5 = data[idx4+1];
  854. d6 = data[idx0+2];
  855. d7 = data[idx3+2];
  856. d8 = data[idx9+1];
  857. d9 = data[idx9];
  858. d10 = data[idx3-1];
  859. d11 = data[idx0-1];
  860. Real deltaZ_X0 = d1-d11;
  861. Real deltaZ_X1 = d6-d0;
  862. Real deltaZ_X2 = d7-d3;
  863. Real deltaZ_X3 = d6-d0;
  864. Real deltaZ_Y0 = d3-d4;
  865. Real deltaZ_Y1 = d2-d5;
  866. Real deltaZ_Y2 = d8-d1;
  867. Real deltaZ_Y3 = d9-d0;
  868. // Interpolate to get the smoothed valued.
  869. Real deltaZ_X_Left = deltaZ_X0*(1.0f-fx) + fx*deltaZ_X3;
  870. Real deltaZ_X_Right = deltaZ_X1*(1.0f-fx) + fx*deltaZ_X2;
  871. Real deltaZ_X = deltaZ_X_Left*(1.0-fy) + fy*deltaZ_X_Right;
  872. Real deltaZ_Y_Left = deltaZ_Y0*(1.0f-fx) + fx*deltaZ_Y3;
  873. Real deltaZ_Y_Right = deltaZ_Y1*(1.0f-fx) + fx*deltaZ_Y2;
  874. Real deltaZ_Y = deltaZ_Y_Left*(1.0-fy) + fy*deltaZ_Y_Right;
  875. Vector3 l2r, n2f, normalAtTexel;
  876. l2r.Set(2*MAP_XY_FACTOR/MAP_HEIGHT_SCALE, 0, deltaZ_X);
  877. n2f.Set(0, 2*MAP_XY_FACTOR/MAP_HEIGHT_SCALE, deltaZ_Y);
  878. Vector3::Normalized_Cross_Product(l2r,n2f, &normalAtTexel);
  879. normal->x = normalAtTexel.X;
  880. normal->y = normalAtTexel.Y;
  881. normal->z = normalAtTexel.Z;
  882. }
  883. return height;
  884. }
  885. //=============================================================================
  886. Bool BaseHeightMapRenderObjClass::isClearLineOfSight(const Coord3D& pos, const Coord3D& posOther) const
  887. {
  888. if (m_map == NULL)
  889. return false; // doh. should not happen.
  890. WorldHeightMap *logicHeightMap = TheTerrainVisual?TheTerrainVisual->getLogicHeightMap():m_map;
  891. #define DO_BRESENHAM
  892. #ifdef DO_BRESENHAM
  893. /*
  894. this is WAY faster, though not quite as accurate... however, the inaccuracy
  895. is pretty minimal, so we really should force other code to live with it. (srj)
  896. */
  897. const Real MAP_XY_FACTOR_INV = 1.0f / MAP_XY_FACTOR;
  898. Int borderSize = logicHeightMap->getBorderSizeInline();
  899. Int start_x = REAL_TO_INT_FLOOR(pos.x * MAP_XY_FACTOR_INV) + borderSize;
  900. Int start_y = REAL_TO_INT_FLOOR(pos.y * MAP_XY_FACTOR_INV) + borderSize;
  901. Int end_x = REAL_TO_INT_FLOOR(posOther.x * MAP_XY_FACTOR_INV) + borderSize;
  902. Int end_y = REAL_TO_INT_FLOOR(posOther.y * MAP_XY_FACTOR_INV) + borderSize;
  903. Int delta_x = abs(end_x - start_x); // The difference between the x's
  904. Int delta_y = abs(end_y - start_y); // The difference between the y's
  905. Int x = start_x; // Start x off at the first pixel
  906. Int y = start_y; // Start y off at the first pixel
  907. Int xinc1, xinc2;
  908. if (end_x >= start_x) // The x-values are increasing
  909. {
  910. xinc1 = 1;
  911. xinc2 = 1;
  912. }
  913. else // The x-values are decreasing
  914. {
  915. xinc1 = -1;
  916. xinc2 = -1;
  917. }
  918. Int yinc1, yinc2;
  919. if (end_y >= start_y) // The y-values are increasing
  920. {
  921. yinc1 = 1;
  922. yinc2 = 1;
  923. }
  924. else // The y-values are decreasing
  925. {
  926. yinc1 = -1;
  927. yinc2 = -1;
  928. }
  929. Int den, num, numadd, numpixels;
  930. Bool checkY = true;
  931. if (delta_x >= delta_y) // There is at least one x-value for every y-value
  932. {
  933. xinc1 = 0; // Don't change the x when numerator >= denominator
  934. yinc2 = 0; // Don't change the y for every iteration
  935. den = delta_x;
  936. num = delta_x / 2;
  937. numadd = delta_y;
  938. numpixels = delta_x; // There are more x-values than y-values
  939. }
  940. else // There is at least one y-value for every x-value
  941. {
  942. checkY = false;
  943. xinc2 = 0; // Don't change the x for every iteration
  944. yinc1 = 0; // Don't change the y when numerator >= denominator
  945. den = delta_y;
  946. num = delta_y / 2;
  947. numadd = delta_x;
  948. numpixels = delta_y; // There are more y-values than x-values
  949. }
  950. Real nsInv = 1.0f / numpixels;
  951. Real z = pos.z;
  952. Real dz = posOther.z - z;
  953. Real zinc = dz * nsInv;
  954. Bool result = true;
  955. const UnsignedByte* data = logicHeightMap->getDataPtr();
  956. Int xExtent = logicHeightMap->getXExtent();
  957. Int yExtent = logicHeightMap->getYExtent();
  958. for (Int curpixel = 0; curpixel < numpixels; curpixel++)
  959. {
  960. if (x < 0 ||
  961. y < 0 ||
  962. x >= xExtent-1 ||
  963. y >= yExtent-1)
  964. {
  965. // once we go off the map, we're done
  966. break;
  967. }
  968. Int idx = x + y*xExtent;
  969. float height = data[idx];
  970. height = __max(height, data[idx + 1]);
  971. height = __max(height, data[idx + xExtent]);
  972. height = __max(height, data[idx + xExtent + 1]);
  973. height *= MAP_HEIGHT_SCALE;
  974. // if terrainHeight > z, we can't see, so punt.
  975. // add a little fudge to account for slop.
  976. const Real LOS_FUDGE = 0.5f;
  977. if (height > z + LOS_FUDGE)
  978. {
  979. result = false;
  980. break;
  981. }
  982. // we're above the max height of the terrain and still looking up, so we're done.
  983. // (don't bother for reverse test, since that doesn't generally happen)
  984. if (z >= getMaxHeight() && zinc > 0.0f)
  985. {
  986. break;
  987. }
  988. z += zinc;
  989. // continue with the maintenance.
  990. num += numadd; // Increase the numerator by the top of the fraction
  991. if (num >= den) // Check if numerator >= denominator
  992. {
  993. num -= den; // Calculate the new numerator value
  994. x += xinc1; // Change the x as appropriate
  995. y += yinc1; // Change the y as appropriate
  996. }
  997. x += xinc2; // Change the x as appropriate
  998. y += yinc2; // Change the y as appropriate
  999. }
  1000. return result;
  1001. #else
  1002. // walk a line from obj to objOther and
  1003. // find the highest point in between 'em. while
  1004. // we're doing this, also estimate the point on the
  1005. // line at the same x,y as the high-terrain-point.
  1006. Real fx = pos.x;
  1007. Real fy = pos.y;
  1008. Real fz = pos.z;
  1009. Real fdx = posOther.x - fx;
  1010. Real fdy = posOther.y - fy;
  1011. Real fdz = posOther.z - fz;
  1012. // What's the largest step size that will be accurate enough?
  1013. // Currently we use a step size of about 2 "feet", which
  1014. // seems acceptable accuracy. If performance here is inadequate,
  1015. // we can try increasing the step size, but be sure to retest
  1016. // accuracy.
  1017. Real len = ceilf(sqrtf(fdx*fdx + fdy*fdy));
  1018. const Real STEP_LEN = 2.0f;
  1019. Int numSteps = REAL_TO_INT_CEIL(len / STEP_LEN);
  1020. if (numSteps < 1) numSteps = 1;
  1021. Real fnsInv = 1.0f / numSteps;
  1022. Real fxinc = fdx * fnsInv;
  1023. Real fyinc = fdy * fnsInv;
  1024. Real fzinc = fdz * fnsInv;
  1025. while (numSteps--)
  1026. {
  1027. Real terrainHeight = getHeightMapHeight( fx, fy, NULL );
  1028. // if terrainHeight > fz, we can't see, so punt.
  1029. // add a little fudge to account for slop.
  1030. const Real LOS_FUDGE = 0.5f;
  1031. if (terrainHeight > fz + LOS_FUDGE)
  1032. {
  1033. return false;
  1034. }
  1035. // we're above the max height of the terrain and still looking up, so we're done.
  1036. // (don't bother for reverse test, since that doesn't generally happen)
  1037. if (fz >= getMaxHeight() && fzinc > 0.0f)
  1038. {
  1039. return true;
  1040. }
  1041. fx += fxinc;
  1042. fy += fyinc;
  1043. fz += fzinc;
  1044. }
  1045. return true;
  1046. #endif
  1047. }
  1048. //=============================================================================
  1049. // BaseHeightMapRenderObjClass::getMaxCellHeight
  1050. //=============================================================================
  1051. /** Returns maximum height of the 4 corners containing the given point */
  1052. //=============================================================================
  1053. Real BaseHeightMapRenderObjClass::getMaxCellHeight(Real x, Real y) const
  1054. {
  1055. float p0,p1,p2,p3;
  1056. float height;
  1057. // 3-----2
  1058. // | /|
  1059. // | / |
  1060. // |/ |
  1061. // 0-----1
  1062. //Find surrounding grid points
  1063. if (m_map == NULL)
  1064. { //sample point is not on the heightmap
  1065. return 0.0f; //return default height
  1066. }
  1067. WorldHeightMap *logicHeightMap = TheTerrainVisual?TheTerrainVisual->getLogicHeightMap():m_map;
  1068. Int offset = 1;
  1069. Int iX = x/MAP_XY_FACTOR;
  1070. Int iY = y/MAP_XY_FACTOR;
  1071. iX += logicHeightMap->getBorderSizeInline();
  1072. iY += logicHeightMap->getBorderSizeInline();
  1073. if (iX<0) iX = 0;
  1074. if (iY<0) iY = 0;
  1075. if (iX >= (logicHeightMap->getXExtent()-1)) {
  1076. iX = logicHeightMap->getXExtent()-2;
  1077. }
  1078. if (iY >= (logicHeightMap->getYExtent()-1)) {
  1079. iY = logicHeightMap->getYExtent()-2;
  1080. }
  1081. UnsignedByte *data = logicHeightMap->getDataPtr();
  1082. p0=data[iX+iY*logicHeightMap->getXExtent()]*MAP_HEIGHT_SCALE;
  1083. p1=data[(iX+offset)+iY*logicHeightMap->getXExtent()]*MAP_HEIGHT_SCALE;
  1084. p2=data[(iX+offset)+(iY+offset)*logicHeightMap->getXExtent()]*MAP_HEIGHT_SCALE;
  1085. p3=data[iX+(iY+offset)*logicHeightMap->getXExtent()]*MAP_HEIGHT_SCALE;
  1086. height=p0;
  1087. height=__max(height,p1);
  1088. height=__max(height,p2);
  1089. height=__max(height,p3);
  1090. return height;
  1091. }
  1092. //=============================================================================
  1093. // BaseHeightMapRenderObjClass::isCliffCell
  1094. //=============================================================================
  1095. /** Returns true if the cell containing the point is a cliff cell */
  1096. //=============================================================================
  1097. Bool BaseHeightMapRenderObjClass::isCliffCell(Real x, Real y)
  1098. {
  1099. if (m_map == NULL)
  1100. { //sample point is not on the heightmap
  1101. return false;
  1102. }
  1103. WorldHeightMap *logicHeightMap = TheTerrainVisual?TheTerrainVisual->getLogicHeightMap():m_map;
  1104. Int iX = x/MAP_XY_FACTOR;
  1105. Int iY = y/MAP_XY_FACTOR;
  1106. iX += logicHeightMap->getBorderSizeInline();
  1107. iY += logicHeightMap->getBorderSizeInline();
  1108. if (iX<0) iX = 0;
  1109. if (iY<0) iY = 0;
  1110. if (iX >= (logicHeightMap->getXExtent()-1)) {
  1111. iX = logicHeightMap->getXExtent()-2;
  1112. }
  1113. if (iY >= (logicHeightMap->getYExtent()-1)) {
  1114. iY = logicHeightMap->getYExtent()-2;
  1115. }
  1116. return logicHeightMap->getCliffState(iX, iY);
  1117. }
  1118. //=============================================================================
  1119. //=============================================================================
  1120. Bool BaseHeightMapRenderObjClass::showAsVisibleCliff(Int xIndex, Int yIndex) const
  1121. {
  1122. if (m_map == NULL)
  1123. {
  1124. return false;
  1125. }
  1126. Int xSize = m_map->getXExtent();
  1127. return m_showAsVisibleCliff[xIndex + yIndex * xSize];
  1128. }
  1129. //=============================================================================
  1130. //=============================================================================
  1131. Bool BaseHeightMapRenderObjClass::evaluateAsVisibleCliff(Int xIndex, Int yIndex, Real valuesGreaterThanRad)
  1132. {
  1133. // This one never changes, so don't bother recomputing it.
  1134. static const Real distance[4] =
  1135. {
  1136. 0.0f,
  1137. 1.0 * MAP_XY_FACTOR,
  1138. sqrt(2.0f) * MAP_XY_FACTOR,
  1139. 1.0 * MAP_XY_FACTOR,
  1140. };
  1141. // Note: getHeight will protect us from going out of bounds by returning 0 if we give it
  1142. // a value outside of its bounds.
  1143. UnsignedByte bytes[4] =
  1144. {
  1145. m_map->getHeight(xIndex + 0, yIndex + 0),
  1146. m_map->getHeight(xIndex + 1, yIndex + 0),
  1147. m_map->getHeight(xIndex + 1, yIndex + 1),
  1148. m_map->getHeight(xIndex + 0, yIndex + 1),
  1149. };
  1150. Real heights[4] =
  1151. {
  1152. INT_TO_REAL(bytes[0]) * MAP_HEIGHT_SCALE,
  1153. INT_TO_REAL(bytes[1]) * MAP_HEIGHT_SCALE,
  1154. INT_TO_REAL(bytes[2]) * MAP_HEIGHT_SCALE,
  1155. INT_TO_REAL(bytes[3]) * MAP_HEIGHT_SCALE,
  1156. };
  1157. Bool anyImpassable = FALSE;
  1158. for (Int i = 1; i < 4 && !anyImpassable; ++i) {
  1159. if (fabs((heights[i] - heights[0]) / distance[i]) > valuesGreaterThanRad) {
  1160. anyImpassable = TRUE;
  1161. }
  1162. }
  1163. return anyImpassable;
  1164. }
  1165. //=============================================================================
  1166. // BaseHeightMapRenderObjClass::oversizeTerrain
  1167. //=============================================================================
  1168. /** Sets the terrain oversize amount. */
  1169. //=============================================================================
  1170. void BaseHeightMapRenderObjClass::oversizeTerrain(Int tilesToOversize)
  1171. {
  1172. // Not needed with flat version. [3/20/2003]
  1173. }
  1174. //=============================================================================
  1175. // BaseHeightMapRenderObjClass::Get_Obj_Space_Bounding_Sphere
  1176. //=============================================================================
  1177. /** WW3D method that returns object bounding sphere used in frustum culling*/
  1178. //=============================================================================
  1179. void BaseHeightMapRenderObjClass::Get_Obj_Space_Bounding_Sphere(SphereClass & sphere) const
  1180. {
  1181. Int x = 0; Int y = 0;
  1182. if (m_map) {
  1183. x = m_map->getXExtent();
  1184. y = m_map->getYExtent();
  1185. }
  1186. Vector3 ObjSpaceCenter((float)x*0.5f*MAP_XY_FACTOR,(float)y*0.5f*MAP_XY_FACTOR,(float)m_minHeight+(m_maxHeight-m_minHeight)*0.5f);
  1187. float length = ObjSpaceCenter.Length();
  1188. if (m_map) {
  1189. ObjSpaceCenter.X += m_map->getDrawOrgX()*MAP_XY_FACTOR;
  1190. ObjSpaceCenter.Y += m_map->getDrawOrgY()*MAP_XY_FACTOR;
  1191. }
  1192. sphere.Init(ObjSpaceCenter, length);
  1193. }
  1194. //=============================================================================
  1195. // BaseHeightMapRenderObjClass::Get_Obj_Space_Bounding_Box
  1196. //=============================================================================
  1197. /** WW3D method that returns object bounding box used in collision detection*/
  1198. //=============================================================================
  1199. void BaseHeightMapRenderObjClass::Get_Obj_Space_Bounding_Box(AABoxClass & box) const
  1200. {
  1201. Int x = 0; Int y = 0;
  1202. if (m_map) {
  1203. x = m_map->getXExtent();
  1204. y = m_map->getYExtent();
  1205. }
  1206. Vector3 minPt(0,0,m_minHeight);
  1207. Vector3 maxPt((float)x*MAP_XY_FACTOR,(float)y*MAP_XY_FACTOR,(float)m_maxHeight);
  1208. MinMaxAABoxClass minMaxBox(minPt, maxPt);
  1209. box.Init(minMaxBox);
  1210. }
  1211. //-------------------------------------------------------------------------------------------------
  1212. /** Get the 3D extent of the terrain visible through the camera. Return value
  1213. is false if no part of terrain is visible. This function returns a worse
  1214. case bounding volume based on lowest/highest points in entire terrain. It
  1215. does not optimize the volume to heights actually visible. Unlike some of
  1216. the other methods, this function is guaranteed not to miss any visible
  1217. polygons. The ignoreMaxHeight flag is used to return a box that uses the
  1218. camera position as the maximum height instead of the terrain - good for getting
  1219. a volume enclosing things that can float above terrain.
  1220. */
  1221. //-------------------------------------------------------------------------------------------------
  1222. Bool BaseHeightMapRenderObjClass::getMaximumVisibleBox(const FrustumClass &frustum, AABoxClass *box, Bool ignoreMaxHeight)
  1223. {
  1224. //create a plane from the lowest point on the terrain
  1225. PlaneClass groundPlane(Vector3(0,0,1), m_minHeight);
  1226. //clip each side of the view frustum to ground plane
  1227. float clipFraction;
  1228. Vector3 ClippedCorners[8];
  1229. ClippedCorners[0]=frustum.Corners[0];
  1230. for (Int i=0; i<4; i++)
  1231. { ClippedCorners[i]=frustum.Corners[i];
  1232. if (groundPlane.Compute_Intersection(frustum.Corners[i],frustum.Corners[i+4],&clipFraction))
  1233. { //edge intersects the terrain
  1234. ClippedCorners[i+4]=frustum.Corners[i]+(frustum.Corners[i+4]-frustum.Corners[i])*clipFraction;
  1235. }
  1236. else
  1237. ClippedCorners[i+4]=frustum.Corners[i+4];
  1238. }
  1239. if (box)
  1240. box->Init(ClippedCorners,8);
  1241. return TRUE;
  1242. }
  1243. //=============================================================================
  1244. // BaseHeightMapRenderObjClass::Class_ID
  1245. //=============================================================================
  1246. /** returns the class id, so the scene can tell what kind of render object it has. */
  1247. //=============================================================================
  1248. Int BaseHeightMapRenderObjClass::Class_ID(void) const
  1249. {
  1250. return RenderObjClass::CLASSID_TILEMAP;
  1251. }
  1252. //=============================================================================
  1253. // BaseHeightMapRenderObjClass::Clone
  1254. //=============================================================================
  1255. /** Not used, but required virtual method. */
  1256. //=============================================================================
  1257. RenderObjClass * BaseHeightMapRenderObjClass::Clone(void) const
  1258. {
  1259. assert(false);
  1260. return NULL;
  1261. }
  1262. //=============================================================================
  1263. // BaseHeightMapRenderObjClass::loadRoadsAndBridges
  1264. //=============================================================================
  1265. /** Loads the roads from the map objects. */
  1266. //=============================================================================
  1267. void BaseHeightMapRenderObjClass::loadRoadsAndBridges(W3DTerrainLogic *pTerrainLogic, Bool saveGame)
  1268. {
  1269. if (DX8Wrapper::_Get_D3D_Device8() && (DX8Wrapper::_Get_D3D_Device8()->TestCooperativeLevel()) != D3D_OK)
  1270. return; //device not ready to render anything
  1271. #ifdef DO_ROADS
  1272. if (m_roadBuffer) {
  1273. m_roadBuffer->loadRoads();
  1274. }
  1275. #endif
  1276. if (m_bridgeBuffer) {
  1277. m_bridgeBuffer->loadBridges(pTerrainLogic, saveGame);
  1278. }
  1279. }
  1280. // ============================================================================
  1281. // BaseHeightMapRenderObjClass::worldBuilderUpdateBridgeTowers
  1282. // ============================================================================
  1283. /** The worldbuilder has it's own method here to update the visual representation
  1284. * of the bridge towers */
  1285. // ============================================================================
  1286. void BaseHeightMapRenderObjClass::worldBuilderUpdateBridgeTowers( W3DAssetManager *assetManager,
  1287. SimpleSceneClass *scene )
  1288. {
  1289. if( m_bridgeBuffer )
  1290. m_bridgeBuffer->worldBuilderUpdateBridgeTowers( assetManager, scene );
  1291. }
  1292. void BaseHeightMapRenderObjClass::setShoreLineDetail(void)
  1293. {
  1294. if (!m_map)
  1295. return;
  1296. Int m_mapDX=m_map->getXExtent();
  1297. Int m_mapDY=m_map->getYExtent();
  1298. //Find all shoreline tiles so they can get extra alpha blend
  1299. updateShorelineTiles(0,0,m_mapDX-1,m_mapDY-1,m_map);
  1300. }
  1301. /** This is an extra pre-process of shoreline data to make it more efficient for runtime culling. It is not
  1302. used by the world builder since it modifies the terrain too frequently. The function also assumes that updateShoreLineTiles()
  1303. was previously called and inserted the tiles in the correctly sorted order.
  1304. WARNING!!! Current version assumes we always sort the entire map! So don't set parameters to partial updates! */
  1305. void BaseHeightMapRenderObjClass::recordShoreLineSortInfos(void)
  1306. {
  1307. if (TheGlobalData->m_isWorldBuilder || !m_shoreLineTilePositions || !m_map)
  1308. return; //we must be in the builder so don't sort.
  1309. //Find how many sortinfos we need.
  1310. Int shoreLineSortInfosSize = m_map->getXExtent()-1;
  1311. Bool shoreLineSortInfosXMajor=TRUE;
  1312. if (shoreLineSortInfosSize <= (m_map->getYExtent()-1))
  1313. { shoreLineSortInfosSize = m_map->getYExtent()-1;
  1314. shoreLineSortInfosXMajor=FALSE;
  1315. }
  1316. m_shoreLineSortInfosXMajor= shoreLineSortInfosXMajor;
  1317. //Check if we need to allocate memory
  1318. if (!m_shoreLineSortInfos || shoreLineSortInfosSize > m_shoreLineSortInfosSize)
  1319. {
  1320. if (m_shoreLineSortInfos)
  1321. delete [] m_shoreLineSortInfos; //old buffer was too small.
  1322. //Find the major map axis (having the most tiles).
  1323. m_shoreLineSortInfosSize = shoreLineSortInfosSize;
  1324. m_shoreLineSortInfos = NEW shoreLineTileSortInfo[m_shoreLineSortInfosSize];
  1325. }
  1326. //Clear the sort infos
  1327. memset(m_shoreLineSortInfos,0,sizeof(shoreLineTileSortInfo)*m_shoreLineSortInfosSize);
  1328. if (m_shoreLineSortInfosXMajor) //map is wider than taller, so tiles are already sorted by x
  1329. {
  1330. //scan all the tiles and record batches of tiles using same x value.
  1331. m_shoreLineTileSortMaxCoordinate=m_shoreLineTileSortMinCoordinate=(m_shoreLineTilePositions[0].m_xy & 0xffff);
  1332. for (Int i=0; i<m_numShoreLineTiles; i++)
  1333. {
  1334. Int x=(m_shoreLineTilePositions[i].m_xy & 0xffff);
  1335. shoreLineTileSortInfo *sortInfo=&m_shoreLineSortInfos[x];
  1336. if (x > m_shoreLineTileSortMaxCoordinate)
  1337. m_shoreLineTileSortMaxCoordinate=x;
  1338. //find number of tiles in a row using same y coordinate.
  1339. Int j=i+1;
  1340. Int minY,maxY;
  1341. minY=maxY=m_shoreLineTilePositions[i].m_xy >> 16;
  1342. while ((m_shoreLineTilePositions[j].m_xy & 0xffff) == x && j < m_numShoreLineTiles)
  1343. { //keep track of highest y coordinate.
  1344. Int y = m_shoreLineTilePositions[j].m_xy >> 16;
  1345. if (y > maxY)
  1346. maxY=y;
  1347. j++;
  1348. }
  1349. sortInfo->tileStartIndex=i;
  1350. sortInfo->numTiles=j-i;
  1351. sortInfo->minTileCoordinate=minY;
  1352. sortInfo->maxTileCoordinate=maxY;
  1353. i += sortInfo->numTiles-1; //skip tiles we just scanned.
  1354. }
  1355. }
  1356. else //map is taller than wider so tiles are already sorted by y
  1357. {
  1358. //scan all the tiles and record batches of tiles using same y value.
  1359. m_shoreLineTileSortMaxCoordinate=m_shoreLineTileSortMinCoordinate=(m_shoreLineTilePositions[0].m_xy >> 16);
  1360. for (Int i=0; i<m_numShoreLineTiles; i++)
  1361. {
  1362. Int y=(m_shoreLineTilePositions[i].m_xy >> 16);
  1363. shoreLineTileSortInfo *sortInfo=&m_shoreLineSortInfos[y];
  1364. if (y > m_shoreLineTileSortMaxCoordinate)
  1365. m_shoreLineTileSortMaxCoordinate=y;
  1366. //find number of tiles in a row using same y coordinate.
  1367. Int j=i+1;
  1368. Int minX,maxX;
  1369. minX=maxX=m_shoreLineTilePositions[i].m_xy & 0xffff;
  1370. while ((m_shoreLineTilePositions[j].m_xy >> 16) == y && j < m_numShoreLineTiles)
  1371. { //keep track of highest x coordinate.
  1372. Int x = m_shoreLineTilePositions[j].m_xy & 0xffff;
  1373. if (x > maxX)
  1374. maxX=x;
  1375. j++;
  1376. }
  1377. sortInfo->tileStartIndex=i;
  1378. sortInfo->numTiles=j-i;
  1379. sortInfo->minTileCoordinate=minX;
  1380. sortInfo->maxTileCoordinate=maxX;
  1381. i += sortInfo->numTiles-1; //skip tiles we just scanned.
  1382. }
  1383. }
  1384. }
  1385. void BaseHeightMapRenderObjClass::updateShorelineTile(Int i, Int j, Int border, WorldHeightMap *pMap)
  1386. {
  1387. Int waterSide;
  1388. Real waterZ0,waterZ1,waterZ2,waterZ3;
  1389. Real terrainZ0, terrainZ1, terrainZ2, terrainZ3;
  1390. //Figure out maximum depth of water before we reach the m_minWaterOpacity value. Depths greater than this don't need
  1391. //custom shoreline tiles because they will get their opacity from the default value stored in the frame buffer during
  1392. //a screen clear operation.
  1393. Real transparentDepth=TheWaterTransparency->m_transparentWaterDepth*TheWaterTransparency->m_minWaterOpacity;
  1394. Real depthScaleFactor = 1.0f/transparentDepth;
  1395. Real X0=(i-border)*MAP_XY_FACTOR;
  1396. Real Y0=(j-border)*MAP_XY_FACTOR;
  1397. waterSide=(waterZ0=TheWaterRenderObj->getWaterHeight(X0,Y0)) > ((terrainZ0=MAP_HEIGHT_SCALE*pMap->getHeight(i,j)));
  1398. Real X1=(i-border+1)*MAP_XY_FACTOR;
  1399. Real Y1=(j-border+1)*MAP_XY_FACTOR;
  1400. waterSide |=((waterZ1=TheWaterRenderObj->getWaterHeight(X1,Y0)) > ((terrainZ1=MAP_HEIGHT_SCALE*pMap->getHeight(i+1,j)))) << 1;
  1401. waterSide |=((waterZ2=TheWaterRenderObj->getWaterHeight(X1,Y1)) > ((terrainZ2=MAP_HEIGHT_SCALE*pMap->getHeight(i+1,j+1)))) << 2;
  1402. waterSide |=((waterZ3=TheWaterRenderObj->getWaterHeight(X0,Y1)) > ((terrainZ3=MAP_HEIGHT_SCALE*pMap->getHeight(i,j+1)))) << 3;
  1403. if (!waterSide || (waterZ0*waterZ1*waterZ2*waterZ3) <= 0)
  1404. return; //all verts are on positive (surface) side of water so don't need blending. Or one of them is outside the water plane bounds (waterHeight <= 0!)
  1405. //Check if mix of under/over water vertices or some vertices within depth fade region.
  1406. if (waterSide < 0xf || (waterZ0 - terrainZ0) < transparentDepth ||
  1407. (waterZ1 - terrainZ1) < transparentDepth || (waterZ2 - terrainZ2) < transparentDepth
  1408. || (waterZ3 - terrainZ3) < transparentDepth)
  1409. { //add tile to set that needs shoreline blending.
  1410. if (m_numShoreLineTiles >= m_shoreLineTilePositionsSize)
  1411. { //no more room to store extra blend tiles so enlarge the buffer.
  1412. shoreLineTileInfo *tempPositions=NEW shoreLineTileInfo[m_shoreLineTilePositionsSize+512];
  1413. memcpy(tempPositions, m_shoreLineTilePositions, m_shoreLineTilePositionsSize*sizeof(shoreLineTileInfo));
  1414. delete [] m_shoreLineTilePositions;
  1415. //enlarge by more tiles to reduce memory trashing
  1416. m_shoreLineTilePositions = tempPositions;
  1417. m_shoreLineTilePositionsSize += 512;
  1418. }
  1419. //Pack x and y position into single integer since maps are limited in size
  1420. shoreLineTileInfo *shoreInfo=&m_shoreLineTilePositions[m_numShoreLineTiles];
  1421. shoreInfo->m_xy=i | (j <<16);
  1422. shoreInfo->verts[0]=X0; shoreInfo->verts[1]=Y0; shoreInfo->verts[2]=terrainZ0;
  1423. shoreInfo->t0=(waterZ0 - terrainZ0)*depthScaleFactor;
  1424. shoreInfo->verts[3]=X1; shoreInfo->verts[4]=Y0; shoreInfo->verts[5]=terrainZ1;
  1425. shoreInfo->t1=(waterZ1 - terrainZ1)*depthScaleFactor;
  1426. shoreInfo->verts[6]=X1; shoreInfo->verts[7]=Y1; shoreInfo->verts[8]=terrainZ2;
  1427. shoreInfo->t2=(waterZ2 - terrainZ2)*depthScaleFactor;
  1428. shoreInfo->verts[9]=X0; shoreInfo->verts[10]=Y1; shoreInfo->verts[11]=terrainZ3;
  1429. shoreInfo->t3=(waterZ3 - terrainZ3)*depthScaleFactor;
  1430. m_numShoreLineTiles++;
  1431. }
  1432. }
  1433. /**Scan through our map and record all tiles which cross a water plane and are within visible depth under
  1434. water.*/
  1435. void BaseHeightMapRenderObjClass::updateShorelineTiles(Int minX, Int minY, Int maxX, Int maxY, WorldHeightMap *pMap)
  1436. {
  1437. Int border = pMap->getBorderSizeInline();
  1438. //Clamp region to valid terrain tiles
  1439. if (minX<0)
  1440. minX = 0;
  1441. if (minY<0)
  1442. minY = 0;
  1443. if (maxX > (pMap->getXExtent() - 1))
  1444. maxX = (pMap->getXExtent() - 1);
  1445. if (maxY > (pMap->getYExtent() - 1))
  1446. maxY = (pMap->getYExtent() - 1);
  1447. if (!m_shoreLineTilePositions)
  1448. { //Need to allocate memory
  1449. m_shoreLineTilePositions = NEW shoreLineTileInfo[DEFAULT_MAX_MAP_SHORELINE_TILES];
  1450. m_shoreLineTilePositionsSize = DEFAULT_MAX_MAP_SHORELINE_TILES;
  1451. }
  1452. //First remove any existing extra blend tiles within this partial region
  1453. for (Int j=0; j<m_numShoreLineTiles; j++)
  1454. { Int x = m_shoreLineTilePositions[j].m_xy & 0xffff;
  1455. Int y = m_shoreLineTilePositions[j].m_xy >> 16;
  1456. if (x >= minX && x < maxX &&
  1457. y >= minY && y < maxY)
  1458. { //this tile is inside region being updated so remove it by shifting tile array
  1459. memcpy(m_shoreLineTilePositions+j,m_shoreLineTilePositions+j+1,(m_numShoreLineTiles-1-j)*sizeof(shoreLineTileInfo));
  1460. m_numShoreLineTiles--;
  1461. j--; //look at current tile again since it was removed.
  1462. }
  1463. }
  1464. if (TheWaterTransparency->m_transparentWaterDepth == 0 || !TheGlobalData->m_showSoftWaterEdge)
  1465. return;
  1466. //we want to add the tiles in a certain order to make culling faster
  1467. //by default they are inserted in x-order
  1468. Bool shoreLineSortInfosXMajor=FALSE;
  1469. if (!TheGlobalData->m_isWorldBuilder) //we're in the game, not the builder
  1470. {
  1471. if ((m_map->getXExtent()-1) > (m_map->getYExtent()-1))
  1472. shoreLineSortInfosXMajor=TRUE;
  1473. }
  1474. if (shoreLineSortInfosXMajor)
  1475. for (Int i=minX; i<maxX; i++)
  1476. for (j=minY; j<maxY; j++)
  1477. {
  1478. updateShorelineTile(i,j,border,pMap);
  1479. }
  1480. else
  1481. for (j=minY; j<maxY; j++)
  1482. for (Int i=minX; i<maxX; i++)
  1483. {
  1484. updateShorelineTile(i,j,border,pMap);
  1485. }
  1486. recordShoreLineSortInfos();
  1487. }
  1488. /** Generate a lookup table for arbitrary angled impassable area viewing. */
  1489. void BaseHeightMapRenderObjClass::updateViewImpassableAreas(Bool partial, Int minX, Int maxX, Int minY, Int maxY)
  1490. {
  1491. Int xSize = m_map->getXExtent();
  1492. Int ySize = m_map->getYExtent();
  1493. if (m_showAsVisibleCliff.size() != xSize * ySize) {
  1494. m_showAsVisibleCliff.resize(xSize * ySize);
  1495. }
  1496. if (!partial) {
  1497. minX = 0;
  1498. minY = 0;
  1499. maxX = xSize;
  1500. maxY = ySize;
  1501. }
  1502. // save calculating the tangent over and over again.
  1503. Real tanImpassableRad = tan(m_curImpassableSlope / 360.f * 2 * PI);
  1504. for (Int j = minY; j < maxY; ++j) {
  1505. for (Int i = minX; i < maxX; ++i) {
  1506. m_showAsVisibleCliff[i + j * xSize] = evaluateAsVisibleCliff(i, j, tanImpassableRad);
  1507. }
  1508. }
  1509. }
  1510. /** Generate a lookup table which can be used to generate an
  1511. alpha value from a given set of uv coordinates. Currently used
  1512. for smoothing water/terrain border*/
  1513. void BaseHeightMapRenderObjClass::initDestAlphaLUT(void)
  1514. {
  1515. if (!m_destAlphaTexture)
  1516. return;
  1517. SurfaceClass *surf=m_destAlphaTexture->Get_Surface_Level();
  1518. if (surf)
  1519. {
  1520. Int pitch;
  1521. UnsignedInt *pData=(UnsignedInt*)surf->Lock(&pitch);
  1522. Int maxOpacity=(Int)(TheWaterTransparency->m_minWaterOpacity * 255.0f);
  1523. Int alpha;
  1524. if (pData)
  1525. {
  1526. //Fill texture with alpha gradient
  1527. for (Int x=0; x<256; x++)
  1528. {
  1529. alpha = x;
  1530. if (alpha > maxOpacity)
  1531. alpha = maxOpacity;
  1532. *pData=(alpha<<24)|0x00ffffff;
  1533. pData++;
  1534. }
  1535. surf->Unlock();
  1536. }
  1537. m_destAlphaTexture->Get_Filter().Set_U_Addr_Mode(TextureFilterClass::TEXTURE_ADDRESS_CLAMP);
  1538. m_destAlphaTexture->Get_Filter().Set_V_Addr_Mode(TextureFilterClass::TEXTURE_ADDRESS_CLAMP);
  1539. REF_PTR_RELEASE(surf);
  1540. m_currentMinWaterOpacity = TheWaterTransparency->m_minWaterOpacity;
  1541. }
  1542. }
  1543. //=============================================================================
  1544. // BaseHeightMapRenderObjClass::initHeightData
  1545. //=============================================================================
  1546. /** Allocate a heightmap of x by y vertices and fill with initial height values.
  1547. Also allocates all rendering resources such as vertex buffers, index buffers,
  1548. shaders, and materials.*/
  1549. //=============================================================================
  1550. Int BaseHeightMapRenderObjClass::initHeightData(Int x, Int y, WorldHeightMap *pMap, RefRenderObjListIterator *pLightsIteratork, Bool updateExtraPassTiles)
  1551. {
  1552. REF_PTR_SET(m_map, pMap); //update our heightmap pointer in case it changed since last call.
  1553. if (m_shroud)
  1554. m_shroud->init(m_map,TheGlobalData->m_partitionCellSize,TheGlobalData->m_partitionCellSize);
  1555. #ifdef DO_ROADS
  1556. m_roadBuffer->setMap(m_map);
  1557. #endif
  1558. HeightSampleType *data = NULL;
  1559. if (pMap) {
  1560. data = pMap->getDataPtr();
  1561. }
  1562. if (m_treeBuffer) {
  1563. Region2D bounds;
  1564. bounds.lo.x = 0;
  1565. bounds.lo.y = 0;
  1566. bounds.hi.x = (pMap->getXExtent() - 2*pMap->getBorderSize()) *MAP_XY_FACTOR;
  1567. bounds.hi.y = (pMap->getYExtent() - 2*pMap->getBorderSize()) *MAP_XY_FACTOR;
  1568. m_treeBuffer->setBounds(bounds);
  1569. }
  1570. if (updateExtraPassTiles)
  1571. {
  1572. m_numShoreLineTiles = 0;
  1573. //Do some preprocessing on map to extract useful data
  1574. if (pMap)
  1575. {
  1576. //Find min/max values for all terrain heights, useful for rendering optimization
  1577. Int m_mapDX=pMap->getXExtent();
  1578. Int m_mapDY=pMap->getYExtent();
  1579. Int i, j, minHt, maxHt;
  1580. minHt = pMap->getMaxHeightValue();
  1581. maxHt = 0;
  1582. for (j=0; j<m_mapDY; j++) {
  1583. for (i=0; i<m_mapDX; i++) {
  1584. Short cur = pMap->getHeight(i,j);
  1585. if (cur<minHt) minHt = cur;
  1586. if (maxHt<cur) maxHt = cur;
  1587. }
  1588. }
  1589. m_minHeight = minHt * MAP_HEIGHT_SCALE;
  1590. m_maxHeight = maxHt * MAP_HEIGHT_SCALE;
  1591. //Find all shoreline tiles so they can get extra alpha blend
  1592. updateShorelineTiles(0,0,m_mapDX-1,m_mapDY-1,pMap);
  1593. if (TheWaterTransparency->m_minWaterOpacity != m_currentMinWaterOpacity)
  1594. initDestAlphaLUT();
  1595. }
  1596. }
  1597. Set_Force_Visible(TRUE); //terrain is always visible.
  1598. m_needFullUpdate = true;
  1599. m_scorchesInBuffer = 0;
  1600. m_curNumScorchVertices=0;
  1601. m_curNumScorchIndices=0;
  1602. // If the textures aren't allocated (usually because of a hardware reset) need to allocate.
  1603. Bool needToAllocate = false;
  1604. if (m_stageTwoTexture == NULL) {
  1605. needToAllocate = true;
  1606. }
  1607. if (data && needToAllocate)
  1608. { //requested heightmap different from old one.
  1609. //allocate a new one.
  1610. freeMapResources(); //free old data and ib/vb
  1611. REF_PTR_SET(m_map,pMap); //update our heightmap pointer in case it changed since last call.
  1612. m_stageTwoTexture=NEW CloudMapTerrainTextureClass;
  1613. m_stageThreeTexture=NEW LightMapTerrainTextureClass(m_macroTextureName);
  1614. m_destAlphaTexture=MSGNEW("TextureClass") TextureClass(256,1,WW3D_FORMAT_A8R8G8B8,MIP_LEVELS_1);
  1615. initDestAlphaLUT();
  1616. #ifdef DO_SCORCH
  1617. allocateScorchBuffers();
  1618. #endif
  1619. m_vertexMaterialClass=VertexMaterialClass::Get_Preset(VertexMaterialClass::PRELIT_DIFFUSE);
  1620. m_shaderClass = detailOpaqueShader; // ShaderClass::_PresetOpaqueShader;
  1621. }
  1622. return 0;
  1623. }
  1624. #ifdef DO_SCORCH
  1625. //=============================================================================
  1626. // BaseHeightMapRenderObjClass::freeScorchBuffers
  1627. //=============================================================================
  1628. /** Frees the vertex buffers for scorches.*/
  1629. //=============================================================================
  1630. void BaseHeightMapRenderObjClass::freeScorchBuffers(void)
  1631. {
  1632. REF_PTR_RELEASE(m_vertexScorch);
  1633. REF_PTR_RELEASE(m_indexScorch);
  1634. REF_PTR_RELEASE(m_scorchTexture);
  1635. }
  1636. //=============================================================================
  1637. // BaseHeightMapRenderObjClass::allocateScorchBuffers
  1638. //=============================================================================
  1639. /** Allocates the vertex buffer and texture for scorches.*/
  1640. //=============================================================================
  1641. void BaseHeightMapRenderObjClass::allocateScorchBuffers(void)
  1642. {
  1643. m_vertexScorch=NEW_REF(DX8VertexBufferClass,(DX8_FVF_XYZDUV1,MAX_SCORCH_VERTEX,DX8VertexBufferClass::USAGE_DEFAULT));
  1644. m_indexScorch=NEW_REF(DX8IndexBufferClass,(MAX_SCORCH_INDEX));
  1645. m_scorchTexture=NEW ScorchTextureClass;
  1646. m_scorchesInBuffer = 0; // If we just allocated the buffers, we got no scorches in the buffer.
  1647. m_curNumScorchVertices=0;
  1648. m_curNumScorchIndices=0;
  1649. #ifdef _DEBUG
  1650. Vector3 loc(4*MAP_XY_FACTOR,4*MAP_XY_FACTOR,0);
  1651. addScorch(loc, 1*MAP_XY_FACTOR, SCORCH_1);
  1652. loc.Y += 10*MAP_XY_FACTOR;
  1653. loc.X += 5*MAP_XY_FACTOR;
  1654. addScorch(loc, 3*MAP_XY_FACTOR, SCORCH_1);
  1655. #endif
  1656. }
  1657. //=============================================================================
  1658. // BaseHeightMapRenderObjClass::updateScorches
  1659. //=============================================================================
  1660. /** Builds the vertex buffer data for drawing the scorches.*/
  1661. //=============================================================================
  1662. void BaseHeightMapRenderObjClass::updateScorches(void)
  1663. {
  1664. if (m_scorchesInBuffer > 1) {
  1665. return;
  1666. }
  1667. if (m_numScorches==0) {
  1668. return;
  1669. }
  1670. if (!m_indexScorch || !m_vertexScorch) {
  1671. return;
  1672. }
  1673. m_curNumScorchVertices = 0;
  1674. m_curNumScorchIndices = 0;
  1675. DX8IndexBufferClass::WriteLockClass lockIdxBuffer(m_indexScorch);
  1676. UnsignedShort *ib=lockIdxBuffer.Get_Index_Array();
  1677. UnsignedShort *curIb = ib;
  1678. DX8VertexBufferClass::WriteLockClass lockVtxBuffer(m_vertexScorch);
  1679. VertexFormatXYZDUV1 *vb = (VertexFormatXYZDUV1*)lockVtxBuffer.Get_Vertex_Array();
  1680. VertexFormatXYZDUV1 *curVb = vb;
  1681. Int curScorch;
  1682. Real shadeR, shadeG, shadeB;
  1683. shadeR = TheGlobalData->m_terrainAmbient[0].red;
  1684. shadeG = TheGlobalData->m_terrainAmbient[0].green;
  1685. shadeB = TheGlobalData->m_terrainAmbient[0].blue;
  1686. shadeR += TheGlobalData->m_terrainDiffuse[0].red/2;
  1687. shadeG += TheGlobalData->m_terrainDiffuse[0].green/2;
  1688. shadeB += TheGlobalData->m_terrainDiffuse[0].blue/2;
  1689. shadeR*=255.0f;
  1690. shadeG*=255.0f;
  1691. shadeB*=255.0f;
  1692. Int diffuse=REAL_TO_INT(shadeB) | (REAL_TO_INT(shadeG) << 8) | (REAL_TO_INT(shadeR) << 16) | ((int)255 << 24);
  1693. m_scorchesInBuffer = 0;
  1694. for (curScorch=m_numScorches-1; curScorch>=0; curScorch--) {
  1695. m_scorchesInBuffer++;
  1696. Real radius = m_scorches[curScorch].radius;
  1697. Vector3 loc = m_scorches[curScorch].location;
  1698. Int type = m_scorches[curScorch].scorchType;
  1699. if (type<0) {
  1700. type = 0;
  1701. }
  1702. if (type >= SCORCH_MARKS_IN_TEXTURE) {
  1703. type = 0;
  1704. }
  1705. Real amtToFloat = 0;
  1706. amtToFloat = MAP_HEIGHT_SCALE/10;
  1707. Int minX = REAL_TO_INT_FLOOR((loc.X-radius)/MAP_XY_FACTOR);
  1708. Int minY = REAL_TO_INT_FLOOR((loc.Y-radius)/MAP_XY_FACTOR);
  1709. if (minX<-m_map->getBorderSizeInline()) minX=-m_map->getBorderSizeInline();
  1710. if (minY<-m_map->getBorderSizeInline()) minY=-m_map->getBorderSizeInline();
  1711. Int maxX = REAL_TO_INT_CEIL((loc.X+radius)/MAP_XY_FACTOR);
  1712. Int maxY = REAL_TO_INT_CEIL((loc.Y+radius)/MAP_XY_FACTOR);
  1713. maxX++; maxY++;
  1714. if (maxX > m_map->getXExtent()-m_map->getBorderSizeInline()) {
  1715. maxX = m_map->getXExtent()-m_map->getBorderSizeInline();
  1716. }
  1717. if (maxY > m_map->getYExtent()-m_map->getBorderSizeInline()) {
  1718. maxY = m_map->getYExtent()-m_map->getBorderSizeInline();
  1719. }
  1720. Int startVertex = m_curNumScorchVertices;
  1721. Int i, j;
  1722. for (j=minY; j<maxY; j++) {
  1723. for (i=minX; i<maxX; i++) {
  1724. if (m_curNumScorchVertices >= MAX_SCORCH_VERTEX) return;
  1725. curVb->diffuse = diffuse;
  1726. Real theZ;
  1727. theZ = amtToFloat+((float)getClipHeight(i+m_map->getBorderSizeInline(),j+m_map->getBorderSizeInline())*MAP_HEIGHT_SCALE);
  1728. // The scorchmarks are spaced out by 1.5 in the texture.
  1729. Real uOffset = (type%SCORCH_PER_ROW) * 1.5f;
  1730. Real vOffset = (type/SCORCH_PER_ROW) * 1.5f;
  1731. Real X = i*MAP_XY_FACTOR;
  1732. Real Y = j*MAP_XY_FACTOR;
  1733. curVb->u1 = (uOffset + 0.5f + (X - loc.X)/(2*radius)) / (SCORCH_PER_ROW+1);
  1734. curVb->v1 = (vOffset + 0.5f + (Y - loc.Y)/(2*radius)) / (SCORCH_PER_ROW+1);
  1735. curVb->x = X;
  1736. curVb->y = Y;
  1737. curVb->z = theZ;
  1738. curVb++;
  1739. m_curNumScorchVertices++;
  1740. }
  1741. }
  1742. Int yOffset = maxX-minX;
  1743. for (j=0; j<maxY-minY-1; j++) {
  1744. for (i=0; i<maxX-minX-1; i++) {
  1745. if (m_curNumScorchIndices+6 > MAX_SCORCH_INDEX) return;
  1746. Int xNdx = i+minX+m_map->getBorderSizeInline();
  1747. Int yNdx = j+minY+m_map->getBorderSizeInline();
  1748. Bool flipForBlend = m_map->getFlipState(xNdx, yNdx);
  1749. #if 0
  1750. UnsignedByte alpha[4];
  1751. float UA[4], VA[4];
  1752. m_map->getAlphaUVData(xNdx, yNdx, UA, VA, alpha, &flipForBlend, false);
  1753. #endif
  1754. if (flipForBlend) {
  1755. *curIb++ = startVertex + j*yOffset + i+1;
  1756. *curIb++ = startVertex + j*yOffset + i+yOffset;
  1757. *curIb++ = startVertex + j*yOffset + i;
  1758. *curIb++ = startVertex + j*yOffset + i+1;
  1759. *curIb++ = startVertex + j*yOffset + i+1+yOffset;
  1760. *curIb++ = startVertex + j*yOffset + i+yOffset;
  1761. }
  1762. else
  1763. {
  1764. *curIb++ = startVertex + j*yOffset + i;
  1765. *curIb++ = startVertex + j*yOffset + i+1+yOffset;
  1766. *curIb++ = startVertex + j*yOffset + i+yOffset;
  1767. *curIb++ = startVertex + j*yOffset + i;
  1768. *curIb++ = startVertex + j*yOffset + i+1;
  1769. *curIb++ = startVertex + j*yOffset + i+1+yOffset;
  1770. }
  1771. m_curNumScorchIndices+=6;
  1772. }
  1773. }
  1774. }
  1775. }
  1776. #endif
  1777. //=============================================================================
  1778. // BaseHeightMapRenderObjClass::clearAllScorches
  1779. //=============================================================================
  1780. /** Removes all scorches. */
  1781. //=============================================================================
  1782. void BaseHeightMapRenderObjClass::clearAllScorches(void)
  1783. {
  1784. #ifdef DO_SCORCH
  1785. m_numScorches=0;
  1786. m_scorchesInBuffer=0;
  1787. #endif
  1788. }
  1789. //=============================================================================
  1790. // BaseHeightMapRenderObjClass::addScorch
  1791. //=============================================================================
  1792. /** Adds a scorch mark. */
  1793. //=============================================================================
  1794. void BaseHeightMapRenderObjClass::addScorch(Vector3 location, Real radius, Scorches type)
  1795. {
  1796. #ifdef DO_SCORCH
  1797. if (m_numScorches >= MAX_SCORCH_MARKS) {
  1798. Int i;
  1799. for (i=0; i<MAX_SCORCH_MARKS-1; i++) {
  1800. m_scorches[i] = m_scorches[i+1];
  1801. }
  1802. m_numScorches--;
  1803. }
  1804. Int i;
  1805. Real limit = radius/4;
  1806. for (i=0; i<m_numScorches; i++) {
  1807. if ( abs(location.X-m_scorches[i].location.X) < limit &&
  1808. abs(location.Y-m_scorches[i].location.Y) < limit &&
  1809. abs(radius - m_scorches[i].radius) < limit &&
  1810. m_scorches[i].scorchType == type) {
  1811. return; // basically a duplicate.
  1812. }
  1813. }
  1814. m_scorches[m_numScorches].location = location;
  1815. m_scorches[m_numScorches].radius = radius;
  1816. m_scorches[m_numScorches].scorchType = type;
  1817. m_numScorches++;
  1818. m_scorchesInBuffer = 0; // force buffer regenerations.
  1819. #endif
  1820. }
  1821. //=============================================================================
  1822. // BaseHeightMapRenderObjClass::getStaticDiffuse
  1823. //=============================================================================
  1824. /** Gets the static diffuse color value for a terrain vertex.*/
  1825. //=============================================================================
  1826. Int BaseHeightMapRenderObjClass::getStaticDiffuse(Int x, Int y)
  1827. {
  1828. if (x<0) x = 0;
  1829. if (y<0) y = 0;
  1830. if (x >= m_map->getXExtent())
  1831. x=m_map->getXExtent()-1;
  1832. if (y >= m_map->getYExtent())
  1833. y=m_map->getYExtent()-1;
  1834. if (m_map == NULL) {
  1835. return(0);
  1836. }
  1837. Vector3 l2r,n2f,normalAtTexel;
  1838. Int vn0,un0,vp1,up1;
  1839. const Int cellOffset = 1;
  1840. vn0 = y-cellOffset;
  1841. vp1 = y+cellOffset;
  1842. if (vp1 >= m_map->getYExtent())
  1843. vp1=m_map->getYExtent()-1;
  1844. if (vn0<0) vn0 = 0;
  1845. un0 = x-cellOffset;
  1846. up1 = x+cellOffset;
  1847. if (un0 < 0)
  1848. un0=0;
  1849. if (up1 >= m_map->getXExtent())
  1850. up1=m_map->getXExtent()-1;
  1851. Vector3 lightRay[MAX_GLOBAL_LIGHTS];
  1852. const Coord3D *lightPos;
  1853. for (Int lightIndex=0; lightIndex < TheGlobalData->m_numGlobalLights; lightIndex++)
  1854. {
  1855. lightPos=&TheGlobalData->m_terrainLightPos[lightIndex];
  1856. lightRay[lightIndex].Set(-lightPos->x,-lightPos->y, -lightPos->z);
  1857. }
  1858. //top-left sample
  1859. l2r.Set(2*MAP_XY_FACTOR,0,MAP_HEIGHT_SCALE*(m_map->getHeight(up1, y) - m_map->getHeight(un0, y)));
  1860. n2f.Set(0,2*MAP_XY_FACTOR,MAP_HEIGHT_SCALE*(m_map->getHeight(x, vp1) - m_map->getHeight(x, vn0)));
  1861. Vector3::Normalized_Cross_Product(l2r,n2f, &normalAtTexel);
  1862. VERTEX_FORMAT vertex;
  1863. vertex.x=ADJUST_FROM_INDEX_TO_REAL(x);
  1864. vertex.y=ADJUST_FROM_INDEX_TO_REAL(y);
  1865. vertex.z= ((float)m_map->getHeight(x,y))*MAP_HEIGHT_SCALE;
  1866. vertex.u1=0;
  1867. vertex.v1=0;
  1868. vertex.u2=1;
  1869. vertex.v2=1;
  1870. RTS3DScene *pMyScene = (RTS3DScene *)Scene;
  1871. if (pMyScene) {
  1872. RefRenderObjListIterator *it = pMyScene->createLightsIterator();
  1873. doTheLight(&vertex, lightRay, &normalAtTexel, it, 1.0f);
  1874. if (it) {
  1875. pMyScene->destroyLightsIterator(it);
  1876. it = NULL;
  1877. }
  1878. } else {
  1879. doTheLight(&vertex, lightRay, &normalAtTexel, NULL, 1.0f);
  1880. }
  1881. return vertex.diffuse;
  1882. }
  1883. //=============================================================================
  1884. // BaseHeightMapRenderObjClass::On_Frame_Update
  1885. //=============================================================================
  1886. /** Updates the diffuse color values in the vertices as affected by the dynamic lights.*/
  1887. //=============================================================================
  1888. void BaseHeightMapRenderObjClass::On_Frame_Update(void)
  1889. {
  1890. }
  1891. //=============================================================================
  1892. // BaseHeightMapRenderObjClass::unitMoved
  1893. //=============================================================================
  1894. /** Tell that a unit moved.*/
  1895. //=============================================================================
  1896. void BaseHeightMapRenderObjClass::unitMoved( Object *unit )
  1897. {
  1898. if (m_treeBuffer) {
  1899. m_treeBuffer->unitMoved(unit);
  1900. }
  1901. }
  1902. //=============================================================================
  1903. // BaseHeightMapRenderObjClass::removeTreesAndPropsForConstruction
  1904. //=============================================================================
  1905. /** Tell that a unit moved.*/
  1906. //=============================================================================
  1907. void BaseHeightMapRenderObjClass::removeTreesAndPropsForConstruction(const Coord3D* pos, const GeometryInfo& geom, Real angle )
  1908. {
  1909. if (m_treeBuffer) {
  1910. m_treeBuffer->removeTreesForConstruction(pos, geom, angle);
  1911. }
  1912. if (m_propBuffer) {
  1913. m_propBuffer->removePropsForConstruction(pos, geom, angle);
  1914. }
  1915. }
  1916. //=============================================================================
  1917. // BaseHeightMapRenderObjClass::addTree
  1918. //=============================================================================
  1919. /** Adds a tree to the tree buffer.*/
  1920. //=============================================================================
  1921. void BaseHeightMapRenderObjClass::addTree(DrawableID id, Coord3D location, Real scale, Real angle,
  1922. Real randomScaleAmount, const W3DTreeDrawModuleData *data)
  1923. {
  1924. if (m_treeBuffer) {
  1925. m_treeBuffer->addTree(id, location, scale, angle, randomScaleAmount, data);
  1926. }
  1927. };
  1928. //=============================================================================
  1929. // BaseHeightMapRenderObjClass::removeTree
  1930. //=============================================================================
  1931. /** Adds a tree to the tree buffer.*/
  1932. //=============================================================================
  1933. void BaseHeightMapRenderObjClass::removeTree(DrawableID id)
  1934. {
  1935. if (m_treeBuffer) {
  1936. m_treeBuffer->removeTree(id);
  1937. }
  1938. };
  1939. //=============================================================================
  1940. // BaseHeightMapRenderObjClass::removeAllTrees
  1941. //=============================================================================
  1942. /** Adds a tree to the tree buffer.*/
  1943. //=============================================================================
  1944. void BaseHeightMapRenderObjClass::removeAllTrees()
  1945. {
  1946. if (m_treeBuffer) {
  1947. m_treeBuffer->clearAllTrees();
  1948. }
  1949. };
  1950. //=============================================================================
  1951. // BaseHeightMapRenderObjClass::updateTreePosition
  1952. //=============================================================================
  1953. /** Updates a tree's position and angle in the tree buffer.*/
  1954. //=============================================================================
  1955. Bool BaseHeightMapRenderObjClass::updateTreePosition(DrawableID id, Coord3D location, Real angle)
  1956. {
  1957. if (m_treeBuffer) {
  1958. return m_treeBuffer->updateTreePosition(id, location, angle);
  1959. }
  1960. return false;
  1961. };
  1962. //=============================================================================
  1963. // BaseHeightMapRenderObjClass::addProp
  1964. //=============================================================================
  1965. /** Adds a prop to the prop buffer.*/
  1966. //=============================================================================
  1967. void BaseHeightMapRenderObjClass::addProp(Int id, Coord3D location, Real angle, Real scale,
  1968. const AsciiString &modelName)
  1969. {
  1970. if (m_propBuffer) {
  1971. m_propBuffer->addProp(id, location, angle, scale, modelName);
  1972. }
  1973. };
  1974. //=============================================================================
  1975. // BaseHeightMapRenderObjClass::removeProp
  1976. //=============================================================================
  1977. /** Adds a prop to the prop buffer.*/
  1978. //=============================================================================
  1979. void BaseHeightMapRenderObjClass::removeProp(Int id)
  1980. {
  1981. if (m_propBuffer) {
  1982. m_propBuffer->removeProp(id);
  1983. }
  1984. };
  1985. //=============================================================================
  1986. // BaseHeightMapRenderObjClass::removeAllProps
  1987. //=============================================================================
  1988. /** Adds a prop to the prop buffer.*/
  1989. //=============================================================================
  1990. void BaseHeightMapRenderObjClass::removeAllProps()
  1991. {
  1992. if (m_propBuffer) {
  1993. m_propBuffer->clearAllProps();
  1994. }
  1995. };
  1996. //=============================================================================
  1997. // BaseHeightMapRenderObjClass::notifyShroudChanged
  1998. //=============================================================================
  1999. /** Notifies that the local shroud changed.*/
  2000. //=============================================================================
  2001. void BaseHeightMapRenderObjClass::notifyShroudChanged(void)
  2002. {
  2003. if (m_propBuffer) {
  2004. m_propBuffer->notifyShroudChanged();
  2005. }
  2006. };
  2007. //=============================================================================
  2008. // BaseHeightMapRenderObjClass::addTerrainBib
  2009. //=============================================================================
  2010. /** Adds a terrainBib to the bib buffer.*/
  2011. //=============================================================================
  2012. void BaseHeightMapRenderObjClass::addTerrainBib(Vector3 corners[4],
  2013. ObjectID id, Bool highlight)
  2014. {
  2015. m_bibBuffer->addBib(corners, id, highlight);
  2016. };
  2017. //=============================================================================
  2018. // BaseHeightMapRenderObjClass::addTerrainBib
  2019. //=============================================================================
  2020. /** Adds a terrainBib to the bib buffer.*/
  2021. //=============================================================================
  2022. void BaseHeightMapRenderObjClass::addTerrainBibDrawable(Vector3 corners[4],
  2023. DrawableID id, Bool highlight)
  2024. {
  2025. m_bibBuffer->addBibDrawable(corners, id, highlight);
  2026. };
  2027. //=============================================================================
  2028. // BaseHeightMapRenderObjClass::removeAllTerrainBibs
  2029. //=============================================================================
  2030. /** Removes all terrainBib highlighting from the bib buffer.*/
  2031. //=============================================================================
  2032. void BaseHeightMapRenderObjClass::removeTerrainBibHighlighting()
  2033. {
  2034. m_bibBuffer->removeHighlighting( );
  2035. };
  2036. //=============================================================================
  2037. // BaseHeightMapRenderObjClass::removeAllTerrainBibs
  2038. //=============================================================================
  2039. /** Removes all terrainBibs from the bib buffer.*/
  2040. //=============================================================================
  2041. void BaseHeightMapRenderObjClass::removeAllTerrainBibs()
  2042. {
  2043. m_bibBuffer->clearAllBibs( );
  2044. };
  2045. //=============================================================================
  2046. // BaseHeightMapRenderObjClass::removeTerrainBib
  2047. //=============================================================================
  2048. /** Removes a terrainBib from the bib buffer.*/
  2049. //=============================================================================
  2050. void BaseHeightMapRenderObjClass::removeTerrainBib(ObjectID id)
  2051. {
  2052. m_bibBuffer->removeBib( id );
  2053. };
  2054. //=============================================================================
  2055. // BaseHeightMapRenderObjClass::removeTerrainBib
  2056. //=============================================================================
  2057. /** Removes a terrainBib from the bib buffer.*/
  2058. //=============================================================================
  2059. void BaseHeightMapRenderObjClass::removeTerrainBibDrawable(DrawableID id)
  2060. {
  2061. m_bibBuffer->removeBibDrawable( id );
  2062. };
  2063. //=============================================================================
  2064. // BaseHeightMapRenderObjClass::staticLightingChanged
  2065. //=============================================================================
  2066. /** Notification that all lighting needs to be recalculated. */
  2067. //=============================================================================
  2068. void BaseHeightMapRenderObjClass::staticLightingChanged( void )
  2069. {
  2070. // Cause the terrain to get updated with new lighting.
  2071. m_needFullUpdate = true;
  2072. // Cause the scorches to get updated with new lighting.
  2073. m_scorchesInBuffer = 0; // If we just allocated the buffers, we got no scorches in the buffer.
  2074. m_curNumScorchVertices=0;
  2075. m_curNumScorchIndices=0;
  2076. m_roadBuffer->updateLighting();
  2077. }
  2078. //=============================================================================
  2079. // BaseHeightMapRenderObjClass::setTimeOfDay
  2080. //=============================================================================
  2081. /** When the time of day changes, the lighting changes and we need to update. */
  2082. //=============================================================================
  2083. void BaseHeightMapRenderObjClass::setTimeOfDay( TimeOfDay tod )
  2084. {
  2085. staticLightingChanged();
  2086. }
  2087. //=============================================================================
  2088. // BaseHeightMapRenderObjClass::Notify_Added
  2089. //=============================================================================
  2090. /** W3D render object method, we use it to add ourselves to tthe update
  2091. list, so On_Frame_Update gets called. */
  2092. //=============================================================================
  2093. void BaseHeightMapRenderObjClass::Notify_Added(SceneClass * scene)
  2094. {
  2095. RenderObjClass::Notify_Added(scene);
  2096. scene->Register(this,SceneClass::ON_FRAME_UPDATE);
  2097. }
  2098. //=============================================================================
  2099. // BaseHeightMapRenderObjClass::updateCenter
  2100. //=============================================================================
  2101. /** Updates the positioning of the drawn portion of the height map in the
  2102. heightmap. As the view slides around, this determines what is the actually
  2103. rendered portion of the terrain. Only a 96x96 section is rendered at any time,
  2104. even though maps can be up to 1024x1024. This function determines which subset
  2105. is rendered. */
  2106. //=============================================================================
  2107. void BaseHeightMapRenderObjClass::updateCenter(CameraClass *camera , RefRenderObjListIterator *pLightsIterator)
  2108. {
  2109. if (m_map==NULL) {
  2110. return;
  2111. }
  2112. if (m_updating) {
  2113. return;
  2114. }
  2115. if (m_treeBuffer) {
  2116. m_treeBuffer->doFullUpdate(); // Tell the trees to update for view change.
  2117. }
  2118. if (m_propBuffer) {
  2119. m_propBuffer->doFullUpdate(); // Tell the trees to update for view change.
  2120. }
  2121. m_updating = true;
  2122. #ifdef DO_ROADS
  2123. if (m_roadBuffer) {
  2124. m_roadBuffer->updateCenter();
  2125. }
  2126. #endif
  2127. if (m_needFullUpdate) {
  2128. m_bridgeBuffer->doFullUpdate();
  2129. m_bridgeBuffer->updateCenter(camera, pLightsIterator);
  2130. m_updating = false;
  2131. return;
  2132. }
  2133. m_bridgeBuffer->updateCenter(camera, pLightsIterator);
  2134. m_updating = false;
  2135. }
  2136. //=============================================================================
  2137. // BaseHeightMapRenderObjClass::Render
  2138. //=============================================================================
  2139. /** Renders (draws) the terrain. */
  2140. //=============================================================================
  2141. //DECLARE_PERF_TIMER(Terrain_Render)
  2142. void BaseHeightMapRenderObjClass::Render(RenderInfoClass & rinfo)
  2143. {
  2144. }
  2145. /**Render parts of terrain that are along the coast line and have vertices directly under the
  2146. water plane. Applying a custom render to these polygons allows for a smoother land->water
  2147. transition*/
  2148. void BaseHeightMapRenderObjClass::renderShoreLines(CameraClass *pCamera)
  2149. {
  2150. if (!TheGlobalData->m_isWorldBuilder) //use faster version optimized for game and not world builder?
  2151. { renderShoreLinesSorted(pCamera);
  2152. return;
  2153. }
  2154. m_numVisibleShoreLineTiles=0;
  2155. if (!TheGlobalData->m_showSoftWaterEdge || TheWaterTransparency->m_transparentWaterDepth==0 || m_numShoreLineTiles == 0)
  2156. return;
  2157. //Check if video card is capable of using this effect
  2158. if (DX8Wrapper::getBackBufferFormat() != WW3D_FORMAT_A8R8G8B8)
  2159. return; //can't apply effect on cards without destination alpha
  2160. Int vertexCount = 0;
  2161. Int indexCount = 0;
  2162. Int drawEdgeY=m_map->getDrawOrgY()+m_map->getDrawHeight()-1;
  2163. Int drawEdgeX=m_map->getDrawOrgX()+m_map->getDrawWidth()-1;
  2164. if (drawEdgeX > (m_map->getXExtent()-1))
  2165. drawEdgeX = m_map->getXExtent()-1;
  2166. if (drawEdgeY > (m_map->getYExtent()-1))
  2167. drawEdgeY = m_map->getYExtent()-1;
  2168. Int drawStartX=m_map->getDrawOrgX();
  2169. Int drawStartY=m_map->getDrawOrgY();
  2170. Int j=0;
  2171. ShaderClass unlitShader=ShaderClass::_PresetOpaque2DShader;
  2172. unlitShader.Set_Depth_Compare(ShaderClass::PASS_LEQUAL);
  2173. DX8Wrapper::Set_Shader(unlitShader);
  2174. VertexMaterialClass *vmat=VertexMaterialClass::Get_Preset(VertexMaterialClass::PRELIT_DIFFUSE);
  2175. DX8Wrapper::Set_Material(vmat);
  2176. REF_PTR_RELEASE(vmat);
  2177. DX8Wrapper::Set_Texture(0,m_destAlphaTexture);
  2178. DX8Wrapper::Set_Transform(D3DTS_WORLD,Matrix3D(1));
  2179. //Enabled writes to destination alpha only
  2180. DX8Wrapper::Set_DX8_Render_State(D3DRS_COLORWRITEENABLE,D3DCOLORWRITEENABLE_ALPHA);
  2181. DX8Wrapper::Set_DX8_Texture_Stage_State(0, D3DTSS_TEXCOORDINDEX, 0);
  2182. while (j != m_numShoreLineTiles)
  2183. {
  2184. DynamicVBAccessClass vb_access(BUFFER_TYPE_DYNAMIC_DX8,dynamic_fvf_type,DEFAULT_MAX_BATCH_SHORELINE_TILES*4);
  2185. DynamicIBAccessClass ib_access(BUFFER_TYPE_DYNAMIC_DX8,DEFAULT_MAX_BATCH_SHORELINE_TILES*6);
  2186. { //Need to put this in another code block so vb/ib gets automatically locked/unlocked by destructors
  2187. DynamicVBAccessClass::WriteLockClass lock(&vb_access);
  2188. VertexFormatXYZNDUV2 *vb= lock.Get_Formatted_Vertex_Array();
  2189. DynamicIBAccessClass::WriteLockClass lockib(&ib_access);
  2190. UnsignedShort *ib=lockib.Get_Index_Array();
  2191. if (!ib || !vb)
  2192. { DX8Wrapper::Set_DX8_Render_State(D3DRS_COLORWRITEENABLE,D3DCOLORWRITEENABLE_BLUE|D3DCOLORWRITEENABLE_GREEN|D3DCOLORWRITEENABLE_RED);
  2193. return;
  2194. }
  2195. try {
  2196. //Loop over visible terrain and extract all the tiles that need shoreline blend
  2197. for (; j<m_numShoreLineTiles; j++)
  2198. {
  2199. if (vertexCount >= (DEFAULT_MAX_BATCH_SHORELINE_TILES*4))
  2200. break; //no room in vertex buffer
  2201. shoreLineTileInfo *shoreInfo=&m_shoreLineTilePositions[j];
  2202. Int x = shoreInfo->m_xy & 0xffff;
  2203. Int y = shoreInfo->m_xy >> 16;
  2204. if (x >= drawStartX && x < drawEdgeX && y >= drawStartY && y < drawEdgeY)
  2205. { //this tile is inside visible region
  2206. vb->x = shoreInfo->verts[0];
  2207. vb->y = shoreInfo->verts[1];
  2208. vb->z = shoreInfo->verts[2];
  2209. vb->nx=0; //filling these to keep AGP write buffer happy.
  2210. vb->ny=0;
  2211. vb->nz=0;
  2212. vb->diffuse=0;
  2213. vb->u1=shoreInfo->t0;
  2214. vb->v1=0;
  2215. vb->u2=0;
  2216. vb->v2=0;
  2217. vb++;
  2218. vb->x = shoreInfo->verts[3];
  2219. vb->y = shoreInfo->verts[4];
  2220. vb->z = shoreInfo->verts[5];
  2221. vb->nx=0; //filling these to keep AGP write buffer happy.
  2222. vb->ny=0;
  2223. vb->nz=0;
  2224. vb->diffuse=0;
  2225. vb->u1=shoreInfo->t1;
  2226. vb->v1=0;
  2227. vb->u2=0;
  2228. vb->v2=0;
  2229. vb++;
  2230. vb->x = shoreInfo->verts[6];
  2231. vb->y = shoreInfo->verts[7];
  2232. vb->z = shoreInfo->verts[8];
  2233. vb->nx=0; //filling these to keep AGP write buffer happy.
  2234. vb->ny=0;
  2235. vb->nz=0;
  2236. vb->diffuse=0;
  2237. vb->u1=shoreInfo->t2;
  2238. vb->v1=0;
  2239. vb->u2=0;
  2240. vb->v2=0;
  2241. vb++;
  2242. vb->x = shoreInfo->verts[9];
  2243. vb->y = shoreInfo->verts[10];
  2244. vb->z = shoreInfo->verts[11];
  2245. vb->nx=0; //filling these to keep AGP write buffer happy.
  2246. vb->ny=0;
  2247. vb->nz=0;
  2248. vb->diffuse=0;
  2249. vb->u1=shoreInfo->t3;
  2250. vb->v1=0;
  2251. vb->u2=0;
  2252. vb->v2=0;
  2253. vb++;
  2254. if (m_map->getQuickFlipState(x,y))
  2255. {
  2256. ib[0]=1+vertexCount;
  2257. ib[1]=3+vertexCount;
  2258. ib[2]=0+vertexCount;
  2259. ib[3]=1+vertexCount;
  2260. ib[4]=2+vertexCount;
  2261. ib[5]=3+vertexCount;
  2262. }
  2263. else
  2264. {
  2265. ib[0]=0+vertexCount;
  2266. ib[1]=2+vertexCount;
  2267. ib[2]=3+vertexCount;
  2268. ib[3]=0+vertexCount;
  2269. ib[4]=1+vertexCount;
  2270. ib[5]=2+vertexCount;
  2271. }
  2272. ib += 6;
  2273. vertexCount +=4;
  2274. indexCount +=6;
  2275. }
  2276. }
  2277. IndexBufferExceptionFunc();
  2278. } catch(...) {
  2279. IndexBufferExceptionFunc();
  2280. }
  2281. }//lock and fill ib/vb
  2282. if (indexCount > 0 && vertexCount > 0)
  2283. {
  2284. DX8Wrapper::Set_Index_Buffer(ib_access,0);
  2285. DX8Wrapper::Set_Vertex_Buffer(vb_access);
  2286. DX8Wrapper::Draw_Triangles( 0,indexCount/3, 0, vertexCount); //draw a quad, 2 triangles, 4 verts
  2287. m_numVisibleShoreLineTiles += indexCount/6;
  2288. }
  2289. vertexCount=0;
  2290. indexCount=0;
  2291. }//for all shore tiles
  2292. //Disable writes to destination alpha
  2293. DX8Wrapper::Set_DX8_Render_State(D3DRS_COLORWRITEENABLE,D3DCOLORWRITEENABLE_BLUE|D3DCOLORWRITEENABLE_GREEN|D3DCOLORWRITEENABLE_RED);
  2294. ShaderClass::Invalidate();
  2295. }
  2296. /**Render parts of terrain that are along the coast line and have vertices directly under the
  2297. water plane. Applying a custom render to these polygons allows for a smoother land->water
  2298. transition. This version is exactly like the one above but optimized for the case where tiles
  2299. are assumed to be sorted. Not used by World Builder. */
  2300. void BaseHeightMapRenderObjClass::renderShoreLinesSorted(CameraClass *pCamera)
  2301. {
  2302. m_numVisibleShoreLineTiles=0;
  2303. if (!TheGlobalData->m_showSoftWaterEdge || TheWaterTransparency->m_transparentWaterDepth==0 || m_numShoreLineTiles == 0)
  2304. return;
  2305. //Check if video card is capable of using this effect
  2306. if (DX8Wrapper::getBackBufferFormat() != WW3D_FORMAT_A8R8G8B8)
  2307. return; //can't apply effect on cards without destination alpha
  2308. Int vertexCount = 0;
  2309. Int indexCount = 0;
  2310. Int drawEdgeY=m_map->getDrawOrgY()+m_map->getDrawHeight()-1;
  2311. Int drawEdgeX=m_map->getDrawOrgX()+m_map->getDrawWidth()-1;
  2312. if (drawEdgeX > (m_map->getXExtent()-1))
  2313. drawEdgeX = m_map->getXExtent()-1;
  2314. if (drawEdgeY > (m_map->getYExtent()-1))
  2315. drawEdgeY = m_map->getYExtent()-1;
  2316. Int drawStartX=m_map->getDrawOrgX();
  2317. Int drawStartY=m_map->getDrawOrgY();
  2318. if (m_shoreLineSortInfosXMajor) //map is wider than taller.
  2319. {
  2320. //Clamp the major map axis to available shoreline tiles.
  2321. if (m_shoreLineTileSortMinCoordinate > drawStartX)
  2322. drawStartX=m_shoreLineTileSortMinCoordinate;
  2323. if ((m_shoreLineTileSortMaxCoordinate+1) < drawEdgeX)
  2324. drawEdgeX=(m_shoreLineTileSortMaxCoordinate+1);
  2325. if ((drawEdgeX-drawStartX) <= 0)
  2326. return; //nothing to draw
  2327. }
  2328. else
  2329. {
  2330. //Clamp the major map axis to available shoreline tiles.
  2331. if (m_shoreLineTileSortMinCoordinate > drawStartY)
  2332. drawStartY=m_shoreLineTileSortMinCoordinate;
  2333. if ((m_shoreLineTileSortMaxCoordinate+1) < drawEdgeY)
  2334. drawEdgeY=(m_shoreLineTileSortMaxCoordinate+1);
  2335. if ((drawEdgeY-drawStartY) <= 0)
  2336. return; //nothing to draw
  2337. }
  2338. ShaderClass unlitShader=ShaderClass::_PresetOpaque2DShader;
  2339. unlitShader.Set_Depth_Compare(ShaderClass::PASS_LEQUAL);
  2340. DX8Wrapper::Set_Shader(unlitShader);
  2341. VertexMaterialClass *vmat=VertexMaterialClass::Get_Preset(VertexMaterialClass::PRELIT_DIFFUSE);
  2342. DX8Wrapper::Set_Material(vmat);
  2343. REF_PTR_RELEASE(vmat);
  2344. DX8Wrapper::Set_Texture(0,m_destAlphaTexture);
  2345. DX8Wrapper::Set_Transform(D3DTS_WORLD,Matrix3D(1));
  2346. //Enabled writes to destination alpha only
  2347. DX8Wrapper::Set_DX8_Render_State(D3DRS_COLORWRITEENABLE,D3DCOLORWRITEENABLE_ALPHA);
  2348. DX8Wrapper::Set_DX8_Texture_Stage_State(0, D3DTSS_TEXCOORDINDEX, 0);
  2349. Bool isDone=FALSE;
  2350. Int lastRenderedTile=0;
  2351. while (!isDone)
  2352. {
  2353. DynamicVBAccessClass vb_access(BUFFER_TYPE_DYNAMIC_DX8,dynamic_fvf_type,DEFAULT_MAX_BATCH_SHORELINE_TILES*4);
  2354. DynamicIBAccessClass ib_access(BUFFER_TYPE_DYNAMIC_DX8,DEFAULT_MAX_BATCH_SHORELINE_TILES*6);
  2355. { //Need to put this in another code block so vb/ib gets automatically locked/unlocked by destructors
  2356. DynamicVBAccessClass::WriteLockClass lock(&vb_access);
  2357. VertexFormatXYZNDUV2 *vb= lock.Get_Formatted_Vertex_Array();
  2358. DynamicIBAccessClass::WriteLockClass lockib(&ib_access);
  2359. UnsignedShort *ib=lockib.Get_Index_Array();
  2360. if (!ib || !vb)
  2361. { DX8Wrapper::Set_DX8_Render_State(D3DRS_COLORWRITEENABLE,D3DCOLORWRITEENABLE_BLUE|D3DCOLORWRITEENABLE_GREEN|D3DCOLORWRITEENABLE_RED);
  2362. return;
  2363. }
  2364. try {
  2365. //Loop over visible terrain and extract all the tiles that need shoreline blend
  2366. if (m_shoreLineSortInfosXMajor) //map is wider than taller.
  2367. {
  2368. for (Int x=drawStartX; x<drawEdgeX; x++)
  2369. { //figure out how many tiles are available in this column
  2370. shoreLineTileSortInfo *sortInfo=&m_shoreLineSortInfos[x];
  2371. if (!sortInfo->numTiles)
  2372. continue; //no tiles in this column.
  2373. //Clamp visible area to actual tiles in this column
  2374. Int startY=drawStartY;
  2375. if (sortInfo->minTileCoordinate > startY)
  2376. startY = sortInfo->minTileCoordinate;
  2377. Int edgeY=drawEdgeY;
  2378. if ((sortInfo->maxTileCoordinate+1) < edgeY)
  2379. edgeY = sortInfo->maxTileCoordinate+1;
  2380. if ((edgeY-startY) <= 0)
  2381. continue; //no tiles visible in this column.
  2382. //Pointer to first tile in this column
  2383. shoreLineTileInfo *shoreInfo=m_shoreLineTilePositions+sortInfo->tileStartIndex+lastRenderedTile;
  2384. //Loop over tiles in this column and render visible ones
  2385. for (Int k=lastRenderedTile; k<sortInfo->numTiles; k++)
  2386. {
  2387. Int tileY = shoreInfo->m_xy >> 16;
  2388. if (tileY < startY)
  2389. { shoreInfo++; //advance to next tile.
  2390. continue; //this tile is not visible
  2391. }
  2392. if (tileY >= edgeY)
  2393. break; //since tiles are x-sorted, there will not be any visible ones after this one.
  2394. if (vertexCount >= (DEFAULT_MAX_BATCH_SHORELINE_TILES*4))
  2395. { lastRenderedTile=k;
  2396. goto flushVertexBuffer0;
  2397. }
  2398. vb->x = shoreInfo->verts[0];
  2399. vb->y = shoreInfo->verts[1];
  2400. vb->z = shoreInfo->verts[2];
  2401. vb->nx=0; //filling these to keep AGP write buffer happy.
  2402. vb->ny=0;
  2403. vb->nz=0;
  2404. vb->diffuse=0;
  2405. vb->u1=shoreInfo->t0;
  2406. vb->v1=0;
  2407. vb->u2=0;
  2408. vb->v2=0;
  2409. vb++;
  2410. vb->x = shoreInfo->verts[3];
  2411. vb->y = shoreInfo->verts[4];
  2412. vb->z = shoreInfo->verts[5];
  2413. vb->nx=0; //filling these to keep AGP write buffer happy.
  2414. vb->ny=0;
  2415. vb->nz=0;
  2416. vb->diffuse=0;
  2417. vb->u1=shoreInfo->t1;
  2418. vb->v1=0;
  2419. vb->u2=0;
  2420. vb->v2=0;
  2421. vb++;
  2422. vb->x = shoreInfo->verts[6];
  2423. vb->y = shoreInfo->verts[7];
  2424. vb->z = shoreInfo->verts[8];
  2425. vb->nx=0; //filling these to keep AGP write buffer happy.
  2426. vb->ny=0;
  2427. vb->nz=0;
  2428. vb->diffuse=0;
  2429. vb->u1=shoreInfo->t2;
  2430. vb->v1=0;
  2431. vb->u2=0;
  2432. vb->v2=0;
  2433. vb++;
  2434. vb->x = shoreInfo->verts[9];
  2435. vb->y = shoreInfo->verts[10];
  2436. vb->z = shoreInfo->verts[11];
  2437. vb->nx=0; //filling these to keep AGP write buffer happy.
  2438. vb->ny=0;
  2439. vb->nz=0;
  2440. vb->diffuse=0;
  2441. vb->u1=shoreInfo->t3;
  2442. vb->v1=0;
  2443. vb->u2=0;
  2444. vb->v2=0;
  2445. vb++;
  2446. if (m_map->getQuickFlipState(x,tileY))
  2447. {
  2448. ib[0]=1+vertexCount;
  2449. ib[1]=3+vertexCount;
  2450. ib[2]=0+vertexCount;
  2451. ib[3]=1+vertexCount;
  2452. ib[4]=2+vertexCount;
  2453. ib[5]=3+vertexCount;
  2454. }
  2455. else
  2456. {
  2457. ib[0]=0+vertexCount;
  2458. ib[1]=2+vertexCount;
  2459. ib[2]=3+vertexCount;
  2460. ib[3]=0+vertexCount;
  2461. ib[4]=1+vertexCount;
  2462. ib[5]=2+vertexCount;
  2463. }
  2464. ib += 6;
  2465. vertexCount +=4;
  2466. indexCount +=6;
  2467. shoreInfo++; //advance to next tile.
  2468. }//looping over tiles in column
  2469. lastRenderedTile=0;
  2470. }//looping over all visible columns.
  2471. flushVertexBuffer0:
  2472. drawStartX = x; //record how far we've moved so far
  2473. isDone = x >= drawEdgeX;
  2474. }
  2475. else
  2476. {
  2477. for (Int y=drawStartY; y<drawEdgeY; y++)
  2478. { //figure out how many tiles are available in this row
  2479. shoreLineTileSortInfo *sortInfo=&m_shoreLineSortInfos[y];
  2480. if (!sortInfo->numTiles)
  2481. continue; //no tiles in this row.
  2482. //Clamp visible area to actual tiles in this row
  2483. Int startX=drawStartX;
  2484. if (sortInfo->minTileCoordinate > startX)
  2485. startX = sortInfo->minTileCoordinate;
  2486. Int edgeX=drawEdgeX;
  2487. if ((sortInfo->maxTileCoordinate+1) < edgeX)
  2488. edgeX = sortInfo->maxTileCoordinate+1;
  2489. if ((edgeX-startX) <= 0)
  2490. continue; //no tiles visible in this row.
  2491. //Pointer to first tile in this row
  2492. shoreLineTileInfo *shoreInfo=m_shoreLineTilePositions+sortInfo->tileStartIndex+lastRenderedTile;
  2493. //Loop over tiles in this row and render visible ones
  2494. for (Int k=lastRenderedTile; k<sortInfo->numTiles; k++)
  2495. {
  2496. Int tileX = shoreInfo->m_xy & 0xffff;
  2497. if (tileX < startX)
  2498. { shoreInfo++; //advance to next tile.
  2499. continue; //this tile is not visible
  2500. }
  2501. if (tileX >= edgeX)
  2502. break; //since tiles are x-sorted, there will not be any visible ones after this one.
  2503. if (vertexCount >= (DEFAULT_MAX_BATCH_SHORELINE_TILES*4))
  2504. { lastRenderedTile=k;
  2505. goto flushVertexBuffer1;
  2506. }
  2507. vb->x = shoreInfo->verts[0];
  2508. vb->y = shoreInfo->verts[1];
  2509. vb->z = shoreInfo->verts[2];
  2510. vb->nx=0; //filling these to keep AGP write buffer happy.
  2511. vb->ny=0;
  2512. vb->nz=0;
  2513. vb->diffuse=0;
  2514. vb->u1=shoreInfo->t0;
  2515. vb->v1=0;
  2516. vb->u2=0;
  2517. vb->v2=0;
  2518. vb++;
  2519. vb->x = shoreInfo->verts[3];
  2520. vb->y = shoreInfo->verts[4];
  2521. vb->z = shoreInfo->verts[5];
  2522. vb->nx=0; //filling these to keep AGP write buffer happy.
  2523. vb->ny=0;
  2524. vb->nz=0;
  2525. vb->diffuse=0;
  2526. vb->u1=shoreInfo->t1;
  2527. vb->v1=0;
  2528. vb->u2=0;
  2529. vb->v2=0;
  2530. vb++;
  2531. vb->x = shoreInfo->verts[6];
  2532. vb->y = shoreInfo->verts[7];
  2533. vb->z = shoreInfo->verts[8];
  2534. vb->nx=0; //filling these to keep AGP write buffer happy.
  2535. vb->ny=0;
  2536. vb->nz=0;
  2537. vb->diffuse=0;
  2538. vb->u1=shoreInfo->t2;
  2539. vb->v1=0;
  2540. vb->u2=0;
  2541. vb->v2=0;
  2542. vb++;
  2543. vb->x = shoreInfo->verts[9];
  2544. vb->y = shoreInfo->verts[10];
  2545. vb->z = shoreInfo->verts[11];
  2546. vb->nx=0; //filling these to keep AGP write buffer happy.
  2547. vb->ny=0;
  2548. vb->nz=0;
  2549. vb->diffuse=0;
  2550. vb->u1=shoreInfo->t3;
  2551. vb->v1=0;
  2552. vb->u2=0;
  2553. vb->v2=0;
  2554. vb++;
  2555. if (m_map->getQuickFlipState(tileX,y))
  2556. {
  2557. ib[0]=1+vertexCount;
  2558. ib[1]=3+vertexCount;
  2559. ib[2]=0+vertexCount;
  2560. ib[3]=1+vertexCount;
  2561. ib[4]=2+vertexCount;
  2562. ib[5]=3+vertexCount;
  2563. }
  2564. else
  2565. {
  2566. ib[0]=0+vertexCount;
  2567. ib[1]=2+vertexCount;
  2568. ib[2]=3+vertexCount;
  2569. ib[3]=0+vertexCount;
  2570. ib[4]=1+vertexCount;
  2571. ib[5]=2+vertexCount;
  2572. }
  2573. ib += 6;
  2574. vertexCount +=4;
  2575. indexCount +=6;
  2576. shoreInfo++; //advance to next tile.
  2577. }//looping over tiles in row
  2578. lastRenderedTile=0;
  2579. }//looping over all visible rows.
  2580. flushVertexBuffer1:
  2581. drawStartY = y; //record how far we've moved so far
  2582. isDone = y >= drawEdgeY;
  2583. IndexBufferExceptionFunc();
  2584. }
  2585. } catch(...) {
  2586. IndexBufferExceptionFunc();
  2587. }
  2588. }//lock and fill ib/vb
  2589. if (indexCount > 0 && vertexCount > 0)
  2590. {
  2591. DX8Wrapper::Set_Index_Buffer(ib_access,0);
  2592. DX8Wrapper::Set_Vertex_Buffer(vb_access);
  2593. DX8Wrapper::Draw_Triangles( 0,indexCount/3, 0, vertexCount); //draw a quad, 2 triangles, 4 verts
  2594. m_numVisibleShoreLineTiles += indexCount/6;
  2595. }
  2596. vertexCount=0;
  2597. indexCount=0;
  2598. }//for all shore tiles
  2599. //Disable writes to destination alpha
  2600. DX8Wrapper::Set_DX8_Render_State(D3DRS_COLORWRITEENABLE,D3DCOLORWRITEENABLE_BLUE|D3DCOLORWRITEENABLE_GREEN|D3DCOLORWRITEENABLE_RED);
  2601. ShaderClass::Invalidate();
  2602. }
  2603. //=============================================================================
  2604. // BaseHeightMapRenderObjClass::renderTrees
  2605. //=============================================================================
  2606. /** Renders (draws) the trees. Since the trees are transparent, this has to be
  2607. called after flush. */
  2608. //=============================================================================
  2609. void BaseHeightMapRenderObjClass::renderTrees(CameraClass * camera)
  2610. {
  2611. #ifdef EXTENDED_STATS
  2612. if (DX8Wrapper::stats.m_disableObjects) {
  2613. return;
  2614. }
  2615. #endif
  2616. if (m_map==NULL) return;
  2617. if (Scene==NULL) return;
  2618. if (m_treeBuffer) {
  2619. Matrix3D tm(Transform);
  2620. DX8Wrapper::Set_Transform(D3DTS_WORLD,tm);
  2621. DX8Wrapper::Set_Material(m_vertexMaterialClass);
  2622. RTS3DScene *pMyScene = (RTS3DScene *)Scene;
  2623. RefRenderObjListIterator pDynamicLightsIterator(pMyScene->getDynamicLights());
  2624. m_treeBuffer->drawTrees(camera, &pDynamicLightsIterator);
  2625. }
  2626. }
  2627. // ------------------------------------------------------------------------------------------------
  2628. /** CRC */
  2629. // ------------------------------------------------------------------------------------------------
  2630. void BaseHeightMapRenderObjClass::crc( Xfer *xfer )
  2631. {
  2632. // empty. jba [8/11/2003]
  2633. } // end CRC
  2634. // ------------------------------------------------------------------------------------------------
  2635. /** Xfer
  2636. * Version Info:
  2637. * 1: Initial version */
  2638. // ------------------------------------------------------------------------------------------------
  2639. void BaseHeightMapRenderObjClass::xfer( Xfer *xfer )
  2640. {
  2641. // version
  2642. XferVersion currentVersion = 1;
  2643. XferVersion version = currentVersion;
  2644. xfer->xferVersion( &version, currentVersion );
  2645. xfer->xferSnapshot( m_treeBuffer );
  2646. xfer->xferSnapshot( m_propBuffer );
  2647. } // end xfer
  2648. // ------------------------------------------------------------------------------------------------
  2649. /** Load post process */
  2650. // ------------------------------------------------------------------------------------------------
  2651. void BaseHeightMapRenderObjClass::loadPostProcess( void )
  2652. {
  2653. // empty. jba [8/11/2003]
  2654. } // end loadPostProcess