W3DShroud.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801
  1. /*
  2. ** Command & Conquer Generals(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. ////////////////////////////////////////////////////////////////////////////////
  19. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. // FILE: W3DShroud.cpp /////////////////////////////////////////////////////////////////////////////
  24. // Created: Mark Wilczynski, Jan 2002
  25. // Desc: Code to support rendering of shrouded units/terrain.
  26. ///////////////////////////////////////////////////////////////////////////////////////////////////
  27. #include "Lib/BaseType.h"
  28. #include "camera.h"
  29. #include "simplevec.h"
  30. #include "dx8wrapper.h"
  31. #include "common/MapObject.h"
  32. #include "common/PerfTimer.h"
  33. #include "W3DDevice/GameClient/HeightMap.h"
  34. #include "W3DDevice/GameClient/W3DPoly.h"
  35. #include "W3DDevice/GameClient/W3DShaderManager.h"
  36. #include "assetmgr.h"
  37. #include "W3DDevice/GameClient/W3DShroud.h"
  38. #include "WW3D2/textureloader.h"
  39. #include "common/GlobalData.h"
  40. #include "GameLogic/PartitionManager.h"
  41. #ifdef _INTERNAL
  42. // for occasional debugging...
  43. //#pragma optimize("", off)
  44. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  45. #endif
  46. //-----------------------------------------------------------------------------
  47. // In Global Data now
  48. //#define SHROUD_COLOR 0x00ffffff //temporary test of gray shroud instead of pure black.
  49. //#define MIN_SHROUD_LEVEL 0 //for gray fog
  50. //Int SHROUD_COLOR=0x00808080; //temporary test of gray shroud instead of pure black.
  51. //Int MIN_SHROUD_LEVEL=50; //for gray fog
  52. //#define SHROUD_COLOR 0x00eeeebff //temporary test of gray shroud instead of pure black.
  53. //#define MIN_SHROUD_LEVEL 254 //for gray fog
  54. //#define SHROUD_COLOR 0x00bbbbbb //temporary test of gray shroud instead of pure black.
  55. //#define SHROUD_COLOR 0x00004080 //temporary test of blue shroud instead of pure black.
  56. //#define MIN_SHROUD_LEVEL 100 //for black fog
  57. //#define MAX_MAP_SHROUDSIZE 1024 //maximum number of shroud cells across entire map.
  58. //#define MAX_VISIBLE_SHROUDSIZE (MAX_MAP_SHROUDSIZE+1) //maximum number of shroud vertices visible at any given time
  59. #define DEFAULT_SHROUD_CELL_SIZE MAP_XY_FACTOR //assume shroud at same resolution as terrain cells.
  60. #define DEFAULT_TERRAIN_SIZE 1024 //assumed size of largest terrain possible (in vertices)
  61. #define DEFAULT_VISIBLE_TERRAIN 96 //assumed size of visible terrain cells.
  62. //-----------------------------------------------------------------------------
  63. W3DShroud::W3DShroud(void)
  64. {
  65. m_finalFogData=NULL;
  66. m_currentFogData=NULL;
  67. m_pSrcTexture=NULL;
  68. m_pDstTexture=NULL;
  69. m_srcTextureData=NULL;
  70. m_srcTexturePitch=NULL;
  71. m_dstTextureWidth=m_numMaxVisibleCellsX=0;
  72. m_dstTextureHeight=m_numMaxVisibleCellsY=0;
  73. m_boderShroudLevel = (W3DShroudLevel)TheGlobalData->m_shroudAlpha; //assume border is black
  74. m_clearDstTexture = TRUE; //force clearing of destination texture;
  75. m_cellWidth=DEFAULT_SHROUD_CELL_SIZE;
  76. m_cellHeight=DEFAULT_SHROUD_CELL_SIZE;
  77. m_numCellsX=0;
  78. m_numCellsY=0;
  79. m_shroudFilter=TextureClass::FILTER_TYPE_DEFAULT;
  80. }
  81. //-----------------------------------------------------------------------------
  82. W3DShroud::~W3DShroud(void)
  83. {
  84. ReleaseResources();
  85. if (m_pSrcTexture)
  86. m_pSrcTexture->Release();
  87. m_pSrcTexture=NULL;
  88. if (m_finalFogData)
  89. delete [] m_finalFogData;
  90. if (m_currentFogData)
  91. delete [] m_currentFogData;
  92. m_drawFogOfWar=FALSE;
  93. }
  94. //-----------------------------------------------------------------------------
  95. /**Called to initialize a new shroud for a new map. Should be done after the map is loaded
  96. into the terrain object. worldCellSize is the world-space dimensions of each shroud cell.
  97. The system will generate enough cells to cover the full map.
  98. */
  99. void W3DShroud::init(WorldHeightMap *pMap, Real worldCellSizeX, Real worldCellSizeY)
  100. {
  101. DEBUG_ASSERTCRASH( m_pSrcTexture == NULL, ("ReAcquire of existing shroud textures"));
  102. DEBUG_ASSERTCRASH( pMap != NULL, ("Shroud init with NULL WorldHeightMap"));
  103. Int dstTextureWidth=0;
  104. Int dstTextureHeight=0;
  105. m_cellWidth=worldCellSizeX;
  106. m_cellHeight=worldCellSizeY;
  107. //Precompute a bounding box for entire shroud layer
  108. if (pMap)
  109. {
  110. m_numCellsX = REAL_TO_INT_CEIL((Real)(pMap->getXExtent() - 1 - pMap->getBorderSize()*2)*MAP_XY_FACTOR/m_cellWidth);
  111. m_numCellsY = REAL_TO_INT_CEIL((Real)(pMap->getYExtent() - 1 - pMap->getBorderSize()*2)*MAP_XY_FACTOR/m_cellHeight);
  112. //Maximum visible cells will depend on maximum drawable terrain size plus 1 for partial cells (since
  113. //shroud cells are larger than terrain cells).
  114. dstTextureWidth=m_numMaxVisibleCellsX=REAL_TO_INT_FLOOR((Real)(pMap->getDrawWidth()-1)*MAP_XY_FACTOR/m_cellWidth)+1;
  115. dstTextureHeight=m_numMaxVisibleCellsY=REAL_TO_INT_FLOOR((Real)(pMap->getDrawHeight()-1)*MAP_XY_FACTOR/m_cellHeight)+1;
  116. dstTextureWidth += 2; //enlarge by 2 pixels so we can have a border color all the way around.
  117. dstTextureHeight += 2; //enlarge by 2 pixels so we can have border color all the way around.
  118. TextureLoader::Validate_Texture_Size((unsigned int &)dstTextureWidth,(unsigned int &)dstTextureHeight);
  119. }
  120. UnsignedInt srcWidth,srcHeight;
  121. srcWidth=m_numCellsX;
  122. //vertical size is larger by 1 pixel so that we have some unused pixels to use in clearing the video texture.
  123. //To clear the video texture, I will copy pixels from this unused area. There is no other way to clear a video
  124. //memory texture to a known value because you can't lock it - only copy into it.
  125. srcHeight=m_numCellsY;
  126. srcHeight += 1;
  127. #ifdef DO_FOG_INTERPOLATION
  128. m_finalFogData = new W3DShroudLevel[srcWidth*srcHeight];
  129. m_currentFogData = new W3DShroudLevel[srcWidth*srcHeight];
  130. //Clear the fog to black
  131. memset(m_currentFogData,0,srcWidth*srcHeight);
  132. memset(m_finalFogData,0,srcWidth*srcHeight);
  133. #endif
  134. #if defined(_DEBUG) || defined(_INTERNAL)
  135. if (TheGlobalData && TheGlobalData->m_fogOfWarOn)
  136. m_pSrcTexture = DX8Wrapper::_Create_DX8_Surface(srcWidth,srcHeight, WW3D_FORMAT_A4R4G4B4);
  137. else
  138. #endif
  139. m_pSrcTexture = DX8Wrapper::_Create_DX8_Surface(srcWidth,srcHeight, WW3D_FORMAT_R5G6B5);
  140. DEBUG_ASSERTCRASH( m_pSrcTexture != NULL, ("Failed to Allocate Shroud Src Surface"));
  141. D3DLOCKED_RECT rect;
  142. //Get a pointer to source surface pixels.
  143. HRESULT res = m_pSrcTexture->LockRect(&rect,NULL,D3DLOCK_NO_DIRTY_UPDATE);
  144. m_pSrcTexture->UnlockRect();
  145. DEBUG_ASSERTCRASH( res == D3D_OK, ("Failed to lock shroud src surface"));
  146. res = 0;// just to avoid compiler warnings
  147. m_srcTextureData=rect.pBits;
  148. m_srcTexturePitch=rect.Pitch;
  149. //clear entire texture to black
  150. memset(m_srcTextureData,0,m_srcTexturePitch*srcHeight);
  151. #if defined(_DEBUG) || defined(_INTERNAL)
  152. if (TheGlobalData && TheGlobalData->m_fogOfWarOn)
  153. fillShroudData(TheGlobalData->m_shroudAlpha); //initialize shroud to a known value
  154. #endif
  155. if (dstTextureWidth != m_dstTextureWidth || dstTextureHeight != m_dstTextureHeight ) ///@todo: Check if size has changed - probably never
  156. ReleaseResources(); //need a new sized shroud
  157. if (!m_pDstTexture )
  158. { m_dstTextureWidth = dstTextureWidth;
  159. m_dstTextureHeight = dstTextureHeight;
  160. ReAcquireResources(); //allocate video memory surface
  161. }
  162. //Force a refresh of shroud data since we just created a new source texture.
  163. if (ThePartitionManager)
  164. ThePartitionManager->refreshShroudForLocalPlayer();
  165. }
  166. //-----------------------------------------------------------------------------
  167. ///Called on map reset.
  168. void W3DShroud::reset()
  169. {
  170. //Free old shroud data since it may no longer fit new map.
  171. if (m_pSrcTexture)
  172. m_pSrcTexture->Release();
  173. m_pSrcTexture=NULL;
  174. if (m_finalFogData)
  175. delete [] m_finalFogData;
  176. m_finalFogData=NULL;
  177. if (m_currentFogData)
  178. delete [] m_currentFogData;
  179. m_currentFogData=NULL;
  180. m_clearDstTexture = TRUE; //always refill the destination texture after a reset
  181. }
  182. //-----------------------------------------------------------------------------
  183. ///Release any resources that can't survive a D3D device reset.
  184. void W3DShroud::ReleaseResources(void)
  185. {
  186. REF_PTR_RELEASE (m_pDstTexture);
  187. }
  188. //-----------------------------------------------------------------------------
  189. ///Restore resources that are lost on D3D device reset.
  190. Bool W3DShroud::ReAcquireResources(void)
  191. {
  192. if (!m_dstTextureWidth)
  193. return TRUE; //nothing to reaquire since shroud was never initialized with valid data
  194. DEBUG_ASSERTCRASH( m_pDstTexture == NULL, ("ReAcquire of existing shroud texture"));
  195. // Create destination texture (stored in video memory).
  196. // Since we control the video memory copy, we can do partial updates more efficiently. Or do shift blits.
  197. #if defined(_DEBUG) || defined(_INTERNAL)
  198. if (TheGlobalData && TheGlobalData->m_fogOfWarOn)
  199. m_pDstTexture = MSGNEW("TextureClass") TextureClass(m_dstTextureWidth,m_dstTextureHeight,WW3D_FORMAT_A4R4G4B4,TextureClass::MIP_LEVELS_1, TextureClass::POOL_DEFAULT);
  200. else
  201. #endif
  202. m_pDstTexture = MSGNEW("TextureClass") TextureClass(m_dstTextureWidth,m_dstTextureHeight,WW3D_FORMAT_R5G6B5,TextureClass::MIP_LEVELS_1, TextureClass::POOL_DEFAULT);
  203. DEBUG_ASSERTCRASH( m_pDstTexture != NULL, ("Failed ReAcquire of shroud texture"));
  204. if (!m_pDstTexture)
  205. { //could not create a valid texture
  206. m_dstTextureWidth = 0;
  207. m_dstTextureHeight = 0;
  208. return FALSE;
  209. }
  210. m_pDstTexture->Set_U_Addr_Mode(TextureClass::TEXTURE_ADDRESS_CLAMP);
  211. m_pDstTexture->Set_V_Addr_Mode(TextureClass::TEXTURE_ADDRESS_CLAMP);
  212. m_pDstTexture->Set_Mip_Mapping(TextureClass::FILTER_TYPE_NONE);
  213. m_clearDstTexture = TRUE; //force clearing of destination texture first time it's used.
  214. return TRUE;
  215. }
  216. //-----------------------------------------------------------------------------
  217. W3DShroudLevel W3DShroud::getShroudLevel(Int x, Int y)
  218. {
  219. DEBUG_ASSERTCRASH( m_pSrcTexture != NULL, ("Reading empty shroud"));
  220. if (x < m_numCellsX && y < m_numCellsY)
  221. {
  222. UnsignedShort pixel=*(UnsignedShort *)((Byte *)m_srcTextureData + x*2 + y*m_srcTexturePitch);
  223. #if defined(_DEBUG) || defined(_INTERNAL)
  224. if (TheGlobalData && TheGlobalData->m_fogOfWarOn)
  225. //in this mode, alpha channel holds intensity
  226. return (W3DShroudLevel)((1.0f-((Real)(pixel >> 12)/15.0f))*255.0f);
  227. else
  228. #endif
  229. //in this mode, green has the best precision at 6 bits.
  230. return (W3DShroudLevel)((Real)((pixel >> 5)&0x3f)/63.0f*255.0f);
  231. }
  232. return 0;
  233. }
  234. //-----------------------------------------------------------------------------
  235. void W3DShroud::setShroudLevel(Int x, Int y, W3DShroudLevel level, Bool textureOnly)
  236. {
  237. DEBUG_ASSERTCRASH( m_pSrcTexture != NULL, ("Writing empty shroud. Usually means that map failed to load."));
  238. if (!m_pSrcTexture)
  239. return;
  240. if (x < m_numCellsX && y < m_numCellsY)
  241. {
  242. if (level < TheGlobalData->m_shroudAlpha)
  243. level = TheGlobalData->m_shroudAlpha;
  244. #if defined(_DEBUG) || defined(_INTERNAL)
  245. if (TheGlobalData && TheGlobalData->m_fogOfWarOn)
  246. {
  247. ///@todo: optimize this case if we end up using fog shroud.
  248. Int redVal = TheGlobalData->m_shroudColor.red;
  249. Int greenVal = TheGlobalData->m_shroudColor.green;
  250. Int blueVal = TheGlobalData->m_shroudColor.blue;
  251. // Int redVal = (SHROUD_COLOR >> 16) & 0xff;
  252. // Int greenVal = (SHROUD_COLOR >> 8) & 0xff;
  253. // Int blueVal = SHROUD_COLOR & 0xff;
  254. Int alphaVal = 255 - level;
  255. UnsignedShort pixel=((blueVal>>4)&0xf) | (((greenVal>>4)&0xf)<<4) | (((redVal>>4)&0xf)<<8) | (((alphaVal>>4)&0xf)<<12);
  256. *(UnsignedShort *)((Byte *)m_srcTextureData + x*2 + y*m_srcTexturePitch)=pixel;
  257. }
  258. else
  259. #endif
  260. {
  261. #ifdef DO_FOG_INTERPOLATION
  262. if (!textureOnly)
  263. m_finalFogData[x+y*m_numCellsX]=level;
  264. #endif
  265. UnsignedInt bluepixel = (UnsignedInt)((Real)level*((Real)(TheGlobalData->m_shroudColor.getAsInt()&0xff)/255.0f));
  266. UnsignedInt greenpixel = (UnsignedInt)((Real)level*((Real)((TheGlobalData->m_shroudColor.getAsInt()&0xff00)>>8)/255.0f));
  267. UnsignedInt redpixel = (UnsignedInt)((Real)level*((Real)((TheGlobalData->m_shroudColor.getAsInt()&0xff0000)>>16)/255.0f));
  268. // UnsignedInt bluepixel = (UnsignedInt)((Real)level*((Real)(SHROUD_COLOR&0xff)/255.0f));
  269. // UnsignedInt greenpixel = (UnsignedInt)((Real)level*((Real)((SHROUD_COLOR&0xff00)>>8)/255.0f));
  270. // UnsignedInt redpixel = (UnsignedInt)((Real)level*((Real)((SHROUD_COLOR&0xff0000)>>16)/255.0f));
  271. if (level == 255)
  272. { //unshrouded pixels should be fully lit
  273. redpixel = 255;
  274. greenpixel = 255;
  275. bluepixel = 255;
  276. }
  277. UnsignedShort *texel = (UnsignedShort *)((Byte *)m_srcTextureData + x*2 + y*m_srcTexturePitch);
  278. // For those interested, MLorenzen has this bock commented out until he gets back on Mon, Sept. 30 2002
  279. // If this code is still here by mid october, nuke it!
  280. // UnsignedInt texelRed = ((*texel >> 8 ) & 0xf8);
  281. // UnsignedInt texelGreen =((*texel >> 3 ) & 0xfc);
  282. // UnsignedInt texelBlue = ((*texel << 3 ) & 0xf8);
  283. // if (texelRed < texelGreen && texelGreen > texelBlue)
  284. // {
  285. // bluepixel += redpixel;
  286. // bluepixel -= redpixel;
  287. // }
  288. *texel = ( ((bluepixel&0xf8) >> 3) | ((greenpixel&0xfc)<<3) | ((redpixel&0xf8)<<8));
  289. }
  290. return;
  291. }
  292. }
  293. //-----------------------------------------------------------------------------
  294. ///Quickly sets the shroud level of entire map to a single value
  295. void W3DShroud::fillShroudData(W3DShroudLevel level)
  296. {
  297. Int x,y;
  298. UnsignedShort pixel;
  299. if (level < TheGlobalData->m_shroudAlpha)
  300. level = TheGlobalData->m_shroudAlpha;
  301. #if defined(_DEBUG) || defined(_INTERNAL)
  302. //convert value to pixel format
  303. if (TheGlobalData && TheGlobalData->m_fogOfWarOn)
  304. {
  305. Int redVal = TheGlobalData->m_shroudColor.red;
  306. Int greenVal = TheGlobalData->m_shroudColor.green;
  307. Int blueVal = TheGlobalData->m_shroudColor.blue;
  308. // Int redVal = (SHROUD_COLOR >> 16) & 0xff;
  309. // Int greenVal = (SHROUD_COLOR >> 8) & 0xff;
  310. // Int blueVal = SHROUD_COLOR & 0xff;
  311. Int alphaVal = 255 - level;
  312. pixel=((blueVal>>4)&0xf) | (((greenVal>>4)&0xf)<<4) | (((redVal>>4)&0xf)<<8) | (((alphaVal>>4)&0xf)<<12);
  313. }
  314. else
  315. #endif
  316. {
  317. UnsignedInt bluepixel = (UnsignedInt)((Real)level*((Real)(TheGlobalData->m_shroudColor.getAsInt()&0xff)/255.0f));
  318. UnsignedInt greenpixel = (UnsignedInt)((Real)level*((Real)((TheGlobalData->m_shroudColor.getAsInt()&0xff00)>>8)/255.0f));
  319. UnsignedInt redpixel = (UnsignedInt)((Real)level*((Real)((TheGlobalData->m_shroudColor.getAsInt()&0xff0000)>>16)/255.0f));
  320. // UnsignedInt bluepixel = (UnsignedInt)((Real)level*((Real)(SHROUD_COLOR&0xff)/255.0f));
  321. // UnsignedInt greenpixel = (UnsignedInt)((Real)level*((Real)((SHROUD_COLOR&0xff00)>>8)/255.0f));
  322. // UnsignedInt redpixel = (UnsignedInt)((Real)level*((Real)((SHROUD_COLOR&0xff0000)>>16)/255.0f));
  323. if (level == 255)
  324. { //unshrouded pixels should be fully lit
  325. redpixel = 255;
  326. greenpixel = 255;
  327. bluepixel = 255;
  328. }
  329. pixel=( ((bluepixel&0xf8) >> 3) | ((greenpixel&0xfc)<<3) | ((redpixel&0xf8)<<8));
  330. }
  331. UnsignedShort *ptr=(UnsignedShort *)m_srcTextureData;
  332. Int pitch = m_srcTexturePitch >> 1; //2 bytes per pointer increment
  333. for (y=0; y<m_numCellsY; y++)
  334. {
  335. for (x=0; x<m_numCellsX; x++)
  336. ptr[x]=pixel;
  337. ptr += pitch;
  338. }
  339. #ifdef DO_FOG_INTERPOLATION
  340. //Set the final shroud state. May differe from current state because of time interpolation.
  341. W3DShroudLevel *cptr=m_finalFogData;
  342. pitch = m_numCellsX;
  343. for (y=0; y<m_numCellsY; y++)
  344. {
  345. for (x=0; x<m_numCellsX; x++)
  346. cptr[x]=level;
  347. ptr += pitch;
  348. }
  349. #endif
  350. }
  351. void W3DShroud::fillBorderShroudData(W3DShroudLevel level, SurfaceClass* pDestSurface)
  352. {
  353. Int x,y;
  354. UnsignedShort pixel;
  355. if (level < TheGlobalData->m_shroudAlpha)
  356. level = TheGlobalData->m_shroudAlpha;
  357. #if defined(_DEBUG) || defined(_INTERNAL)
  358. //convert value to pixel format
  359. if (TheGlobalData && TheGlobalData->m_fogOfWarOn)
  360. {
  361. Int redVal = TheGlobalData->m_shroudColor.red;
  362. Int greenVal = TheGlobalData->m_shroudColor.green;
  363. Int blueVal = TheGlobalData->m_shroudColor.blue;
  364. Int alphaVal = 255 - level;
  365. pixel=((blueVal>>4)&0xf) | (((greenVal>>4)&0xf)<<4) | (((redVal>>4)&0xf)<<8) | (((alphaVal>>4)&0xf)<<12);
  366. }
  367. else
  368. #endif
  369. {
  370. UnsignedInt bluepixel = (UnsignedInt)((Real)level*((Real)(TheGlobalData->m_shroudColor.getAsInt()&0xff)/255.0f));
  371. UnsignedInt greenpixel = (UnsignedInt)((Real)level*((Real)((TheGlobalData->m_shroudColor.getAsInt()&0xff00)>>8)/255.0f));
  372. UnsignedInt redpixel = (UnsignedInt)((Real)level*((Real)((TheGlobalData->m_shroudColor.getAsInt()&0xff0000)>>16)/255.0f));
  373. if (level == 255)
  374. { //unshrouded pixels should be fully lit
  375. redpixel = 255;
  376. greenpixel = 255;
  377. bluepixel = 255;
  378. }
  379. pixel=( ((bluepixel&0xf8) >> 3) | ((greenpixel&0xfc)<<3) | ((redpixel&0xf8)<<8));
  380. }
  381. //Skip to unused texels within the shroud data
  382. UnsignedShort *ptr=(UnsignedShort *)m_srcTextureData + m_numCellsY*(m_srcTexturePitch >> 1);
  383. //Fill unused texels with border color
  384. for (x=0; x<m_numCellsX; x++)
  385. ptr[x]=pixel;
  386. //Fill destination texture with border color
  387. RECT srcRect;
  388. //create a rectangle enclosing bottom row of unused pixels long enough
  389. //to cover destination width.
  390. srcRect.left=0;
  391. srcRect.top=m_numCellsY;
  392. srcRect.right= m_numCellsX;
  393. srcRect.bottom= m_numCellsY+1;
  394. POINT dstPoint={0,0};
  395. Int numFullCopies = m_dstTextureWidth/srcRect.right;
  396. Int numExtraPixels = m_dstTextureWidth%srcRect.right;
  397. for (y=0; y<m_dstTextureHeight; y++)
  398. {
  399. dstPoint.y=y;
  400. dstPoint.x=0;
  401. for (x=0; x<numFullCopies; x++)
  402. {
  403. dstPoint.x = x * srcRect.right; //advance to next set of pixel in row.
  404. DX8Wrapper::_Copy_DX8_Rects(
  405. m_pSrcTexture,
  406. &srcRect,
  407. 1,
  408. pDestSurface->Peek_D3D_Surface(),
  409. &dstPoint);
  410. }
  411. if (numExtraPixels)
  412. { Int oldVal=srcRect.right;
  413. dstPoint.x = numFullCopies * oldVal;
  414. srcRect.right = numExtraPixels;
  415. DX8Wrapper::_Copy_DX8_Rects(
  416. m_pSrcTexture,
  417. &srcRect,
  418. 1,
  419. pDestSurface->Peek_D3D_Surface(),
  420. &dstPoint);
  421. srcRect.right = oldVal;
  422. }
  423. }
  424. }
  425. /**Set the shroud color within the border area of the map*/
  426. void W3DShroud::setBorderShroudLevel(W3DShroudLevel level)
  427. {
  428. m_boderShroudLevel = level;
  429. m_clearDstTexture = TRUE;
  430. }
  431. //-----------------------------------------------------------------------------
  432. ///@todo: remove this
  433. TextureClass *DummyTexture=NULL;
  434. //#define LOAD_DUMMY_SHROUD
  435. //-----------------------------------------------------------------------------
  436. //DECLARE_PERF_TIMER(shroudCopy)
  437. //-----------------------------------------------------------------------------
  438. /** Updates video memory surface with currently visible shroud data */
  439. void W3DShroud::render(CameraClass *cam)
  440. {
  441. if (!m_pSrcTexture)
  442. return; //nothing to update from. Must be in reset state.
  443. if (DX8Wrapper::_Get_D3D_Device8() && (DX8Wrapper::_Get_D3D_Device8()->TestCooperativeLevel()) != D3D_OK)
  444. return; //device not ready to render anything
  445. #if defined(_DEBUG) || defined(_INTERNAL)
  446. if (TheGlobalData && TheGlobalData->m_fogOfWarOn != m_drawFogOfWar)
  447. {
  448. //fog state has changed since last time shroud system was initialized
  449. reset();
  450. ReleaseResources();
  451. init(TheTerrainRenderObject->getMap(),m_cellWidth,m_cellHeight);
  452. ThePartitionManager->refreshShroudForLocalPlayer();
  453. m_drawFogOfWar=TheGlobalData->m_fogOfWarOn;
  454. m_clearDstTexture=TRUE;
  455. }
  456. #endif
  457. DEBUG_ASSERTCRASH( m_pSrcTexture != NULL, ("Updating unallocated shroud texture"));
  458. #ifdef LOAD_DUMMY_SHROUD
  459. static doInit=1;
  460. if (doInit)
  461. {
  462. //some temporary code here to debug the shroud.
  463. ///@todo: remove this debug buffer fill.
  464. fillShroudData(1.0f); //force to all shrouded
  465. Short *src=(Short *)m_srcTextureData;
  466. //fill with some dummy values
  467. src[0]=(char)0xff;
  468. src[1]=(char)0xff;
  469. src[m_numCellsX]=(char)0xff;
  470. src[m_numCellsX+1]=(char)0xff;
  471. src[m_numCellsX*2]=(char)0xff;
  472. src[m_numCellsX*9+8]=(char)0xff;
  473. src[m_numCellsX*8+8]=(char)0xff;
  474. src[m_numCellsX*7+8]=(char)0xff;
  475. src[m_numCellsX*8+9]=(char)0xff;
  476. src[m_numCellsX*8+7]=(char)0xff;
  477. DummyTexture=WW3DAssetManager::Get_Instance()->Get_Texture("shroud1024.tga");
  478. Short *dataDest=(Short *)((char *)m_srcTextureData); //offset to correct row of full sysmem shroud
  479. Int pitchDest = m_srcTexturePitch >> 1; //2 bytes per pixel so divide byte count by 2.
  480. //Copy the dummy shroud into our game shroud.
  481. SurfaceClass *pSurface=DummyTexture->Get_Surface_Level(0);
  482. Int pitch;
  483. Int *dataSrc=(Int *)((char *)pSurface->Lock(&pitch)); //offset to correct row of full sysmem shroud
  484. pitch >>= 2; //4 bytes per pixel so divide byte count by 4.
  485. SurfaceClass::SurfaceDescription desc;
  486. pSurface->Get_Description(desc);
  487. //Check if source data is larger than our current shroud
  488. desc.Width = __min(desc.Width,m_numCellsX);
  489. desc.Height = __min(desc.Height,m_numCellsY);
  490. for (Int y=0; y<desc.Height; y++)
  491. {
  492. for (Int x=0; x<desc.Width; x++)
  493. {
  494. #if defined(_DEBUG) || defined(_INTERNAL)
  495. if (TheGlobalData && TheGlobalData->m_fogOfWarOn)
  496. {
  497. dataDest[x]=((TheGlobalData->m_shroudColor.getAsInt()>>4)&0xf) | (((TheGlobalData->m_shroudColor.getAsInt()>>12)&0xf)<<4) | (((TheGlobalData->m_shroudColor.getAsInt()>>20)&0xf)<<8) | ((((255-(dataSrc[x] & 0xff))>>4)&0xf)<<12);
  498. // dataDest[x]=((SHROUD_COLOR>>4)&0xf) | (((SHROUD_COLOR>>12)&0xf)<<4) | (((SHROUD_COLOR>>20)&0xf)<<8) | ((((255-(dataSrc[x] & 0xff))>>4)&0xf)<<12);
  499. }
  500. else
  501. #endif
  502. {
  503. dataDest[x]=((dataSrc[x]>>3)&0x1f) | (((dataSrc[x]>>10)&0x3f)<<5) | (((dataSrc[x]>>19)&0x1f)<<11);
  504. }
  505. }
  506. dataDest += pitchDest; //skip to next row.
  507. dataSrc += pitch; //skip to next row of shroud
  508. }
  509. pSurface->Unlock();
  510. REF_PTR_RELEASE (pSurface);
  511. REF_PTR_RELEASE (DummyTexture);
  512. doInit=0;
  513. }
  514. #endif //LOAD_DUMMY_SHROUD
  515. WorldHeightMap *hm=TheTerrainRenderObject->getMap();
  516. Int visStartX=REAL_TO_INT_FLOOR((Real)(hm->getDrawOrgX()-hm->getBorderSize())*MAP_XY_FACTOR/m_cellWidth); //start of rendered heightmap rectangle
  517. if (visStartX < 0)
  518. visStartX = 0; //no shroud is applied in border area so it always starts at > 0
  519. Int visStartY=REAL_TO_INT_FLOOR((Real)(hm->getDrawOrgY()-hm->getBorderSize())*MAP_XY_FACTOR/m_cellHeight);
  520. if (visStartY < 0)
  521. visStartY = 0; //no shroud is applied in border area so it always starts at > 0
  522. Int visEndX=visStartX+REAL_TO_INT_FLOOR((Real)(hm->getDrawWidth()-1)*MAP_XY_FACTOR/m_cellWidth)+1; //size of rendered heightmap rectangle
  523. Int visEndY=visStartY+REAL_TO_INT_FLOOR((Real)(hm->getDrawHeight()-1)*MAP_XY_FACTOR/m_cellHeight)+1;
  524. if (visEndX > m_numCellsX)
  525. {
  526. visStartX -= visEndX - m_numCellsX; //shift visible rectangle to fall within terrain bounds
  527. if (visStartX < 0)
  528. visStartX = 0;
  529. visEndX = m_numCellsX;
  530. }
  531. if (visEndY > m_numCellsY)
  532. {
  533. visStartY -= visEndY - m_numCellsY; //shift visible rectangle to fall within terrain bounds
  534. if (visStartY < 0)
  535. visStartY = 0;
  536. visEndY = m_numCellsY;
  537. }
  538. m_drawOriginX = (Real)visStartX * m_cellWidth;
  539. m_drawOriginY = (Real)visStartY * m_cellHeight;
  540. //If system memory usage becomes too large, we should store shroud as Bytes. Update
  541. //a system memory texture with data. Then copy this to video memory. For now we're
  542. //holding shroud data directly in a texture to avoid the extra copy.
  543. /* pSurface=m_pSrcTexture->Get_Surface_Level(0);
  544. data=(Short *)((char *)pSurface->Lock(&pitch) + visStartY*pitch); //offset to correct row of full sysmem shroud
  545. pitch >>= 1; //we have 2 bytes per pixel, so divide pitch by 2
  546. Byte *sd=shroudData+visStartY*MAX_MAP_SHROUDSIZE; //pointer to first shroud row
  547. for (Int y=visStartY; y<(visStartY+visSizeY); y++)
  548. {
  549. for (Int x=visStartX; x<(visStartX+visSizeX); x++)
  550. {
  551. data[x]=sd[x]|(sd[x]<<8);
  552. }
  553. data += pitch; //skip to next row.
  554. sd += MAX_MAP_SHROUDSIZE; //skip to next row of shroud
  555. }
  556. pSurface->Unlock();
  557. */
  558. if (m_pDstTexture->Get_Mag_Filter() != m_shroudFilter)
  559. {
  560. m_pDstTexture->Set_Mag_Filter(m_shroudFilter);
  561. m_pDstTexture->Set_Min_Filter(m_shroudFilter);
  562. }
  563. //Update video memory texture with sysmem copy
  564. SurfaceClass* pDestSurface;
  565. {
  566. pDestSurface=m_pDstTexture->Get_Surface_Level(0);
  567. }
  568. RECT srcRect;
  569. POINT dstPoint={1,1}; //first row/column is reserved for border.
  570. srcRect.left=visStartX;
  571. srcRect.top=visStartY;
  572. srcRect.right=visEndX;
  573. srcRect.bottom=visEndY;
  574. #ifdef DO_FOG_INTERPOLATION
  575. //interpolate current shroud state to the final one
  576. interpolateFogLevels(&srcRect);
  577. #endif
  578. if (m_clearDstTexture)
  579. { //we need to clear unused parts of the destination texture to a known
  580. //color in order to keep map border in the state we want.
  581. m_clearDstTexture=FALSE;
  582. fillBorderShroudData(m_boderShroudLevel, pDestSurface);
  583. }
  584. {
  585. //USE_PERF_TIMER(shroudCopy)
  586. DX8Wrapper::_Copy_DX8_Rects(
  587. m_pSrcTexture,
  588. &srcRect,
  589. 1,
  590. pDestSurface->Peek_D3D_Surface(),
  591. &dstPoint);
  592. }
  593. REF_PTR_RELEASE (pDestSurface);
  594. }
  595. #define FOG_INTERPOLATION_RATE (255.0f/1000.0f) //take one second to go from black to fully lit.
  596. //-----------------------------------------------------------------------------
  597. void W3DShroud::interpolateFogLevels(RECT *rect)
  598. {
  599. static UnsignedInt prevTime = timeGetTime();
  600. UnsignedInt timeDiff=timeGetTime()-prevTime;
  601. if (!timeDiff)
  602. return; //no time has elapsed
  603. prevTime +=timeDiff; //update for next frame
  604. Int maxFogChange=FOG_INTERPOLATION_RATE * (Real)timeDiff; //maximum amount of fog change allowed in frame.
  605. if (maxFogChange > 255)
  606. maxFogChange = 255;
  607. W3DShroudLevel levelDelta = maxFogChange;
  608. W3DShroudLevel *startLevel=m_currentFogData;
  609. W3DShroudLevel *finalLevel=m_finalFogData;
  610. for (Int j=0; j<m_numCellsY; j++)
  611. {
  612. for (Int i=0; i<m_numCellsX; i++,startLevel++,finalLevel++)
  613. if (*startLevel != *finalLevel)
  614. { //fog needs fading.
  615. if (*startLevel == *finalLevel)
  616. continue;
  617. else
  618. if (*finalLevel < *startLevel)
  619. {
  620. if ((*startLevel - *finalLevel) < levelDelta)
  621. *startLevel = *finalLevel; //change too large so clamp to final value.
  622. else
  623. *startLevel -= levelDelta;
  624. }
  625. else
  626. if (*finalLevel > *startLevel)
  627. {
  628. if ((*finalLevel - *startLevel) < levelDelta)
  629. *startLevel = *finalLevel; //change too large so clamp to final value.
  630. else
  631. *startLevel += levelDelta;
  632. }
  633. setShroudLevel(i,j,*startLevel,TRUE);
  634. }
  635. }
  636. }
  637. //-----------------------------------------------------------------------------
  638. void W3DShroud::setShroudFilter(Bool enable)
  639. {
  640. if (enable)
  641. m_shroudFilter=TextureClass::FILTER_TYPE_DEFAULT;
  642. else
  643. m_shroudFilter=TextureClass::FILTER_TYPE_NONE;
  644. }
  645. //-----------------------------------------------------------------------------
  646. ///Set render states required to draw shroud pass.
  647. void W3DShroudMaterialPassClass::Install_Materials(void) const
  648. {
  649. if (TheTerrainRenderObject->getShroud())
  650. {
  651. W3DShaderManager::setTexture(0,TheTerrainRenderObject->getShroud()->getShroudTexture());
  652. W3DShaderManager::setShader(W3DShaderManager::ST_SHROUD_TEXTURE, 0);
  653. }
  654. }
  655. //-----------------------------------------------------------------------------
  656. ///Restore render states that W3D doesn't know about.
  657. void W3DShroudMaterialPassClass::UnInstall_Materials(void) const
  658. {
  659. W3DShaderManager::resetShader(W3DShaderManager::ST_SHROUD_TEXTURE);
  660. }
  661. //-----------------------------------------------------------------------------
  662. ///Set render states required to draw shroud pass.
  663. void W3DMaskMaterialPassClass::Install_Materials(void) const
  664. {
  665. W3DShaderManager::setShader(W3DShaderManager::ST_MASK_TEXTURE, 0);
  666. }
  667. //-----------------------------------------------------------------------------
  668. ///Restore render states that W3D doesn't know about.
  669. void W3DMaskMaterialPassClass::UnInstall_Materials(void) const
  670. {
  671. if (m_allowUninstall)
  672. W3DShaderManager::resetShader(W3DShaderManager::ST_MASK_TEXTURE);
  673. }