W3DShroud.cpp 28 KB

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