| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801 |
- /*
- ** Command & Conquer Generals(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program is free software: you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation, either version 3 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- ////////////////////////////////////////////////////////////////////////////////
- // //
- // (c) 2001-2003 Electronic Arts Inc. //
- // //
- ////////////////////////////////////////////////////////////////////////////////
- // FILE: W3DShroud.cpp /////////////////////////////////////////////////////////////////////////////
- // Created: Mark Wilczynski, Jan 2002
- // Desc: Code to support rendering of shrouded units/terrain.
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- #include "Lib/BaseType.h"
- #include "camera.h"
- #include "simplevec.h"
- #include "dx8wrapper.h"
- #include "common/MapObject.h"
- #include "common/PerfTimer.h"
- #include "W3DDevice/GameClient/HeightMap.h"
- #include "W3DDevice/GameClient/W3DPoly.h"
- #include "W3DDevice/GameClient/W3DShaderManager.h"
- #include "assetmgr.h"
- #include "W3DDevice/GameClient/W3DShroud.h"
- #include "WW3D2/textureloader.h"
- #include "common/GlobalData.h"
- #include "GameLogic/PartitionManager.h"
- #ifdef _INTERNAL
- // for occasional debugging...
- //#pragma optimize("", off)
- //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
- #endif
- //-----------------------------------------------------------------------------
- // In Global Data now
- //#define SHROUD_COLOR 0x00ffffff //temporary test of gray shroud instead of pure black.
- //#define MIN_SHROUD_LEVEL 0 //for gray fog
- //Int SHROUD_COLOR=0x00808080; //temporary test of gray shroud instead of pure black.
- //Int MIN_SHROUD_LEVEL=50; //for gray fog
- //#define SHROUD_COLOR 0x00eeeebff //temporary test of gray shroud instead of pure black.
- //#define MIN_SHROUD_LEVEL 254 //for gray fog
- //#define SHROUD_COLOR 0x00bbbbbb //temporary test of gray shroud instead of pure black.
- //#define SHROUD_COLOR 0x00004080 //temporary test of blue shroud instead of pure black.
- //#define MIN_SHROUD_LEVEL 100 //for black fog
- //#define MAX_MAP_SHROUDSIZE 1024 //maximum number of shroud cells across entire map.
- //#define MAX_VISIBLE_SHROUDSIZE (MAX_MAP_SHROUDSIZE+1) //maximum number of shroud vertices visible at any given time
- #define DEFAULT_SHROUD_CELL_SIZE MAP_XY_FACTOR //assume shroud at same resolution as terrain cells.
- #define DEFAULT_TERRAIN_SIZE 1024 //assumed size of largest terrain possible (in vertices)
- #define DEFAULT_VISIBLE_TERRAIN 96 //assumed size of visible terrain cells.
- //-----------------------------------------------------------------------------
- W3DShroud::W3DShroud(void)
- {
- m_finalFogData=NULL;
- m_currentFogData=NULL;
- m_pSrcTexture=NULL;
- m_pDstTexture=NULL;
- m_srcTextureData=NULL;
- m_srcTexturePitch=NULL;
- m_dstTextureWidth=m_numMaxVisibleCellsX=0;
- m_dstTextureHeight=m_numMaxVisibleCellsY=0;
- m_boderShroudLevel = (W3DShroudLevel)TheGlobalData->m_shroudAlpha; //assume border is black
- m_clearDstTexture = TRUE; //force clearing of destination texture;
- m_cellWidth=DEFAULT_SHROUD_CELL_SIZE;
- m_cellHeight=DEFAULT_SHROUD_CELL_SIZE;
- m_numCellsX=0;
- m_numCellsY=0;
- m_shroudFilter=TextureClass::FILTER_TYPE_DEFAULT;
- }
- //-----------------------------------------------------------------------------
- W3DShroud::~W3DShroud(void)
- {
- ReleaseResources();
- if (m_pSrcTexture)
- m_pSrcTexture->Release();
- m_pSrcTexture=NULL;
- if (m_finalFogData)
- delete [] m_finalFogData;
- if (m_currentFogData)
- delete [] m_currentFogData;
- m_drawFogOfWar=FALSE;
- }
- //-----------------------------------------------------------------------------
- /**Called to initialize a new shroud for a new map. Should be done after the map is loaded
- into the terrain object. worldCellSize is the world-space dimensions of each shroud cell.
- The system will generate enough cells to cover the full map.
- */
- void W3DShroud::init(WorldHeightMap *pMap, Real worldCellSizeX, Real worldCellSizeY)
- {
- DEBUG_ASSERTCRASH( m_pSrcTexture == NULL, ("ReAcquire of existing shroud textures"));
- DEBUG_ASSERTCRASH( pMap != NULL, ("Shroud init with NULL WorldHeightMap"));
- Int dstTextureWidth=0;
- Int dstTextureHeight=0;
- m_cellWidth=worldCellSizeX;
- m_cellHeight=worldCellSizeY;
- //Precompute a bounding box for entire shroud layer
- if (pMap)
- {
- m_numCellsX = REAL_TO_INT_CEIL((Real)(pMap->getXExtent() - 1 - pMap->getBorderSize()*2)*MAP_XY_FACTOR/m_cellWidth);
- m_numCellsY = REAL_TO_INT_CEIL((Real)(pMap->getYExtent() - 1 - pMap->getBorderSize()*2)*MAP_XY_FACTOR/m_cellHeight);
- //Maximum visible cells will depend on maximum drawable terrain size plus 1 for partial cells (since
- //shroud cells are larger than terrain cells).
- dstTextureWidth=m_numMaxVisibleCellsX=REAL_TO_INT_FLOOR((Real)(pMap->getDrawWidth()-1)*MAP_XY_FACTOR/m_cellWidth)+1;
- dstTextureHeight=m_numMaxVisibleCellsY=REAL_TO_INT_FLOOR((Real)(pMap->getDrawHeight()-1)*MAP_XY_FACTOR/m_cellHeight)+1;
- dstTextureWidth += 2; //enlarge by 2 pixels so we can have a border color all the way around.
- dstTextureHeight += 2; //enlarge by 2 pixels so we can have border color all the way around.
- TextureLoader::Validate_Texture_Size((unsigned int &)dstTextureWidth,(unsigned int &)dstTextureHeight);
- }
- UnsignedInt srcWidth,srcHeight;
- srcWidth=m_numCellsX;
- //vertical size is larger by 1 pixel so that we have some unused pixels to use in clearing the video texture.
- //To clear the video texture, I will copy pixels from this unused area. There is no other way to clear a video
- //memory texture to a known value because you can't lock it - only copy into it.
- srcHeight=m_numCellsY;
- srcHeight += 1;
- #ifdef DO_FOG_INTERPOLATION
- m_finalFogData = new W3DShroudLevel[srcWidth*srcHeight];
- m_currentFogData = new W3DShroudLevel[srcWidth*srcHeight];
- //Clear the fog to black
- memset(m_currentFogData,0,srcWidth*srcHeight);
- memset(m_finalFogData,0,srcWidth*srcHeight);
- #endif
- #if defined(_DEBUG) || defined(_INTERNAL)
- if (TheGlobalData && TheGlobalData->m_fogOfWarOn)
- m_pSrcTexture = DX8Wrapper::_Create_DX8_Surface(srcWidth,srcHeight, WW3D_FORMAT_A4R4G4B4);
- else
- #endif
- m_pSrcTexture = DX8Wrapper::_Create_DX8_Surface(srcWidth,srcHeight, WW3D_FORMAT_R5G6B5);
- DEBUG_ASSERTCRASH( m_pSrcTexture != NULL, ("Failed to Allocate Shroud Src Surface"));
- D3DLOCKED_RECT rect;
- //Get a pointer to source surface pixels.
- HRESULT res = m_pSrcTexture->LockRect(&rect,NULL,D3DLOCK_NO_DIRTY_UPDATE);
- m_pSrcTexture->UnlockRect();
- DEBUG_ASSERTCRASH( res == D3D_OK, ("Failed to lock shroud src surface"));
- res = 0;// just to avoid compiler warnings
- m_srcTextureData=rect.pBits;
- m_srcTexturePitch=rect.Pitch;
- //clear entire texture to black
- memset(m_srcTextureData,0,m_srcTexturePitch*srcHeight);
- #if defined(_DEBUG) || defined(_INTERNAL)
- if (TheGlobalData && TheGlobalData->m_fogOfWarOn)
- fillShroudData(TheGlobalData->m_shroudAlpha); //initialize shroud to a known value
- #endif
- if (dstTextureWidth != m_dstTextureWidth || dstTextureHeight != m_dstTextureHeight ) ///@todo: Check if size has changed - probably never
- ReleaseResources(); //need a new sized shroud
- if (!m_pDstTexture )
- { m_dstTextureWidth = dstTextureWidth;
- m_dstTextureHeight = dstTextureHeight;
- ReAcquireResources(); //allocate video memory surface
- }
- //Force a refresh of shroud data since we just created a new source texture.
- if (ThePartitionManager)
- ThePartitionManager->refreshShroudForLocalPlayer();
- }
- //-----------------------------------------------------------------------------
- ///Called on map reset.
- void W3DShroud::reset()
- {
- //Free old shroud data since it may no longer fit new map.
- if (m_pSrcTexture)
- m_pSrcTexture->Release();
- m_pSrcTexture=NULL;
- if (m_finalFogData)
- delete [] m_finalFogData;
- m_finalFogData=NULL;
- if (m_currentFogData)
- delete [] m_currentFogData;
- m_currentFogData=NULL;
- m_clearDstTexture = TRUE; //always refill the destination texture after a reset
- }
- //-----------------------------------------------------------------------------
- ///Release any resources that can't survive a D3D device reset.
- void W3DShroud::ReleaseResources(void)
- {
- REF_PTR_RELEASE (m_pDstTexture);
- }
- //-----------------------------------------------------------------------------
- ///Restore resources that are lost on D3D device reset.
- Bool W3DShroud::ReAcquireResources(void)
- {
- if (!m_dstTextureWidth)
- return TRUE; //nothing to reaquire since shroud was never initialized with valid data
- DEBUG_ASSERTCRASH( m_pDstTexture == NULL, ("ReAcquire of existing shroud texture"));
-
- // Create destination texture (stored in video memory).
- // Since we control the video memory copy, we can do partial updates more efficiently. Or do shift blits.
- #if defined(_DEBUG) || defined(_INTERNAL)
- if (TheGlobalData && TheGlobalData->m_fogOfWarOn)
- m_pDstTexture = MSGNEW("TextureClass") TextureClass(m_dstTextureWidth,m_dstTextureHeight,WW3D_FORMAT_A4R4G4B4,TextureClass::MIP_LEVELS_1, TextureClass::POOL_DEFAULT);
- else
- #endif
- m_pDstTexture = MSGNEW("TextureClass") TextureClass(m_dstTextureWidth,m_dstTextureHeight,WW3D_FORMAT_R5G6B5,TextureClass::MIP_LEVELS_1, TextureClass::POOL_DEFAULT);
- DEBUG_ASSERTCRASH( m_pDstTexture != NULL, ("Failed ReAcquire of shroud texture"));
- if (!m_pDstTexture)
- { //could not create a valid texture
- m_dstTextureWidth = 0;
- m_dstTextureHeight = 0;
- return FALSE;
- }
- m_pDstTexture->Set_U_Addr_Mode(TextureClass::TEXTURE_ADDRESS_CLAMP);
- m_pDstTexture->Set_V_Addr_Mode(TextureClass::TEXTURE_ADDRESS_CLAMP);
- m_pDstTexture->Set_Mip_Mapping(TextureClass::FILTER_TYPE_NONE);
- m_clearDstTexture = TRUE; //force clearing of destination texture first time it's used.
- return TRUE;
- }
- //-----------------------------------------------------------------------------
- W3DShroudLevel W3DShroud::getShroudLevel(Int x, Int y)
- {
- DEBUG_ASSERTCRASH( m_pSrcTexture != NULL, ("Reading empty shroud"));
- if (x < m_numCellsX && y < m_numCellsY)
- {
- UnsignedShort pixel=*(UnsignedShort *)((Byte *)m_srcTextureData + x*2 + y*m_srcTexturePitch);
-
- #if defined(_DEBUG) || defined(_INTERNAL)
- if (TheGlobalData && TheGlobalData->m_fogOfWarOn)
- //in this mode, alpha channel holds intensity
- return (W3DShroudLevel)((1.0f-((Real)(pixel >> 12)/15.0f))*255.0f);
- else
- #endif
- //in this mode, green has the best precision at 6 bits.
- return (W3DShroudLevel)((Real)((pixel >> 5)&0x3f)/63.0f*255.0f);
- }
- return 0;
- }
- //-----------------------------------------------------------------------------
- void W3DShroud::setShroudLevel(Int x, Int y, W3DShroudLevel level, Bool textureOnly)
- {
- DEBUG_ASSERTCRASH( m_pSrcTexture != NULL, ("Writing empty shroud. Usually means that map failed to load."));
- if (!m_pSrcTexture)
- return;
- if (x < m_numCellsX && y < m_numCellsY)
- {
- if (level < TheGlobalData->m_shroudAlpha)
- level = TheGlobalData->m_shroudAlpha;
- #if defined(_DEBUG) || defined(_INTERNAL)
- if (TheGlobalData && TheGlobalData->m_fogOfWarOn)
- {
- ///@todo: optimize this case if we end up using fog shroud.
- Int redVal = TheGlobalData->m_shroudColor.red;
- Int greenVal = TheGlobalData->m_shroudColor.green;
- Int blueVal = TheGlobalData->m_shroudColor.blue;
- // Int redVal = (SHROUD_COLOR >> 16) & 0xff;
- // Int greenVal = (SHROUD_COLOR >> 8) & 0xff;
- // Int blueVal = SHROUD_COLOR & 0xff;
- Int alphaVal = 255 - level;
- UnsignedShort pixel=((blueVal>>4)&0xf) | (((greenVal>>4)&0xf)<<4) | (((redVal>>4)&0xf)<<8) | (((alphaVal>>4)&0xf)<<12);
- *(UnsignedShort *)((Byte *)m_srcTextureData + x*2 + y*m_srcTexturePitch)=pixel;
- }
- else
- #endif
- {
- #ifdef DO_FOG_INTERPOLATION
- if (!textureOnly)
- m_finalFogData[x+y*m_numCellsX]=level;
- #endif
- UnsignedInt bluepixel = (UnsignedInt)((Real)level*((Real)(TheGlobalData->m_shroudColor.getAsInt()&0xff)/255.0f));
- UnsignedInt greenpixel = (UnsignedInt)((Real)level*((Real)((TheGlobalData->m_shroudColor.getAsInt()&0xff00)>>8)/255.0f));
- UnsignedInt redpixel = (UnsignedInt)((Real)level*((Real)((TheGlobalData->m_shroudColor.getAsInt()&0xff0000)>>16)/255.0f));
- // UnsignedInt bluepixel = (UnsignedInt)((Real)level*((Real)(SHROUD_COLOR&0xff)/255.0f));
- // UnsignedInt greenpixel = (UnsignedInt)((Real)level*((Real)((SHROUD_COLOR&0xff00)>>8)/255.0f));
- // UnsignedInt redpixel = (UnsignedInt)((Real)level*((Real)((SHROUD_COLOR&0xff0000)>>16)/255.0f));
- if (level == 255)
- { //unshrouded pixels should be fully lit
- redpixel = 255;
- greenpixel = 255;
- bluepixel = 255;
- }
- UnsignedShort *texel = (UnsignedShort *)((Byte *)m_srcTextureData + x*2 + y*m_srcTexturePitch);
- // For those interested, MLorenzen has this bock commented out until he gets back on Mon, Sept. 30 2002
- // If this code is still here by mid october, nuke it!
- // UnsignedInt texelRed = ((*texel >> 8 ) & 0xf8);
- // UnsignedInt texelGreen =((*texel >> 3 ) & 0xfc);
- // UnsignedInt texelBlue = ((*texel << 3 ) & 0xf8);
- // if (texelRed < texelGreen && texelGreen > texelBlue)
- // {
- // bluepixel += redpixel;
- // bluepixel -= redpixel;
- // }
- *texel = ( ((bluepixel&0xf8) >> 3) | ((greenpixel&0xfc)<<3) | ((redpixel&0xf8)<<8));
- }
- return;
- }
- }
- //-----------------------------------------------------------------------------
- ///Quickly sets the shroud level of entire map to a single value
- void W3DShroud::fillShroudData(W3DShroudLevel level)
- {
- Int x,y;
- UnsignedShort pixel;
- if (level < TheGlobalData->m_shroudAlpha)
- level = TheGlobalData->m_shroudAlpha;
- #if defined(_DEBUG) || defined(_INTERNAL)
- //convert value to pixel format
- if (TheGlobalData && TheGlobalData->m_fogOfWarOn)
- {
- Int redVal = TheGlobalData->m_shroudColor.red;
- Int greenVal = TheGlobalData->m_shroudColor.green;
- Int blueVal = TheGlobalData->m_shroudColor.blue;
- // Int redVal = (SHROUD_COLOR >> 16) & 0xff;
- // Int greenVal = (SHROUD_COLOR >> 8) & 0xff;
- // Int blueVal = SHROUD_COLOR & 0xff;
- Int alphaVal = 255 - level;
- pixel=((blueVal>>4)&0xf) | (((greenVal>>4)&0xf)<<4) | (((redVal>>4)&0xf)<<8) | (((alphaVal>>4)&0xf)<<12);
- }
- else
- #endif
- {
- UnsignedInt bluepixel = (UnsignedInt)((Real)level*((Real)(TheGlobalData->m_shroudColor.getAsInt()&0xff)/255.0f));
- UnsignedInt greenpixel = (UnsignedInt)((Real)level*((Real)((TheGlobalData->m_shroudColor.getAsInt()&0xff00)>>8)/255.0f));
- UnsignedInt redpixel = (UnsignedInt)((Real)level*((Real)((TheGlobalData->m_shroudColor.getAsInt()&0xff0000)>>16)/255.0f));
- // UnsignedInt bluepixel = (UnsignedInt)((Real)level*((Real)(SHROUD_COLOR&0xff)/255.0f));
- // UnsignedInt greenpixel = (UnsignedInt)((Real)level*((Real)((SHROUD_COLOR&0xff00)>>8)/255.0f));
- // UnsignedInt redpixel = (UnsignedInt)((Real)level*((Real)((SHROUD_COLOR&0xff0000)>>16)/255.0f));
- if (level == 255)
- { //unshrouded pixels should be fully lit
- redpixel = 255;
- greenpixel = 255;
- bluepixel = 255;
- }
- pixel=( ((bluepixel&0xf8) >> 3) | ((greenpixel&0xfc)<<3) | ((redpixel&0xf8)<<8));
- }
- UnsignedShort *ptr=(UnsignedShort *)m_srcTextureData;
- Int pitch = m_srcTexturePitch >> 1; //2 bytes per pointer increment
- for (y=0; y<m_numCellsY; y++)
- {
- for (x=0; x<m_numCellsX; x++)
- ptr[x]=pixel;
- ptr += pitch;
- }
- #ifdef DO_FOG_INTERPOLATION
- //Set the final shroud state. May differe from current state because of time interpolation.
- W3DShroudLevel *cptr=m_finalFogData;
- pitch = m_numCellsX;
- for (y=0; y<m_numCellsY; y++)
- {
- for (x=0; x<m_numCellsX; x++)
- cptr[x]=level;
- ptr += pitch;
- }
- #endif
- }
- void W3DShroud::fillBorderShroudData(W3DShroudLevel level, SurfaceClass* pDestSurface)
- {
- Int x,y;
- UnsignedShort pixel;
- if (level < TheGlobalData->m_shroudAlpha)
- level = TheGlobalData->m_shroudAlpha;
- #if defined(_DEBUG) || defined(_INTERNAL)
- //convert value to pixel format
- if (TheGlobalData && TheGlobalData->m_fogOfWarOn)
- {
- Int redVal = TheGlobalData->m_shroudColor.red;
- Int greenVal = TheGlobalData->m_shroudColor.green;
- Int blueVal = TheGlobalData->m_shroudColor.blue;
- Int alphaVal = 255 - level;
- pixel=((blueVal>>4)&0xf) | (((greenVal>>4)&0xf)<<4) | (((redVal>>4)&0xf)<<8) | (((alphaVal>>4)&0xf)<<12);
- }
- else
- #endif
- {
- UnsignedInt bluepixel = (UnsignedInt)((Real)level*((Real)(TheGlobalData->m_shroudColor.getAsInt()&0xff)/255.0f));
- UnsignedInt greenpixel = (UnsignedInt)((Real)level*((Real)((TheGlobalData->m_shroudColor.getAsInt()&0xff00)>>8)/255.0f));
- UnsignedInt redpixel = (UnsignedInt)((Real)level*((Real)((TheGlobalData->m_shroudColor.getAsInt()&0xff0000)>>16)/255.0f));
- if (level == 255)
- { //unshrouded pixels should be fully lit
- redpixel = 255;
- greenpixel = 255;
- bluepixel = 255;
- }
- pixel=( ((bluepixel&0xf8) >> 3) | ((greenpixel&0xfc)<<3) | ((redpixel&0xf8)<<8));
- }
- //Skip to unused texels within the shroud data
- UnsignedShort *ptr=(UnsignedShort *)m_srcTextureData + m_numCellsY*(m_srcTexturePitch >> 1);
- //Fill unused texels with border color
- for (x=0; x<m_numCellsX; x++)
- ptr[x]=pixel;
- //Fill destination texture with border color
- RECT srcRect;
- //create a rectangle enclosing bottom row of unused pixels long enough
- //to cover destination width.
- srcRect.left=0;
- srcRect.top=m_numCellsY;
- srcRect.right= m_numCellsX;
- srcRect.bottom= m_numCellsY+1;
- POINT dstPoint={0,0};
- Int numFullCopies = m_dstTextureWidth/srcRect.right;
- Int numExtraPixels = m_dstTextureWidth%srcRect.right;
- for (y=0; y<m_dstTextureHeight; y++)
- {
- dstPoint.y=y;
- dstPoint.x=0;
- for (x=0; x<numFullCopies; x++)
- {
- dstPoint.x = x * srcRect.right; //advance to next set of pixel in row.
- DX8Wrapper::_Copy_DX8_Rects(
- m_pSrcTexture,
- &srcRect,
- 1,
- pDestSurface->Peek_D3D_Surface(),
- &dstPoint);
- }
- if (numExtraPixels)
- { Int oldVal=srcRect.right;
- dstPoint.x = numFullCopies * oldVal;
- srcRect.right = numExtraPixels;
- DX8Wrapper::_Copy_DX8_Rects(
- m_pSrcTexture,
- &srcRect,
- 1,
- pDestSurface->Peek_D3D_Surface(),
- &dstPoint);
- srcRect.right = oldVal;
- }
- }
-
- }
- /**Set the shroud color within the border area of the map*/
- void W3DShroud::setBorderShroudLevel(W3DShroudLevel level)
- {
- m_boderShroudLevel = level;
- m_clearDstTexture = TRUE;
- }
- //-----------------------------------------------------------------------------
- ///@todo: remove this
- TextureClass *DummyTexture=NULL;
- //#define LOAD_DUMMY_SHROUD
- //-----------------------------------------------------------------------------
- //DECLARE_PERF_TIMER(shroudCopy)
- //-----------------------------------------------------------------------------
- /** Updates video memory surface with currently visible shroud data */
- void W3DShroud::render(CameraClass *cam)
- {
- if (!m_pSrcTexture)
- return; //nothing to update from. Must be in reset state.
- if (DX8Wrapper::_Get_D3D_Device8() && (DX8Wrapper::_Get_D3D_Device8()->TestCooperativeLevel()) != D3D_OK)
- return; //device not ready to render anything
- #if defined(_DEBUG) || defined(_INTERNAL)
- if (TheGlobalData && TheGlobalData->m_fogOfWarOn != m_drawFogOfWar)
- {
- //fog state has changed since last time shroud system was initialized
- reset();
- ReleaseResources();
- init(TheTerrainRenderObject->getMap(),m_cellWidth,m_cellHeight);
- ThePartitionManager->refreshShroudForLocalPlayer();
- m_drawFogOfWar=TheGlobalData->m_fogOfWarOn;
- m_clearDstTexture=TRUE;
- }
- #endif
- DEBUG_ASSERTCRASH( m_pSrcTexture != NULL, ("Updating unallocated shroud texture"));
- #ifdef LOAD_DUMMY_SHROUD
-
- static doInit=1;
- if (doInit)
- {
- //some temporary code here to debug the shroud.
- ///@todo: remove this debug buffer fill.
- fillShroudData(1.0f); //force to all shrouded
- Short *src=(Short *)m_srcTextureData;
- //fill with some dummy values
- src[0]=(char)0xff;
- src[1]=(char)0xff;
- src[m_numCellsX]=(char)0xff;
- src[m_numCellsX+1]=(char)0xff;
- src[m_numCellsX*2]=(char)0xff;
- src[m_numCellsX*9+8]=(char)0xff;
- src[m_numCellsX*8+8]=(char)0xff;
- src[m_numCellsX*7+8]=(char)0xff;
- src[m_numCellsX*8+9]=(char)0xff;
- src[m_numCellsX*8+7]=(char)0xff;
- DummyTexture=WW3DAssetManager::Get_Instance()->Get_Texture("shroud1024.tga");
- Short *dataDest=(Short *)((char *)m_srcTextureData); //offset to correct row of full sysmem shroud
- Int pitchDest = m_srcTexturePitch >> 1; //2 bytes per pixel so divide byte count by 2.
- //Copy the dummy shroud into our game shroud.
- SurfaceClass *pSurface=DummyTexture->Get_Surface_Level(0);
- Int pitch;
- Int *dataSrc=(Int *)((char *)pSurface->Lock(&pitch)); //offset to correct row of full sysmem shroud
- pitch >>= 2; //4 bytes per pixel so divide byte count by 4.
- SurfaceClass::SurfaceDescription desc;
- pSurface->Get_Description(desc);
- //Check if source data is larger than our current shroud
- desc.Width = __min(desc.Width,m_numCellsX);
- desc.Height = __min(desc.Height,m_numCellsY);
- for (Int y=0; y<desc.Height; y++)
- {
- for (Int x=0; x<desc.Width; x++)
- {
- #if defined(_DEBUG) || defined(_INTERNAL)
- if (TheGlobalData && TheGlobalData->m_fogOfWarOn)
- {
- 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);
- // dataDest[x]=((SHROUD_COLOR>>4)&0xf) | (((SHROUD_COLOR>>12)&0xf)<<4) | (((SHROUD_COLOR>>20)&0xf)<<8) | ((((255-(dataSrc[x] & 0xff))>>4)&0xf)<<12);
- }
- else
- #endif
- {
- dataDest[x]=((dataSrc[x]>>3)&0x1f) | (((dataSrc[x]>>10)&0x3f)<<5) | (((dataSrc[x]>>19)&0x1f)<<11);
- }
- }
- dataDest += pitchDest; //skip to next row.
- dataSrc += pitch; //skip to next row of shroud
- }
- pSurface->Unlock();
- REF_PTR_RELEASE (pSurface);
- REF_PTR_RELEASE (DummyTexture);
- doInit=0;
- }
- #endif //LOAD_DUMMY_SHROUD
- WorldHeightMap *hm=TheTerrainRenderObject->getMap();
- Int visStartX=REAL_TO_INT_FLOOR((Real)(hm->getDrawOrgX()-hm->getBorderSize())*MAP_XY_FACTOR/m_cellWidth); //start of rendered heightmap rectangle
- if (visStartX < 0)
- visStartX = 0; //no shroud is applied in border area so it always starts at > 0
- Int visStartY=REAL_TO_INT_FLOOR((Real)(hm->getDrawOrgY()-hm->getBorderSize())*MAP_XY_FACTOR/m_cellHeight);
- if (visStartY < 0)
- visStartY = 0; //no shroud is applied in border area so it always starts at > 0
- Int visEndX=visStartX+REAL_TO_INT_FLOOR((Real)(hm->getDrawWidth()-1)*MAP_XY_FACTOR/m_cellWidth)+1; //size of rendered heightmap rectangle
- Int visEndY=visStartY+REAL_TO_INT_FLOOR((Real)(hm->getDrawHeight()-1)*MAP_XY_FACTOR/m_cellHeight)+1;
- if (visEndX > m_numCellsX)
- {
- visStartX -= visEndX - m_numCellsX; //shift visible rectangle to fall within terrain bounds
- if (visStartX < 0)
- visStartX = 0;
- visEndX = m_numCellsX;
- }
- if (visEndY > m_numCellsY)
- {
- visStartY -= visEndY - m_numCellsY; //shift visible rectangle to fall within terrain bounds
- if (visStartY < 0)
- visStartY = 0;
- visEndY = m_numCellsY;
- }
- m_drawOriginX = (Real)visStartX * m_cellWidth;
- m_drawOriginY = (Real)visStartY * m_cellHeight;
- //If system memory usage becomes too large, we should store shroud as Bytes. Update
- //a system memory texture with data. Then copy this to video memory. For now we're
- //holding shroud data directly in a texture to avoid the extra copy.
- /* pSurface=m_pSrcTexture->Get_Surface_Level(0);
- data=(Short *)((char *)pSurface->Lock(&pitch) + visStartY*pitch); //offset to correct row of full sysmem shroud
- pitch >>= 1; //we have 2 bytes per pixel, so divide pitch by 2
- Byte *sd=shroudData+visStartY*MAX_MAP_SHROUDSIZE; //pointer to first shroud row
-
- for (Int y=visStartY; y<(visStartY+visSizeY); y++)
- {
- for (Int x=visStartX; x<(visStartX+visSizeX); x++)
- {
- data[x]=sd[x]|(sd[x]<<8);
- }
- data += pitch; //skip to next row.
- sd += MAX_MAP_SHROUDSIZE; //skip to next row of shroud
- }
- pSurface->Unlock();
- */
- if (m_pDstTexture->Get_Mag_Filter() != m_shroudFilter)
- {
- m_pDstTexture->Set_Mag_Filter(m_shroudFilter);
- m_pDstTexture->Set_Min_Filter(m_shroudFilter);
- }
- //Update video memory texture with sysmem copy
- SurfaceClass* pDestSurface;
- {
- pDestSurface=m_pDstTexture->Get_Surface_Level(0);
- }
- RECT srcRect;
- POINT dstPoint={1,1}; //first row/column is reserved for border.
-
- srcRect.left=visStartX;
- srcRect.top=visStartY;
- srcRect.right=visEndX;
- srcRect.bottom=visEndY;
- #ifdef DO_FOG_INTERPOLATION
- //interpolate current shroud state to the final one
- interpolateFogLevels(&srcRect);
- #endif
- if (m_clearDstTexture)
- { //we need to clear unused parts of the destination texture to a known
- //color in order to keep map border in the state we want.
- m_clearDstTexture=FALSE;
-
- fillBorderShroudData(m_boderShroudLevel, pDestSurface);
- }
- {
- //USE_PERF_TIMER(shroudCopy)
- DX8Wrapper::_Copy_DX8_Rects(
- m_pSrcTexture,
- &srcRect,
- 1,
- pDestSurface->Peek_D3D_Surface(),
- &dstPoint);
- }
- REF_PTR_RELEASE (pDestSurface);
- }
- #define FOG_INTERPOLATION_RATE (255.0f/1000.0f) //take one second to go from black to fully lit.
- //-----------------------------------------------------------------------------
- void W3DShroud::interpolateFogLevels(RECT *rect)
- {
- static UnsignedInt prevTime = timeGetTime();
- UnsignedInt timeDiff=timeGetTime()-prevTime;
- if (!timeDiff)
- return; //no time has elapsed
- prevTime +=timeDiff; //update for next frame
- Int maxFogChange=FOG_INTERPOLATION_RATE * (Real)timeDiff; //maximum amount of fog change allowed in frame.
- if (maxFogChange > 255)
- maxFogChange = 255;
- W3DShroudLevel levelDelta = maxFogChange;
- W3DShroudLevel *startLevel=m_currentFogData;
- W3DShroudLevel *finalLevel=m_finalFogData;
- for (Int j=0; j<m_numCellsY; j++)
- {
- for (Int i=0; i<m_numCellsX; i++,startLevel++,finalLevel++)
- if (*startLevel != *finalLevel)
- { //fog needs fading.
- if (*startLevel == *finalLevel)
- continue;
- else
- if (*finalLevel < *startLevel)
- {
- if ((*startLevel - *finalLevel) < levelDelta)
- *startLevel = *finalLevel; //change too large so clamp to final value.
- else
- *startLevel -= levelDelta;
- }
- else
- if (*finalLevel > *startLevel)
- {
- if ((*finalLevel - *startLevel) < levelDelta)
- *startLevel = *finalLevel; //change too large so clamp to final value.
- else
- *startLevel += levelDelta;
- }
- setShroudLevel(i,j,*startLevel,TRUE);
- }
- }
- }
- //-----------------------------------------------------------------------------
- void W3DShroud::setShroudFilter(Bool enable)
- {
- if (enable)
- m_shroudFilter=TextureClass::FILTER_TYPE_DEFAULT;
- else
- m_shroudFilter=TextureClass::FILTER_TYPE_NONE;
- }
- //-----------------------------------------------------------------------------
- ///Set render states required to draw shroud pass.
- void W3DShroudMaterialPassClass::Install_Materials(void) const
- {
- if (TheTerrainRenderObject->getShroud())
- {
- W3DShaderManager::setTexture(0,TheTerrainRenderObject->getShroud()->getShroudTexture());
- W3DShaderManager::setShader(W3DShaderManager::ST_SHROUD_TEXTURE, 0);
- }
- }
- //-----------------------------------------------------------------------------
- ///Restore render states that W3D doesn't know about.
- void W3DShroudMaterialPassClass::UnInstall_Materials(void) const
- {
- W3DShaderManager::resetShader(W3DShaderManager::ST_SHROUD_TEXTURE);
- }
- //-----------------------------------------------------------------------------
- ///Set render states required to draw shroud pass.
- void W3DMaskMaterialPassClass::Install_Materials(void) const
- {
- W3DShaderManager::setShader(W3DShaderManager::ST_MASK_TEXTURE, 0);
- }
- //-----------------------------------------------------------------------------
- ///Restore render states that W3D doesn't know about.
- void W3DMaskMaterialPassClass::UnInstall_Materials(void) const
- {
- if (m_allowUninstall)
- W3DShaderManager::resetShader(W3DShaderManager::ST_MASK_TEXTURE);
- }
|