From dfb477c7e1d940b5d07d2a576f7a19ce6952f3a6 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Sat, 13 Dec 2025 23:12:18 +0100 Subject: [PATCH 1/2] unify(texture): Merge W3DWater and WW3D2 texture code (#1989) --- .../GameClient/Drawable/Draw/W3DLaserDraw.cpp | 3 + .../GameClient/Shadow/W3DProjectedShadow.cpp | 2 +- .../W3DDevice/GameClient/W3DAssetManager.cpp | 2 +- .../W3DDevice/GameClient/W3DDisplay.cpp | 1 - .../W3DDevice/GameClient/Water/W3DWater.cpp | 86 +- .../GameClient/Water/W3DWaterTracks.cpp | 30 + .../Source/WWVegas/WW3D2/assetmgr.cpp | 64 +- .../Libraries/Source/WWVegas/WW3D2/assetmgr.h | 1 - .../Libraries/Source/WWVegas/WW3D2/bmp2d.cpp | 26 +- .../Source/WWVegas/WW3D2/dx8caps.cpp | 2 + .../Source/WWVegas/WW3D2/dx8texman.h | 44 +- .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 652 +++- .../Source/WWVegas/WW3D2/dx8wrapper.h | 62 +- .../Source/WWVegas/WW3D2/texproject.cpp | 58 +- .../Source/WWVegas/WW3D2/texproject.h | 21 +- .../Source/WWVegas/WW3D2/texture.cpp | 2112 ++++++++--- .../Libraries/Source/WWVegas/WW3D2/texture.h | 542 ++- .../Source/WWVegas/WW3D2/texturefilter.cpp | 149 +- .../Source/WWVegas/WW3D2/texturefilter.h | 4 +- .../Source/WWVegas/WW3D2/textureloader.cpp | 3142 ++++++++++++----- .../Source/WWVegas/WW3D2/textureloader.h | 339 +- .../Source/WWVegas/WW3D2/texturethumbnail.cpp | 435 ++- .../Source/WWVegas/WW3D2/texturethumbnail.h | 84 +- .../Libraries/Source/WWVegas/WW3D2/ww3d.cpp | 12 +- .../Libraries/Source/WWVegas/WW3D2/ww3d.h | 2 +- .../Tools/WorldBuilder/src/ObjectPreview.cpp | 2 +- .../Tools/WorldBuilder/src/WorldBuilder.cpp | 1 - .../W3DDevice/GameClient/Water/W3DWater.cpp | 10 +- .../GameClient/Water/W3DWaterTracks.cpp | 6 +- 29 files changed, 5861 insertions(+), 2033 deletions(-) diff --git a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DLaserDraw.cpp b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DLaserDraw.cpp index c79b154f017..cf4944e2647 100644 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DLaserDraw.cpp +++ b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DLaserDraw.cpp @@ -124,6 +124,9 @@ W3DLaserDraw::W3DLaserDraw( Thing *thing, const ModuleData* moduleData ) : m_texture = WW3DAssetManager::Get_Instance()->Get_Texture( data->m_textureName.str() ); if (m_texture) { + if (!m_texture->Is_Initialized()) + m_texture->Init(); //make sure texture is actually loaded before accessing surface. + SurfaceClass::SurfaceDescription surfaceDesc; m_texture->Get_Level_Description(surfaceDesc); m_textureAspectRatio = (Real)surfaceDesc.Width/(Real)surfaceDesc.Height; diff --git a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Shadow/W3DProjectedShadow.cpp b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Shadow/W3DProjectedShadow.cpp index 7466599e104..49c3c00e9b5 100644 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Shadow/W3DProjectedShadow.cpp +++ b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Shadow/W3DProjectedShadow.cpp @@ -261,7 +261,7 @@ Bool W3DProjectedShadowManager::ReAcquireResources(void) DEBUG_ASSERTCRASH(m_dynamicRenderTarget == NULL, ("Acquire of existing shadow render target")); m_renderTargetHasAlpha=TRUE; - if ((m_dynamicRenderTarget=DX8Wrapper::Create_Render_Target (DEFAULT_RENDER_TARGET_WIDTH, DEFAULT_RENDER_TARGET_HEIGHT, true)) == NULL) + if ((m_dynamicRenderTarget=DX8Wrapper::Create_Render_Target (DEFAULT_RENDER_TARGET_WIDTH, DEFAULT_RENDER_TARGET_HEIGHT, WW3D_FORMAT_A8R8G8B8)) == NULL) { m_renderTargetHasAlpha=FALSE; diff --git a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DAssetManager.cpp b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DAssetManager.cpp index 55a53a8596d..a0143fd001a 100644 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DAssetManager.cpp +++ b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DAssetManager.cpp @@ -627,7 +627,7 @@ TextureClass * W3DAssetManager::Recolor_Texture_One_Time(TextureClass *texture, // make sure texture is loaded if (!texture->Is_Initialized()) - TextureLoader::Request_High_Priority_Loading(texture, (MipCountType)texture->Get_Mip_Level_Count()); + TextureLoader::Request_Foreground_Loading(texture); SurfaceClass::SurfaceDescription desc; SurfaceClass *newsurf, *oldsurf; diff --git a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp index b8ce435c769..88b25cd33ae 100644 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp +++ b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp @@ -402,7 +402,6 @@ W3DDisplay::~W3DDisplay() // shutdown Debug_Statistics::Shutdown_Statistics(); - TextureLoadTaskClass::shutdown(); if (!TheGlobalData->m_headless) W3DShaderManager::shutdown(); m_assetManager->Free_Assets(); diff --git a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWater.cpp b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWater.cpp index 258bf46c868..3b15a0667ef 100644 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWater.cpp +++ b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWater.cpp @@ -209,6 +209,8 @@ void WaterRenderObjClass::setupJbaWaterShader(void) DX8Wrapper::Apply_Render_State_Changes(); //force update of view and projection matrices DX8Wrapper::Set_DX8_Texture_Stage_State( 0, D3DTSS_ALPHAOP, D3DTOP_ADD ); + if (!m_riverAlphaEdge->Is_Initialized()) + m_riverAlphaEdge->Init(); DX8Wrapper::_Get_D3D_Device8()->SetTexture(3,m_riverAlphaEdge->Peek_D3D_Texture()); DX8Wrapper::Set_DX8_Texture_Stage_State(3, D3DTSS_ADDRESSU, D3DTADDRESS_WRAP); DX8Wrapper::Set_DX8_Texture_Stage_State(3, D3DTSS_ADDRESSV, D3DTADDRESS_WRAP); @@ -219,7 +221,12 @@ void WaterRenderObjClass::setupJbaWaterShader(void) Bool doSparkles = true; if (m_riverWaterPixelShader && doSparkles) { + if (!m_waterSparklesTexture->Is_Initialized()) + m_waterSparklesTexture->Init(); DX8Wrapper::_Get_D3D_Device8()->SetTexture(1,m_waterSparklesTexture->Peek_D3D_Texture()); + + if (!m_waterNoiseTexture->Is_Initialized()) + m_waterNoiseTexture->Init(); DX8Wrapper::_Get_D3D_Device8()->SetTexture(2,m_waterNoiseTexture->Peek_D3D_Texture()); DX8Wrapper::Set_DX8_Texture_Stage_State(1, D3DTSS_ADDRESSU, D3DTADDRESS_WRAP); @@ -526,7 +533,7 @@ HRESULT WaterRenderObjClass::initBumpMap(LPDIRECT3DTEXTURE8 *pTex, TextureClass pSrc=(unsigned char *)surf->Lock((int *)&dwSrcPitch); // Create the bumpmap's surface and texture objects - m_pBumpTexture[i]=DX8Wrapper::_Create_DX8_Texture(d3dsd.Width,d3dsd.Height,WW3D_FORMAT_U8V8,MIP_LEVELS_1,D3DPOOL_MANAGED,false); + m_pBumpTexture[i]=DX8Wrapper::_Create_DX8_Texture(d3dsd.Width,d3dsd.Height,WW3D_FORMAT_U8V8,TextureClass::MIP_LEVELS_1,D3DPOOL_MANAGED,false); // Fill the bits of the new texture surface with bits from // a private format. @@ -944,6 +951,22 @@ void WaterRenderObjClass::ReAcquireResources(void) } } + //W3D Invalidate textures after losing the device and since we peek at the textures directly, it won't + //know to reinit them for us. Do it here manually: + if (m_riverTexture && !m_riverTexture->Is_Initialized()) + m_riverTexture->Init(); + if (m_waterNoiseTexture && !m_waterNoiseTexture->Is_Initialized()) + m_waterNoiseTexture->Init(); + if (m_riverAlphaEdge && !m_riverAlphaEdge->Is_Initialized()) + m_riverAlphaEdge->Init(); + if (m_waterSparklesTexture && !m_waterSparklesTexture->Is_Initialized()) + m_waterSparklesTexture->Init(); + if (m_whiteTexture && !m_whiteTexture->Is_Initialized()) + { m_whiteTexture->Init(); + SurfaceClass *surface=m_whiteTexture->Get_Surface_Level(); + surface->DrawPixel(0,0,0xffffffff); + REF_PTR_RELEASE(surface); + } } void WaterRenderObjClass::load(void) @@ -1428,7 +1451,7 @@ void WaterRenderObjClass::renderMirror(CameraClass *cam) Matrix3D reflectedTransform(rRight,rUp,rN,rPos); - DX8Wrapper::Set_Render_Target(m_pReflectionTexture); + DX8Wrapper::Set_Render_Target_With_Z((TextureClass*)m_pReflectionTexture); // Clear the backbuffer WW3D::Begin_Render(false,true,Vector3(0.0f,0.0f,0.0f)); //clearing only z-buffer since background always filled with clouds @@ -1619,11 +1642,11 @@ void WaterRenderObjClass::Render(RenderInfoClass & rinfo) DX8Wrapper::Set_DX8_Render_State(D3DRS_ALPHATESTENABLE, true); //test pixels if transparent(clipped) before rendering. // Set clipping texture - m_alphaClippingTexture->Set_U_Addr_Mode(TextureFilterClass::TEXTURE_ADDRESS_CLAMP); - m_alphaClippingTexture->Set_V_Addr_Mode(TextureFilterClass::TEXTURE_ADDRESS_CLAMP); - m_alphaClippingTexture->Set_Min_Filter(TextureFilterClass::FILTER_TYPE_NONE); - m_alphaClippingTexture->Set_Mag_Filter(TextureFilterClass::FILTER_TYPE_NONE); - m_alphaClippingTexture->Set_Mip_Mapping(TextureFilterClass::FILTER_TYPE_NONE); + m_alphaClippingTexture->Set_U_Addr_Mode(TextureClass::TEXTURE_ADDRESS_CLAMP); + m_alphaClippingTexture->Set_V_Addr_Mode(TextureClass::TEXTURE_ADDRESS_CLAMP); + m_alphaClippingTexture->Set_Min_Filter(TextureClass::FILTER_TYPE_NONE); + m_alphaClippingTexture->Set_Mag_Filter(TextureClass::FILTER_TYPE_NONE); + m_alphaClippingTexture->Set_Mip_Mapping(TextureClass::FILTER_TYPE_NONE); DX8Wrapper::Set_Texture(0,m_alphaClippingTexture); @@ -2904,6 +2927,22 @@ void WaterRenderObjClass::drawRiverWater(PolygonTrigger *pTrig) void WaterRenderObjClass::setupFlatWaterShader(void) { + + DX8Wrapper::Set_Texture(0,m_riverTexture); + if (!TheWaterTransparency->m_additiveBlend) + DX8Wrapper::Set_Shader(ShaderClass::_PresetAlphaShader); + else + DX8Wrapper::Set_Shader(ShaderClass::_PresetAdditiveShader); + + VertexMaterialClass *vmat=VertexMaterialClass::Get_Preset(VertexMaterialClass::PRELIT_DIFFUSE); + DX8Wrapper::Set_Material(vmat); + REF_PTR_RELEASE(vmat); + m_riverTexture->Get_Filter().Set_Mag_Filter(TextureFilterClass::FILTER_TYPE_BEST); + m_riverTexture->Get_Filter().Set_Min_Filter(TextureFilterClass::FILTER_TYPE_BEST); + m_riverTexture->Get_Filter().Set_Mip_Mapping(TextureFilterClass::FILTER_TYPE_BEST); + + DX8Wrapper::Apply_Render_State_Changes(); //force update of view and projection matrices + //Setup shroud to render in same pass as water if (m_trapezoidWaterPixelShader) { if (TheTerrainRenderObject->getShroud()) @@ -2911,10 +2950,6 @@ void WaterRenderObjClass::setupFlatWaterShader(void) W3DShaderManager::setTexture(0,TheTerrainRenderObject->getShroud()->getShroudTexture()); //Use stage 3 to apply the shroud W3DShaderManager::setShader(W3DShaderManager::ST_SHROUD_TEXTURE, 3); - m_pDev->SetTextureStageState( 3, D3DTSS_MINFILTER, D3DTEXF_LINEAR ); - m_pDev->SetTextureStageState( 3, D3DTSS_MAGFILTER, D3DTEXF_LINEAR ); - m_pDev->SetTextureStageState( 3, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP); - m_pDev->SetTextureStageState( 3, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP); //Shroud shader uses z-compare of EQUAL which wouldn't work on water because it doesn't //write to the zbuffer. Change to LESSEQUAL. DX8Wrapper::_Get_D3D_Device8()->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL); @@ -2922,25 +2957,16 @@ void WaterRenderObjClass::setupFlatWaterShader(void) else { //Assume no shroud, so stage 3 will be "NULL" texture but using actual white because //pixel shader on GF4 generates random colors with SetTexture(3,NULL). + if (!m_whiteTexture->Is_Initialized()) + { m_whiteTexture->Init(); + SurfaceClass *surface=m_whiteTexture->Get_Surface_Level(); + surface->DrawPixel(0,0,0xffffffff); + REF_PTR_RELEASE(surface); + } DX8Wrapper::_Get_D3D_Device8()->SetTexture(3,m_whiteTexture->Peek_D3D_Texture()); } } - DX8Wrapper::Set_Texture(0,m_riverTexture); - if (!TheWaterTransparency->m_additiveBlend) - DX8Wrapper::Set_Shader(ShaderClass::_PresetAlphaShader); - else - DX8Wrapper::Set_Shader(ShaderClass::_PresetAdditiveShader); - - VertexMaterialClass *vmat=VertexMaterialClass::Get_Preset(VertexMaterialClass::PRELIT_DIFFUSE); - DX8Wrapper::Set_Material(vmat); - REF_PTR_RELEASE(vmat); - m_riverTexture->Get_Filter().Set_Mag_Filter(TextureFilterClass::FILTER_TYPE_BEST); - m_riverTexture->Get_Filter().Set_Min_Filter(TextureFilterClass::FILTER_TYPE_BEST); - m_riverTexture->Get_Filter().Set_Mip_Mapping(TextureFilterClass::FILTER_TYPE_BEST); - - DX8Wrapper::Apply_Render_State_Changes(); //force update of view and projection matrices - DX8Wrapper::Set_DX8_Texture_Stage_State( 0, D3DTSS_ALPHAOP, D3DTOP_ADD ); DX8Wrapper::Set_DX8_Texture_Stage_State(0, D3DTSS_TEXCOORDINDEX, 0); DX8Wrapper::Set_DX8_Texture_Stage_State(1, D3DTSS_TEXCOORDINDEX, 0); @@ -2948,7 +2974,15 @@ void WaterRenderObjClass::setupFlatWaterShader(void) Bool doSparkles = true; if (m_trapezoidWaterPixelShader && doSparkles) { + + if (!m_waterSparklesTexture->Is_Initialized()) + m_waterSparklesTexture->Init(); + DX8Wrapper::_Get_D3D_Device8()->SetTexture(1,m_waterSparklesTexture->Peek_D3D_Texture()); + + if (!m_waterNoiseTexture->Is_Initialized()) + m_waterNoiseTexture->Init(); + DX8Wrapper::_Get_D3D_Device8()->SetTexture(2,m_waterNoiseTexture->Peek_D3D_Texture()); DX8Wrapper::Set_DX8_Texture_Stage_State(1, D3DTSS_ADDRESSU, D3DTADDRESS_WRAP); diff --git a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWaterTracks.cpp b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWaterTracks.cpp index c5cb7e41686..5c60664aaee 100644 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWaterTracks.cpp +++ b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWaterTracks.cpp @@ -45,7 +45,10 @@ #include "W3DDevice/GameClient/HeightMap.h" #include "W3DDevice/GameClient/W3DWaterTracks.h" +#include "W3DDevice/GameClient/W3DShaderManager.h" +#include "W3DDevice/GameClient/W3DShroud.h" #include "GameClient/InGameUI.h" +#include "GameClient/Water.h" #include "GameLogic/TerrainLogic.h" #include "Common/FramePacer.h" #include "Common/GlobalData.h" @@ -851,6 +854,9 @@ Try improving the fit to vertical surfaces like cliffs. */ Int diffuseLight; + if (!TheGlobalData->m_showSoftWaterEdge || TheWaterTransparency->m_transparentWaterDepth ==0 ) + return; + if (TheGlobalData->m_usingWaterTrackEditor) TestWaterUpdate(); @@ -887,6 +893,24 @@ Try improving the fit to vertical surfaces like cliffs. DX8Wrapper::Set_Vertex_Buffer(m_vertexBuffer); DX8Wrapper::Set_DX8_Render_State(D3DRS_ZBIAS,8); + //Force apply of render states so we can override them. + DX8Wrapper::Apply_Render_State_Changes(); + + if (TheTerrainRenderObject->getShroud()) + { + W3DShaderManager::setTexture(0,TheTerrainRenderObject->getShroud()->getShroudTexture()); + W3DShaderManager::setShader(W3DShaderManager::ST_SHROUD_TEXTURE, 1); + + //modulate with shroud texture + DX8Wrapper::Set_DX8_Texture_Stage_State( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE ); //stage 1 texture + DX8Wrapper::Set_DX8_Texture_Stage_State( 1, D3DTSS_COLORARG2, D3DTA_CURRENT ); //previous stage texture + DX8Wrapper::Set_DX8_Texture_Stage_State( 1, D3DTSS_COLOROP, D3DTOP_MODULATE ); + DX8Wrapper::Set_DX8_Texture_Stage_State( 1, D3DTSS_ALPHAOP, D3DTOP_MODULATE ); + + //Shroud shader uses z-compare of EQUAL which wouldn't work on water because it doesn't + //write to the zbuffer. Change to LESSEQUAL. + DX8Wrapper::Set_DX8_Render_State(D3DRS_ZFUNC, D3DCMP_LESSEQUAL); + } Int LastTextureType=-1; @@ -905,6 +929,12 @@ Try improving the fit to vertical surfaces like cliffs. } DX8Wrapper::Set_DX8_Render_State(D3DRS_ZBIAS,0); + + if (TheTerrainRenderObject->getShroud()) + { //we used the shroud shader, so reset it. + DX8Wrapper::Set_DX8_Render_State(D3DRS_ZFUNC, D3DCMP_EQUAL); + W3DShaderManager::resetShader(W3DShaderManager::ST_SHROUD_TEXTURE); + } } WaterTracksObj *WaterTracksRenderSystem::findTrack(Vector2 &start, Vector2 &end, waveType type) diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/assetmgr.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/assetmgr.cpp index 40931555aa9..2afb91369db 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/assetmgr.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/assetmgr.cpp @@ -16,7 +16,7 @@ ** along with this program. If not, see . */ -/* $Header: /Commando/Code/ww3d2/assetmgr.cpp 36 8/24/01 3:23p Jani_p $ */ +/* $Header: /Commando/Code/ww3d2/assetmgr.cpp 43 11/01/01 1:11a Jani_p $ */ /*********************************************************************************************** *** Confidential - Westwood Studios *** *********************************************************************************************** @@ -25,12 +25,16 @@ * * * $Archive:: /Commando/Code/ww3d2/assetmgr.cpp $* * * - * Author:: Greg_h * + * Org Author:: Greg_h * * * - * $Modtime:: 8/22/01 6:54p $* + * Author : Kenny Mitchell * * * - * $Revision:: 36 $* + * $Modtime:: 08/05/02 10:14a $* * * + * $Revision:: 46 $* + * * + * 06/27/02 KM Texture class abstraction * + * 08/05/02 KM Texture class redesign (revisited) *---------------------------------------------------------------------------------------------* * Functions: * * WW3DAssetManager::WW3DAssetManager -- Constructor * @@ -1040,46 +1044,6 @@ HTreeClass * WW3DAssetManager::Get_HTree(const char * name) return htree; } -/*********************************************************************************************** - * WW3DAssetManager::Get_Bumpmap_Based_On_Texture -- Generate a bumpmap from texture. The * - * resulting texture is stored to the hash table so that any further requests will share it. * - * * - * INPUT: * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 1/31/2001 NH : Created. * - *=============================================================================================*/ - -TextureClass* WW3DAssetManager::Get_Bumpmap_Based_On_Texture(TextureClass* texture) -{ - WWASSERT(texture->Get_Texture_Name() && strlen(texture->Get_Texture_Name())); - StringClass bump_name="__Bumpmap-"; - bump_name+=texture->Get_Texture_Name(); - _strlwr(bump_name.Peek_Buffer()); // lower case - - /* - ** See if the texture has already been generated. - */ - - TextureClass* tex = TextureHash.Get(bump_name); - - /* - ** Didn't have it so we have to create a new texture - */ - if (!tex) { - tex = NEW_REF(BumpmapTextureClass,(texture)); - tex->Set_Texture_Name(bump_name); - TextureHash.Insert(tex->Get_Texture_Name(),tex); - } - - tex->Add_Ref(); - return tex; -} - /*********************************************************************************************** * WW3DAssetManager::Get_Texture -- get a TextureClass from the specified file * * * @@ -1127,7 +1091,7 @@ TextureClass * WW3DAssetManager::Get_Texture ** See if the texture has already been loaded. */ TextureClass* tex = TextureHash.Get(lower_case_name); - if (tex && texture_format!=WW3D_FORMAT_UNKNOWN) + if (tex && (tex->Is_Initialized() == true) && (texture_format!=WW3D_FORMAT_UNKNOWN)) { WWASSERT_PRINT(tex->Get_Texture_Format()==texture_format,("Texture %s has already been loaded with different format",filename)); } @@ -1139,7 +1103,15 @@ TextureClass * WW3DAssetManager::Get_Texture { if (type==TextureBaseClass::TEX_REGULAR) { - tex = NEW_REF (TextureClass, (lower_case_name, NULL, mip_level_count, texture_format, allow_compression)); + tex = NEW_REF (TextureClass, (lower_case_name, NULL, mip_level_count, texture_format, allow_compression, allow_reduction)); + } + else if (type==TextureBaseClass::TEX_CUBEMAP) + { + tex = NEW_REF (CubeTextureClass, (lower_case_name, NULL, mip_level_count, texture_format, allow_compression, allow_reduction)); + } + else if (type==TextureBaseClass::TEX_VOLUME) + { + tex = NEW_REF (VolumeTextureClass, (lower_case_name, NULL, mip_level_count, texture_format, allow_compression, allow_reduction)); } else { diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/assetmgr.h b/Generals/Code/Libraries/Source/WWVegas/WW3D2/assetmgr.h index c68dd00020d..f3f1ca83f79 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/assetmgr.h +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/assetmgr.h @@ -269,7 +269,6 @@ class WW3DAssetManager TextureBaseClass::TexAssetType type=TextureBaseClass::TEX_REGULAR, bool allow_reduction=true ); - TextureClass* Get_Bumpmap_Based_On_Texture(TextureClass* texture); virtual void Release_All_Textures(void); virtual void Release_Unused_Textures(void); diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/bmp2d.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/bmp2d.cpp index 0f72cdd87c9..8f0ba147a09 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/bmp2d.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/bmp2d.cpp @@ -24,12 +24,15 @@ * * * $Archive:: /Commando/Code/ww3d2/bmp2d.cpp $* * * - * $Author:: Naty_h $* + * $Org Author:: Jani_p $* * * - * $Modtime:: 4/13/01 1:37p $* + * $Author:: Kenny_m $* * * - * $Revision:: 10 $* + * $Modtime:: 08/05/02 10:44a $* * * + * $Revision:: 12 $* + * * + * 08/05/02 KM Texture class redesign *-------------------------------------------------------------------------* * Functions: * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -39,6 +42,9 @@ #include "ww3d.h" #include "texture.h" #include "surfaceclass.h" +#include "assetmgr.h" +#include "textureloader.h" +#include "ww3dformat.h" Bitmap2DObjClass::Bitmap2DObjClass ( @@ -67,7 +73,15 @@ Bitmap2DObjClass::Bitmap2DObjClass // load up the surfaces file name - SurfaceClass *surface=NEW_REF(SurfaceClass,(filename)); + TextureClass *tex = WW3DAssetManager::Get_Instance()->Get_Texture(filename, MIP_LEVELS_1); + if (!tex->Is_Initialized()) + TextureLoader::Request_Foreground_Loading(tex); + + SurfaceClass *surface = tex->Get_Surface_Level(0); + + if (!surface) { + surface = NEW_REF(SurfaceClass, (32, 32, Get_Valid_Texture_Format(WW3D_FORMAT_R8G8B8,true))); + } SurfaceClass::SurfaceDescription sd; surface->Get_Description(sd); @@ -185,6 +199,7 @@ Bitmap2DObjClass::Bitmap2DObjClass REF_PTR_RELEASE(piece_texture); } } + REF_PTR_RELEASE(tex); REF_PTR_RELEASE(surface); Set_Dirty(); @@ -216,6 +231,9 @@ Bitmap2DObjClass::Bitmap2DObjClass // SurfaceClass::SurfaceDescription sd; // texture->Get_Level_Description(sd); + if (!texture->Is_Initialized()) + TextureLoader::Request_Foreground_Loading(texture); + // convert image width and image height to normalized values float vw = (float) texture->Get_Width() / (float)resw; float vh = (float) texture->Get_Height() / (float)resh; diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8caps.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8caps.cpp index 7dd3dc6638b..38477273fe3 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8caps.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8caps.cpp @@ -539,6 +539,8 @@ void DX8Caps::Compute_Caps(WW3DFormat display_format, const D3DADAPTER_IDENTIFIE MaxTexturesPerPass=MAX_TEXTURE_STAGES; Check_Texture_Format_Support(display_format,caps); + Check_Render_To_Texture_Support(display_format,caps); + Check_Depth_Stencil_Support(display_format,caps); Check_Texture_Compression_Support(caps); Check_Bumpmap_Support(caps); Check_Shader_Support(caps); diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8texman.h b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8texman.h index f97ab5fb7fb..bc188322071 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8texman.h +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8texman.h @@ -26,12 +26,13 @@ * * * Original Author:: Hector Yee * * * - * $Author:: Jani_p $* + * Author : Kenny Mitchell * * * - * $Modtime:: 7/26/01 5:12p $* + * $Modtime:: 06/27/02 1:27p $* * * - * $Revision:: 3 $* + * $Revision:: 4 $* * * + * 06/27/02 KM Texture class abstraction * *---------------------------------------------------------------------------------------------* * Functions: * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -120,6 +121,43 @@ class DX8TextureTrackerClass : public TextureTrackerClass bool RenderTarget; }; +class DX8ZTextureTrackerClass : public TextureTrackerClass +{ +public: + DX8ZTextureTrackerClass + ( + unsigned int w, + unsigned int h, + WW3DZFormat zformat, + MipCountType count, + TextureBaseClass* tex + ) + : TextureTrackerClass(w,h,count,tex), ZFormat(zformat) + { + } + + virtual void Recreate() const + { + WWASSERT(Texture->Peek_D3D_Base_Texture()==NULL); + Texture->Poke_Texture + ( + DX8Wrapper::_Create_DX8_ZTexture + ( + Width, + Height, + ZFormat, + Mip_level_count, + D3DPOOL_DEFAULT + ) + ); + } + + +private: + WW3DZFormat ZFormat; +}; + + class DX8TextureManagerClass { public: diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 44b7056ff36..b6696957880 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -32,6 +32,7 @@ * * * $Revision:: 134 $* * * + * 08/05/02 KM Texture class redesign *---------------------------------------------------------------------------------------------* * Functions: * * DX8Wrapper::_Update_Texture -- Copies a texture from system memory to video memory * @@ -125,8 +126,11 @@ LightEnvironmentClass* DX8Wrapper::Light_Environment = NULL; RenderInfoClass* DX8Wrapper::Render_Info = NULL; DWORD DX8Wrapper::Vertex_Processing_Behavior = 0; +ZTextureClass* DX8Wrapper::Shadow_Map[MAX_SHADOW_MAPS]; + Vector3 DX8Wrapper::Ambient_Color; // shader system additions KJM ^ + bool DX8Wrapper::world_identity; unsigned DX8Wrapper::RenderStates[256]; unsigned DX8Wrapper::TextureStageStates[MAX_TEXTURE_STAGES][32]; @@ -140,7 +144,9 @@ D3DCOLOR DX8Wrapper::FogColor = 0; IDirect3D8 * DX8Wrapper::D3DInterface = NULL; IDirect3DDevice8 * DX8Wrapper::D3DDevice = NULL; IDirect3DSurface8 * DX8Wrapper::CurrentRenderTarget = NULL; +IDirect3DSurface8 * DX8Wrapper::CurrentDepthBuffer = NULL; IDirect3DSurface8 * DX8Wrapper::DefaultRenderTarget = NULL; +IDirect3DSurface8 * DX8Wrapper::DefaultDepthBuffer = NULL; bool DX8Wrapper::IsRenderToTexture = false; unsigned DX8Wrapper::matrix_changes = 0; @@ -268,6 +274,7 @@ bool DX8Wrapper::Init(void * hwnd, bool lite) memset(Vertex_Shader_Constants,0,sizeof(Vector4)*MAX_VERTEX_SHADER_CONSTANTS); memset(Pixel_Shader_Constants,0,sizeof(Vector4)*MAX_PIXEL_SHADER_CONSTANTS); memset(&render_state,0,sizeof(RenderStateStruct)); + memset(Shadow_Map,0,sizeof(ZTextureClass*)*MAX_SHADOW_MAPS); /* ** Initialize all variables! @@ -396,7 +403,7 @@ void DX8Wrapper::Do_Onetime_Device_Dependent_Inits(void) ** Initalize any other subsystems inside of WW3D */ MissingTexture::_Init(); - TextureFilterClass::_Init_Filters(); + TextureFilterClass::_Init_Filters((TextureFilterClass::TextureFilterMode)WW3D::Get_Texture_Filter()); TheDX8MeshRenderer.Init(); BoxRenderObjClass::Init(); VertexMaterialClass::Init(); @@ -603,6 +610,8 @@ bool DX8Wrapper::Reset_Device(bool reload_assets) DX8_THREAD_ASSERT(); if ((IsInitted) && (D3DDevice != NULL)) { // Release all non-MANAGED stuff + WW3D::_Invalidate_Textures(); + Set_Vertex_Buffer (NULL); Set_Index_Buffer (NULL, 0); if (m_pCleanupHook) { @@ -2378,6 +2387,305 @@ IDirect3DTexture8 * DX8Wrapper::_Create_DX8_Texture } +/*! + * KJM create depth stencil texture + */ +IDirect3DTexture8 * DX8Wrapper::_Create_DX8_ZTexture +( + unsigned int width, + unsigned int height, + WW3DZFormat zformat, + MipCountType mip_level_count, + D3DPOOL pool +) +{ + DX8_THREAD_ASSERT(); + DX8_Assert(); + IDirect3DTexture8* texture = NULL; + + D3DFORMAT zfmt=WW3DZFormat_To_D3DFormat(zformat); + + unsigned ret=DX8Wrapper::_Get_D3D_Device8()->CreateTexture + ( + width, + height, + mip_level_count, + D3DUSAGE_DEPTHSTENCIL, + zfmt, + pool, + &texture + ); + + if (ret==D3DERR_NOTAVAILABLE) + { + Non_Fatal_Log_DX8_ErrorCode(ret,__FILE__,__LINE__); + return NULL; + } + + // If ran out of texture ram, try invalidating some textures and mesh cache. + if (ret==D3DERR_OUTOFVIDEOMEMORY) + { + WWDEBUG_SAY(("Error: Out of memory while creating render target. Trying to release assets...")); + // Free all textures that haven't been used in the last 5 seconds + TextureClass::Invalidate_Old_Unused_Textures(5000); + + // Invalidate the mesh cache + WW3D::_Invalidate_Mesh_Cache(); + + ret=DX8Wrapper::_Get_D3D_Device8()->CreateTexture + ( + width, + height, + mip_level_count, + D3DUSAGE_DEPTHSTENCIL, + zfmt, + pool, + &texture + ); + + if (SUCCEEDED(ret)) + { + WWDEBUG_SAY(("...Render target creation succesful.")); + } + else + { + WWDEBUG_SAY(("...Render target creation failed.")); + } + if (ret==D3DERR_OUTOFVIDEOMEMORY) + { + Non_Fatal_Log_DX8_ErrorCode(ret,__FILE__,__LINE__); + return NULL; + } + } + + DX8_ErrorCode(ret); + + texture->AddRef(); // don't release this texture + + // Just return the texture, no reduction + // allowed for render targets. + + return texture; +} + +/*! + * KJM create cube map texture + */ +IDirect3DCubeTexture8* DX8Wrapper::_Create_DX8_Cube_Texture +( + unsigned int width, + unsigned int height, + WW3DFormat format, + MipCountType mip_level_count, + D3DPOOL pool, + bool rendertarget +) +{ + WWASSERT(width==height); + DX8_THREAD_ASSERT(); + DX8_Assert(); + IDirect3DCubeTexture8* texture=NULL; + + // Paletted textures not supported! + WWASSERT(format!=D3DFMT_P8); + + // NOTE: If 'format' is not supported as a texture format, this function will find the closest + // format that is supported and use that instead. + + // Render target may return NOTAVAILABLE, in + // which case we return NULL. + if (rendertarget) + { + unsigned ret=D3DXCreateCubeTexture + ( + DX8Wrapper::_Get_D3D_Device8(), + width, + mip_level_count, + D3DUSAGE_RENDERTARGET, + WW3DFormat_To_D3DFormat(format), + pool, + &texture + ); + + if (ret==D3DERR_NOTAVAILABLE) + { + Non_Fatal_Log_DX8_ErrorCode(ret,__FILE__,__LINE__); + return NULL; + } + + // If ran out of texture ram, try invalidating some textures and mesh cache. + if (ret==D3DERR_OUTOFVIDEOMEMORY) + { + WWDEBUG_SAY(("Error: Out of memory while creating render target. Trying to release assets...")); + // Free all textures that haven't been used in the last 5 seconds + TextureClass::Invalidate_Old_Unused_Textures(5000); + + // Invalidate the mesh cache + WW3D::_Invalidate_Mesh_Cache(); + + ret=D3DXCreateCubeTexture + ( + DX8Wrapper::_Get_D3D_Device8(), + width, + mip_level_count, + D3DUSAGE_RENDERTARGET, + WW3DFormat_To_D3DFormat(format), + pool, + &texture + ); + + if (SUCCEEDED(ret)) + { + WWDEBUG_SAY(("...Render target creation succesful.")); + } + else + { + WWDEBUG_SAY(("...Render target creation failed.")); + } + if (ret==D3DERR_OUTOFVIDEOMEMORY) + { + Non_Fatal_Log_DX8_ErrorCode(ret,__FILE__,__LINE__); + return NULL; + } + } + + DX8_ErrorCode(ret); + // Just return the texture, no reduction + // allowed for render targets. + return texture; + } + + // We should never run out of video memory when allocating a non-rendertarget texture. + // However, it seems to happen sometimes when there are a lot of textures in memory and so + // if it happens we'll release assets and try again (anything is better than crashing). + unsigned ret=D3DXCreateCubeTexture + ( + DX8Wrapper::_Get_D3D_Device8(), + width, + mip_level_count, + 0, + WW3DFormat_To_D3DFormat(format), + pool, + &texture + ); + + // If ran out of texture ram, try invalidating some textures and mesh cache. + if (ret==D3DERR_OUTOFVIDEOMEMORY) + { + WWDEBUG_SAY(("Error: Out of memory while creating texture. Trying to release assets...")); + // Free all textures that haven't been used in the last 5 seconds + TextureClass::Invalidate_Old_Unused_Textures(5000); + + // Invalidate the mesh cache + WW3D::_Invalidate_Mesh_Cache(); + + ret=D3DXCreateCubeTexture + ( + DX8Wrapper::_Get_D3D_Device8(), + width, + mip_level_count, + 0, + WW3DFormat_To_D3DFormat(format), + pool, + &texture + ); + if (SUCCEEDED(ret)) + { + WWDEBUG_SAY(("...Texture creation succesful.")); + } + else + { + StringClass format_name(0,true); + Get_WW3D_Format_Name(format, format_name); + WWDEBUG_SAY(("...Texture creation failed. (%d x %d, format: %s, mips: %d",width,height,format_name.str(),mip_level_count)); + } + + } + DX8_ErrorCode(ret); + + return texture; +} + +/*! + * KJM create volume texture + */ +IDirect3DVolumeTexture8* DX8Wrapper::_Create_DX8_Volume_Texture +( + unsigned int width, + unsigned int height, + unsigned int depth, + WW3DFormat format, + MipCountType mip_level_count, + D3DPOOL pool +) +{ + DX8_THREAD_ASSERT(); + DX8_Assert(); + IDirect3DVolumeTexture8* texture=NULL; + + // Paletted textures not supported! + WWASSERT(format!=D3DFMT_P8); + + // NOTE: If 'format' is not supported as a texture format, this function will find the closest + // format that is supported and use that instead. + + + // We should never run out of video memory when allocating a non-rendertarget texture. + // However, it seems to happen sometimes when there are a lot of textures in memory and so + // if it happens we'll release assets and try again (anything is better than crashing). + unsigned ret=D3DXCreateVolumeTexture + ( + DX8Wrapper::_Get_D3D_Device8(), + width, + height, + depth, + mip_level_count, + 0, + WW3DFormat_To_D3DFormat(format), + pool, + &texture + ); + + // If ran out of texture ram, try invalidating some textures and mesh cache. + if (ret==D3DERR_OUTOFVIDEOMEMORY) + { + WWDEBUG_SAY(("Error: Out of memory while creating texture. Trying to release assets...")); + // Free all textures that haven't been used in the last 5 seconds + TextureClass::Invalidate_Old_Unused_Textures(5000); + + // Invalidate the mesh cache + WW3D::_Invalidate_Mesh_Cache(); + + ret=D3DXCreateVolumeTexture + ( + DX8Wrapper::_Get_D3D_Device8(), + width, + height, + depth, + mip_level_count, + 0, + WW3DFormat_To_D3DFormat(format), + pool, + &texture + ); + if (SUCCEEDED(ret)) + { + WWDEBUG_SAY(("...Texture creation succesful.")); + } + else + { + StringClass format_name(0,true); + Get_WW3D_Format_Name(format, format_name); + WWDEBUG_SAY(("...Texture creation failed. (%d x %d, format: %s, mips: %d",width,height,format_name.str(),mip_level_count)); + } + + } + DX8_ErrorCode(ret); + + return texture; +} + + IDirect3DSurface8 * DX8Wrapper::_Create_DX8_Surface(unsigned int width, unsigned int height, WW3DFormat format) { DX8_THREAD_ASSERT(); @@ -2660,10 +2968,24 @@ SurfaceClass * DX8Wrapper::_Get_DX8_Back_Buffer(unsigned int num) TextureClass * -DX8Wrapper::Create_Render_Target (int width, int height, bool alpha) +DX8Wrapper::Create_Render_Target (int width, int height, WW3DFormat format) { DX8_THREAD_ASSERT(); DX8_Assert(); + number_of_DX8_calls++; + + // Use the current display format if format isn't specified + if (format==WW3D_FORMAT_UNKNOWN) { + D3DDISPLAYMODE mode; + DX8CALL(GetDisplayMode(&mode)); + format=D3DFormat_To_WW3DFormat(mode.Format); + } + + // If render target format isn't supported return NULL + if (!Get_Current_Caps()->Support_Render_To_Texture_Format(format)) { + WWDEBUG_SAY(("DX8Wrapper - Render target format is not supported")); + return NULL; + } // // Note: We're going to force the width and height to be powers of two and equal @@ -2685,49 +3007,81 @@ DX8Wrapper::Create_Render_Target (int width, int height, bool alpha) width = height = poweroftwosize; // - // Get the current format of the display + // Attempt to create the render target // - D3DDISPLAYMODE mode; - DX8CALL(GetDisplayMode(&mode)); + TextureClass * tex = NEW_REF(TextureClass,(width,height,format,MIP_LEVELS_1,TextureClass::POOL_DEFAULT,true)); + + // 3dfx drivers are lying in the CheckDeviceFormat call and claiming + // that they support render targets! + if (tex->Peek_D3D_Base_Texture() == NULL) + { + WWDEBUG_SAY(("DX8Wrapper - Render target creation failed!")); + REF_PTR_RELEASE(tex); + } + + return tex; +} + +//********************************************************************************************** +//! Create render target with associated depth stencil buffer +/*! KJM +*/ +void DX8Wrapper::Create_Render_Target +( + int width, + int height, + WW3DFormat format, + WW3DZFormat zformat, + TextureClass** target, + ZTextureClass** depth_buffer +) +{ + DX8_THREAD_ASSERT(); + DX8_Assert(); + number_of_DX8_calls++; - // If the user requested a render-target texture and this device does not support that - // feature, return NULL - HRESULT hr; + // Use the current display format if format isn't specified + if (format==WW3D_FORMAT_UNKNOWN) + { + *target=NULL; + *depth_buffer=NULL; + return; +/* D3DDISPLAYMODE mode; + DX8CALL(GetDisplayMode(&mode)); + format=D3DFormat_To_WW3DFormat(mode.Format);*/ + } - if (alpha) + // If render target format isn't supported return NULL + if (!Get_Current_Caps()->Support_Render_To_Texture_Format(format) || + !Get_Current_Caps()->Support_Depth_Stencil_Format(zformat)) { - //user wants a texture with destination alpha channel - only 1 such format - //ever exists on current hardware - D3DFMT_A8R8G8B8 - hr = D3DInterface->CheckDeviceFormat( D3DADAPTER_DEFAULT, - WW3D_DEVTYPE, - mode.Format, - D3DUSAGE_RENDERTARGET, - D3DRTYPE_TEXTURE, - D3DFMT_A8R8G8B8 ); - mode.Format=D3DFMT_A8R8G8B8; + WWDEBUG_SAY(("DX8Wrapper - Render target with depth format is not supported")); + return; } - else + + // Note: We're going to force the width and height to be powers of two and equal + const D3DCAPS8& dx8caps=Get_Current_Caps()->Get_DX8_Caps(); + float poweroftwosize = width; + if (height > 0 && height < width) { - hr = D3DInterface->CheckDeviceFormat( D3DADAPTER_DEFAULT, - WW3D_DEVTYPE, - mode.Format, - D3DUSAGE_RENDERTARGET, - D3DRTYPE_TEXTURE, - mode.Format ); + poweroftwosize = height; } + poweroftwosize = ::Find_POT (poweroftwosize); - number_of_DX8_calls++; - if (hr != D3D_OK) { - WWDEBUG_SAY(("DX8Wrapper - Driver cannot create render target!")); - return NULL; + if (poweroftwosize>dx8caps.MaxTextureWidth) + { + poweroftwosize=dx8caps.MaxTextureWidth; } - // + if (poweroftwosize>dx8caps.MaxTextureHeight) + { + poweroftwosize=dx8caps.MaxTextureHeight; + } + + width = height = poweroftwosize; + // Attempt to create the render target - // - DX8_Assert(); - WW3DFormat format=D3DFormat_To_WW3DFormat(mode.Format); - TextureClass * tex = NEW_REF(TextureClass,(width,height,format,MIP_LEVELS_1,TextureClass::POOL_DEFAULT,true)); + TextureClass* tex=NEW_REF(TextureClass,(width,height,format,MIP_LEVELS_1,TextureClass::POOL_DEFAULT,true)); // 3dfx drivers are lying in the CheckDeviceFormat call and claiming // that they support render targets! @@ -2737,19 +3091,52 @@ DX8Wrapper::Create_Render_Target (int width, int height, bool alpha) REF_PTR_RELEASE(tex); } - return tex; -} + *target=tex; + // attempt to create the depth stencil buffer + *depth_buffer=NEW_REF + ( + ZTextureClass, + ( + width, + height, + zformat, + MIP_LEVELS_1, + TextureClass::POOL_DEFAULT + ) + ); +} -void -DX8Wrapper::Set_Render_Target -(TextureClass * texture) +/*! + * Set render target + * KM Added optional custom z target + */ +void DX8Wrapper::Set_Render_Target_With_Z +( + TextureClass* texture, + ZTextureClass* ztexture +) { - WWASSERT(texture != NULL); - SurfaceClass * surf = texture->Get_Surface_Level(); - WWASSERT(surf != NULL); - Set_Render_Target(surf->Peek_D3D_Surface()); - REF_PTR_RELEASE(surf); + WWASSERT(texture!=NULL); + IDirect3DSurface8 * d3d_surf = texture->Get_D3D_Surface_Level(); + WWASSERT(d3d_surf != NULL); + + IDirect3DSurface8* d3d_zbuf=NULL; + if (ztexture!=NULL) + { + + d3d_zbuf=ztexture->Get_D3D_Surface_Level(); + WWASSERT(d3d_zbuf!=NULL); + Set_Render_Target(d3d_surf,d3d_zbuf); + d3d_zbuf->Release(); + } + else + { + Set_Render_Target(d3d_surf,true); + } + d3d_surf->Release(); + + IsRenderToTexture = true; } void @@ -2767,7 +3154,7 @@ DX8Wrapper::Set_Render_Target(IDirect3DSwapChain8 *swap_chain) // // Set this back buffer as the render targer // - Set_Render_Target (render_target); + Set_Render_Target (render_target, true); // // Release our hold on the back buffer @@ -2783,31 +3170,36 @@ DX8Wrapper::Set_Render_Target(IDirect3DSwapChain8 *swap_chain) } void -DX8Wrapper::Set_Render_Target(IDirect3DSurface8 *render_target) +DX8Wrapper::Set_Render_Target(IDirect3DSurface8 *render_target, bool use_default_depth_buffer) { +//#ifndef _XBOX DX8_THREAD_ASSERT(); DX8_Assert(); - // - // We'll need the depth buffer later... - // - IDirect3DSurface8 *depth_buffer = NULL; - DX8CALL(GetDepthStencilSurface (&depth_buffer)); - // // Should we restore the default render target set a new one? // if (render_target == NULL || render_target == DefaultRenderTarget) { + // If there is currently a custom render target, default must NOT be NULL. + if (CurrentRenderTarget) + { + WWASSERT(DefaultRenderTarget!=NULL); + } // // Restore the default render target // if (DefaultRenderTarget != NULL) { - DX8CALL(SetRenderTarget (DefaultRenderTarget, depth_buffer)); + DX8CALL(SetRenderTarget (DefaultRenderTarget, DefaultDepthBuffer)); DefaultRenderTarget->Release (); DefaultRenderTarget = NULL; + if (DefaultDepthBuffer) + { + DefaultDepthBuffer->Release (); + DefaultDepthBuffer = NULL; + } } // @@ -2819,9 +3211,25 @@ DX8Wrapper::Set_Render_Target(IDirect3DSurface8 *render_target) CurrentRenderTarget = NULL; } + if (CurrentDepthBuffer!=NULL) + { + CurrentDepthBuffer->Release(); + CurrentDepthBuffer=NULL; + } + } else if (render_target != CurrentRenderTarget) { + WWASSERT(DefaultRenderTarget==NULL); + + // + // We'll need the depth buffer later... + // + if (DefaultDepthBuffer == NULL) + { +// IDirect3DSurface8 *depth_buffer = NULL; + DX8CALL(GetDepthStencilSurface (&DefaultDepthBuffer)); + } // // Get a pointer to the default render target (if necessary) @@ -2840,6 +3248,12 @@ DX8Wrapper::Set_Render_Target(IDirect3DSurface8 *render_target) CurrentRenderTarget = NULL; } + if (CurrentDepthBuffer!=NULL) + { + CurrentDepthBuffer->Release(); + CurrentDepthBuffer=NULL; + } + // // Keep a copy of the current render target (for housekeeping) // @@ -2852,20 +3266,142 @@ DX8Wrapper::Set_Render_Target(IDirect3DSurface8 *render_target) // // Switch render targets // - DX8CALL(SetRenderTarget (CurrentRenderTarget, depth_buffer)); + if (use_default_depth_buffer) + { + DX8CALL(SetRenderTarget (CurrentRenderTarget, DefaultDepthBuffer)); + } + else + { + DX8CALL(SetRenderTarget (CurrentRenderTarget, NULL)); + } } } // // Free our hold on the depth buffer // - if (depth_buffer != NULL) { - depth_buffer->Release (); - depth_buffer = NULL; - } +// if (depth_buffer != NULL) { +// depth_buffer->Release (); +// depth_buffer = NULL; +// } IsRenderToTexture = false; return ; +//#endif // XBOX +} + + +//********************************************************************************************** +//! Set render target with depth stencil buffer +/*! KJM +*/ +void DX8Wrapper::Set_Render_Target +( + IDirect3DSurface8* render_target, + IDirect3DSurface8* depth_buffer +) +{ +//#ifndef _XBOX + DX8_THREAD_ASSERT(); + DX8_Assert(); + + // + // Should we restore the default render target set a new one? + // + if (render_target == NULL || render_target == DefaultRenderTarget) + { + // If there is currently a custom render target, default must NOT be NULL. + if (CurrentRenderTarget) + { + WWASSERT(DefaultRenderTarget!=NULL); + } + + // + // Restore the default render target + // + if (DefaultRenderTarget != NULL) + { + DX8CALL(SetRenderTarget (DefaultRenderTarget, DefaultDepthBuffer)); + DefaultRenderTarget->Release (); + DefaultRenderTarget = NULL; + if (DefaultDepthBuffer) + { + DefaultDepthBuffer->Release (); + DefaultDepthBuffer = NULL; + } + } + + // + // Release our hold on the "current" render target + // + if (CurrentRenderTarget != NULL) + { + CurrentRenderTarget->Release (); + CurrentRenderTarget = NULL; + } + + if (CurrentDepthBuffer!=NULL) + { + CurrentDepthBuffer->Release(); + CurrentDepthBuffer=NULL; + } + } + else if (render_target != CurrentRenderTarget) + { + WWASSERT(DefaultRenderTarget==NULL); + + // + // We'll need the depth buffer later... + // + if (DefaultDepthBuffer == NULL) + { +// IDirect3DSurface8 *depth_buffer = NULL; + DX8CALL(GetDepthStencilSurface (&DefaultDepthBuffer)); + } + + // + // Get a pointer to the default render target (if necessary) + // + if (DefaultRenderTarget == NULL) + { + DX8CALL(GetRenderTarget (&DefaultRenderTarget)); + } + + // + // Release our hold on the old "current" render target + // + if (CurrentRenderTarget != NULL) + { + CurrentRenderTarget->Release (); + CurrentRenderTarget = NULL; + } + + if (CurrentDepthBuffer!=NULL) + { + CurrentDepthBuffer->Release(); + CurrentDepthBuffer=NULL; + } + + // + // Keep a copy of the current render target (for housekeeping) + // + CurrentRenderTarget = render_target; + CurrentDepthBuffer = depth_buffer; + WWASSERT (CurrentRenderTarget != NULL); + if (CurrentRenderTarget != NULL) + { + CurrentRenderTarget->AddRef (); + CurrentDepthBuffer->AddRef(); + + // + // Switch render targets + // + DX8CALL(SetRenderTarget (CurrentRenderTarget, CurrentDepthBuffer)); + } + } + + IsRenderToTexture=true; +//#endif // XBOX } diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h index c5404ad3ff7..f72ce2e13ee 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h @@ -349,6 +349,37 @@ class DX8Wrapper ** Resources */ + static IDirect3DVolumeTexture8* _Create_DX8_Volume_Texture + ( + unsigned int width, + unsigned int height, + unsigned int depth, + WW3DFormat format, + MipCountType mip_level_count, + D3DPOOL pool=D3DPOOL_MANAGED + ); + + static IDirect3DCubeTexture8* _Create_DX8_Cube_Texture + ( + unsigned int width, + unsigned int height, + WW3DFormat format, + MipCountType mip_level_count, + D3DPOOL pool=D3DPOOL_MANAGED, + bool rendertarget=false + ); + + + static IDirect3DTexture8* _Create_DX8_ZTexture + ( + unsigned int width, + unsigned int height, + WW3DZFormat zformat, + MipCountType mip_level_count, + D3DPOOL pool=D3DPOOL_MANAGED + ); + + static IDirect3DTexture8 * _Create_DX8_Texture ( unsigned int width, @@ -436,15 +467,32 @@ class DX8Wrapper static IDirect3DSwapChain8 * Create_Additional_Swap_Chain (HWND render_window); /* - ** Render target interface + ** Render target interface. If render target format is WW3D_FORMAT_UNKNOWN, current display format is used. */ - static TextureClass * Create_Render_Target (int width, int height, bool alpha=false); + static TextureClass * Create_Render_Target (int width, int height, WW3DFormat format = WW3D_FORMAT_UNKNOWN); + + static void Set_Render_Target (IDirect3DSurface8 *render_target, bool use_default_depth_buffer = false); + static void Set_Render_Target (IDirect3DSurface8* render_target, IDirect3DSurface8* dpeth_buffer); - static void Set_Render_Target (TextureBaseClass * texture); - static void Set_Render_Target (IDirect3DSurface8 *render_target); static void Set_Render_Target (IDirect3DSwapChain8 *swap_chain); static bool Is_Render_To_Texture(void) { return IsRenderToTexture; } + // for depth map support KJM V + static void Create_Render_Target + ( + int width, + int height, + WW3DFormat format, + WW3DZFormat zformat, + TextureClass** target, + ZTextureClass** depth_buffer + ); + static void Set_Render_Target_With_Z (TextureClass * texture, ZTextureClass* ztexture=NULL); + + static void Set_Shadow_Map(int idx, ZTextureClass* ztex) { Shadow_Map[idx]=ztex; } + static ZTextureClass* Get_Shadow_Map(int idx) { return Shadow_Map[idx]; } + // for depth map support KJM ^ + // shader system udpates KJM v static void Apply_Default_State(); @@ -597,6 +645,9 @@ class DX8Wrapper static RenderInfoClass* Render_Info; static DWORD Vertex_Processing_Behavior; + + static ZTextureClass* Shadow_Map[MAX_SHADOW_MAPS]; + static Vector3 Ambient_Color; // shader system updates KJM ^ @@ -631,7 +682,10 @@ class DX8Wrapper static IDirect3DDevice8 * D3DDevice; //d3ddevice8; static IDirect3DSurface8 * CurrentRenderTarget; + static IDirect3DSurface8 * CurrentDepthBuffer; static IDirect3DSurface8 * DefaultRenderTarget; + static IDirect3DSurface8 * DefaultDepthBuffer; + static unsigned DrawPolygonLowBoundLimit; static bool IsRenderToTexture; diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/texproject.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/texproject.cpp index 2e819962eb0..79ea6d9804b 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/texproject.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/texproject.cpp @@ -26,12 +26,15 @@ * * * Original Author:: Greg Hjelstrom * * * - * $Author:: Jani_p $* + * $Author:: Kenny Mitchell * * * - * $Modtime:: 7/23/01 5:31p $* + * $Modtime:: 08/05/02 10:03a $* * * - * $Revision:: 15 $* + * $Revision:: 22 $* * * + * 06/26/02 KM Matrix name change to avoid MAX conflicts * + * 06/27/02 KM Render to shadow buffer texture support * + * 08/05/02 KM Texture class redesign *---------------------------------------------------------------------------------------------* * Functions: * * TexProjectClass::TexProjectClass -- Constructor * @@ -88,7 +91,7 @@ #include "MPU.h" #define DEBUG_SHADOW_RENDERING 0 -#define DEFAULT_TEXTURE_SIZE 64 +//#define DEFAULT_TEXTURE_SIZE 64 const float INTENSITY_RATE_OF_CHANGE = 1.0f; // change in intensity per second @@ -186,6 +189,7 @@ TexProjectClass::TexProjectClass(void) : MaterialPass(NULL), Mapper1(NULL), RenderTarget(NULL), + DepthStencilTarget(NULL), HFov(90.0f), VFov(90.0f), XMin(-10.0f), @@ -195,9 +199,6 @@ TexProjectClass::TexProjectClass(void) : ZNear(1.0f), ZFar(1000.0f) { - // set a default texture size - Set_Texture_Size(DEFAULT_TEXTURE_SIZE); - // create a material pass class MaterialPass = NEW_REF(MaterialPassClass,()); MaterialPass->Set_Cull_Volume(&WorldBoundingVolume); @@ -236,6 +237,7 @@ TexProjectClass::~TexProjectClass(void) REF_PTR_RELEASE(Mapper1); REF_PTR_RELEASE(MaterialPass); REF_PTR_RELEASE(RenderTarget); + REF_PTR_RELEASE(DepthStencilTarget); } @@ -1108,6 +1110,7 @@ bool TexProjectClass::Compute_Ortho_Projection * * * HISTORY: * * 1/11/00 gth : Created. * + * 5/16/02 kjm : Added optional custom depth/stencil target * *=============================================================================================*/ bool TexProjectClass::Compute_Texture ( @@ -1122,15 +1125,20 @@ bool TexProjectClass::Compute_Texture /* ** Render to texture */ - TextureClass * rtarget = Peek_Render_Target(); + TextureClass * rtarget=NULL; + ZTextureClass* ztarget=NULL; + + Peek_Render_Target(&rtarget,&ztarget); if (rtarget != NULL) { + // set projector for render context KJM + context->Texture_Projector=this; /* ** Set the render target */ - DX8Wrapper::Set_Render_Target(rtarget); + DX8Wrapper::Set_Render_Target_With_Z (rtarget,ztarget); /* ** Set up the camera @@ -1145,9 +1153,15 @@ bool TexProjectClass::Compute_Texture color.Set(1.0f,1.0f,1.0f); } - WW3D::Begin_Render(true,true,color); + bool zclear=ztarget!=NULL; + + bool snapshot=WW3D::Is_Snapshot_Activated(); + SNAPSHOT_SAY(("TexProjectCLass::Begin_Render()")); + WW3D::Begin_Render(true,zclear,color); // false to zclear as we don't have z-buffer WW3D::Render(*model,*context); + SNAPSHOT_SAY(("TexProjectCLass::End_Render()")); WW3D::End_Render(false); + WW3D::Activate_Snapshot(snapshot); // End_Render() ends the shapsnot, so restore the state DX8Wrapper::Set_Render_Target((IDirect3DSurface8 *)NULL); @@ -1200,11 +1214,13 @@ bool TexProjectClass::Needs_Render_Target(void) *=============================================================================================*/ void TexProjectClass::Set_Render_Target ( - TextureClass* render_target + TextureClass* render_target, + ZTextureClass* zbuffer ) { REF_PTR_SET(RenderTarget,render_target); Set_Texture(RenderTarget); + REF_PTR_SET(DepthStencilTarget,zbuffer); } /*********************************************************************************************** @@ -1218,12 +1234,23 @@ void TexProjectClass::Set_Render_Target * * * HISTORY: * * 4/5/2001 gth : Created. * + * 5/16/2002 kjm : Added optional custom zbuffer * *=============================================================================================*/ TextureClass* TexProjectClass::Peek_Render_Target ( - void + TextureClass** rtarget, + ZTextureClass** ztarget ) { + // some uses of this function just want to know if a render target exists + if (rtarget==NULL) return RenderTarget; + + *rtarget=RenderTarget; + + // don't set if pointer isn't supplied + if (ztarget!=NULL) + *ztarget=DepthStencilTarget; + return RenderTarget; } @@ -1252,6 +1279,13 @@ void TexProjectClass::Configure_Camera(CameraClass & camera) camera.Set_Projection_Type(CameraClass::ORTHO); camera.Set_View_Plane(Vector2(XMin,YMin),Vector2(XMax,YMax)); } + + // Set one-pixel borders to the texture to avoid "flooding" shadows... + float size=Get_Texture_Size(); + float inv_size=1.0f/size; + Vector2 vmin(1.0f*inv_size,1.0f*inv_size); + Vector2 vmax((size-1.0f)*inv_size,(size-1.0f)*inv_size); + camera.Set_Viewport(vmin,vmax); } diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/texproject.h b/Generals/Code/Libraries/Source/WWVegas/WW3D2/texproject.h index 88ebc09e646..0ad5aa9efd7 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/texproject.h +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/texproject.h @@ -26,12 +26,13 @@ * * * Original Author:: Greg Hjelstrom * * * - * $Author:: Greg_h $* + * $Author:: Kenny Mitchell * * * - * $Modtime:: 4/23/01 7:29p $* + * $Modtime:: 06/26/02 4:04p $* * * - * $Revision:: 6 $* + * $Revision:: 8 $* * * + * 06/27/02 KM Render to shadow buffer texture support * *---------------------------------------------------------------------------------------------* * Functions: * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -54,6 +55,8 @@ class RenderObjClass; class MaterialPassClass; class SurfaceClass; +class TextureClass; +class ZTextureClass; /** @@ -139,6 +142,11 @@ class TexProjectClass : public ProjectorClass, public CullableClass, public Mult TextureClass * Get_Texture(void) const; TextureClass * Peek_Texture(void) const; + + void Set_DepthStencilBuffer(ZTextureClass* ztex); + ZTextureClass* Get_DepthStencilBuffer() const; + ZTextureClass* Peek_DepthStencilBuffer() const; + /* ** Automatic initialization of a TexProjectClass. ** First set up your projection parameters, give the projector a render target, then call Compute_Texture @@ -150,8 +158,8 @@ class TexProjectClass : public ProjectorClass, public CullableClass, public Mult bool Compute_Ortho_Projection(const AABoxClass & obj_box,const Matrix3D & tm,const Vector3 & lightdir,float znear=-1.0f,float zfar=-1.0f); bool Needs_Render_Target(void); - void Set_Render_Target(TextureClass * render_target); - TextureClass * Peek_Render_Target(void); + void Set_Render_Target(TextureClass* render_target, ZTextureClass* ztarget=NULL); + TextureClass* Peek_Render_Target(TextureClass** rtarget=NULL, ZTextureClass** ztarget=NULL); bool Compute_Texture(RenderObjClass * model,SpecialRenderInfoClass * context); @@ -190,7 +198,7 @@ class TexProjectClass : public ProjectorClass, public CullableClass, public Mult SIZE_MASK = 0xFFF00000, // desired texture size stored in upper 3 nibbles SIZE_SHIFT = 20, - DEFAULT_FLAGS = ATTENUATE | AFFECT_DYNAMIC_OBJS | AFFECT_STATIC_OBJS | (64<(texture)->Peek_D3D_Texture(); - if (!d3d_texture) return 0; - for (unsigned i=red_factor;iGetLevelCount();++i) { - D3DSURFACE_DESC desc; - DX8_ErrorCode(d3d_texture->GetLevelDesc(i,&desc)); - size+=desc.Size; - } - return size; -} +// This throttles submissions to the background texture loading queue. +static unsigned TexturesAppliedPerFrame; +const unsigned MAX_TEXTURES_APPLIED_PER_FRAME=2; -/************************************************************************* -** TextureClass -*************************************************************************/ -TextureClass::TextureClass(unsigned width, unsigned height, WW3DFormat format, MipCountType mip_level_count, PoolType pool,bool rendertarget) - : +/*! + * KM General base constructor for texture classes + */ +TextureBaseClass::TextureBaseClass +( + unsigned int width, + unsigned int height, + enum MipCountType mip_level_count, + enum PoolType pool, + bool rendertarget, + bool reducible +) +: MipLevelCount(mip_level_count), D3DTexture(NULL), + Initialized(false), + Name(""), + FullPath(""), texture_id(unused_texture_id++), - Initialized(true), - Filter(mip_level_count), - MipLevelCount(mip_level_count), - Pool(pool), - Dirty(false), IsLightmap(false), - IsProcedural(true), - Name(""), - TextureFormat(format), + IsProcedural(false), + IsReducible(reducible), IsCompressionAllowed(false), - TextureLoadTask(NULL), + InactivationTime(0), + ExtendedInactivationTime(0), + LastInactivationSyncTime(0), + LastAccessed(0), Width(width), - Height(height) + Height(height), + Pool(pool), + Dirty(false), + TextureLoadTask(NULL), + ThumbnailLoadTask(NULL), + HSVShift(0.0f,0.0f,0.0f) { - switch (format) - { - case WW3D_FORMAT_DXT1: - case WW3D_FORMAT_DXT2: - case WW3D_FORMAT_DXT3: - case WW3D_FORMAT_DXT4: - case WW3D_FORMAT_DXT5: - IsCompressionAllowed=true; - break; - default : break; - } +} - D3DPOOL d3dpool=(D3DPOOL)0; - switch(pool) - { - case POOL_DEFAULT : d3dpool=D3DPOOL_DEFAULT; break; - case POOL_MANAGED : d3dpool=D3DPOOL_MANAGED; break; - case POOL_SYSTEMMEM : d3dpool=D3DPOOL_SYSTEMMEM; break; - default: WWASSERT(0); - } - D3DTexture = DX8Wrapper::_Create_DX8_Texture(width, height, format, mip_level_count,d3dpool,rendertarget); - if (pool==POOL_DEFAULT) + +//********************************************************************************************** +//! Base texture class destructor +/*! KJM +*/ +TextureBaseClass::~TextureBaseClass(void) +{ + delete TextureLoadTask; + TextureLoadTask=NULL; + delete ThumbnailLoadTask; + ThumbnailLoadTask=NULL; + + if (D3DTexture) { - Dirty=true; - DX8TextureTrackerClass *track=W3DNEW DX8TextureTrackerClass - ( - width, - height, - format, - mip_level_count, - this, - rendertarget - ); - DX8TextureManagerClass::Add(track); + D3DTexture->Release(); + D3DTexture = NULL; } - LastAccessed=WW3D::Get_Sync_Time(); + + DX8TextureManagerClass::Remove(this); } -// ---------------------------------------------------------------------------- -TextureClass::TextureClass -( - const char *name, - const char *full_path, - MipCountType mip_level_count, - WW3DFormat texture_format, - bool allow_compression) - : - D3DTexture(NULL), - texture_id(unused_texture_id++), - Initialized(false), - Filter(mip_level_count), - MipLevelCount(mip_level_count), - Pool(POOL_MANAGED), - Dirty(false), - IsLightmap(false), - IsProcedural(false), - TextureFormat(texture_format), - IsCompressionAllowed(allow_compression), - TextureLoadTask(NULL), - Width(0), - Height(0) + + +//********************************************************************************************** +//! Invalidate old unused textures +/*! +*/ +void TextureBaseClass::Invalidate_Old_Unused_Textures(unsigned invalidation_time_override) { - switch (TextureFormat) - { - case WW3D_FORMAT_DXT1: - case WW3D_FORMAT_DXT2: - case WW3D_FORMAT_DXT3: - case WW3D_FORMAT_DXT4: - case WW3D_FORMAT_DXT5: - IsCompressionAllowed=true; - break; - case WW3D_FORMAT_U8V8: // Bumpmap - case WW3D_FORMAT_L6V5U5: // Bumpmap - case WW3D_FORMAT_X8L8V8U8: // Bumpmap - // If requesting bumpmap format that isn't available we'll just return the surface in whatever color - // format the texture file is in. (This is illegal case, the format support should always be queried - // before creating a bump texture!) - if (!DX8Wrapper::Get_Current_Caps()->Support_Texture_Format(TextureFormat)) - { - TextureFormat=WW3D_FORMAT_UNKNOWN; - } - // If bump format is valid, make sure compression is not allowed so that we don't even attempt to load - // from a compressed file (quality isn't good enough for bump map). Also disable mipmapping. - else - { - IsCompressionAllowed=false; - MipLevelCount=MIP_LEVELS_1; - Filter.Set_Mip_Mapping(TextureFilterClass::FILTER_TYPE_NONE); - } - break; - default: break; + // (gth) If thumbnails are not enabled, then we don't run this code. + if (WW3D::Get_Thumbnail_Enabled() == false) { + return; } - WWASSERT_PRINT(name && name[0], "TextureClass CTor: NULL or empty texture name"); - int len=strlen(name); - for (int i=0;i ite(WW3DAssetManager::Get_Instance()->Texture_Hash()); + // Loop through all the textures in the manager + + for (ite.First ();!ite.Is_Done();ite.Next ()) { - if (name[i]=='+') + TextureClass* tex=ite.Peek_Value(); + + // Consider invalidating if texture has been initialized and defines inactivation time + if (tex->Initialized && tex->InactivationTime) { - IsLightmap=true; + unsigned age=synctime-tex->LastAccessed; - // Set bilinear filtering for lightmaps (they are very stretched and - // low detail so we don't care for anisotropic or trilinear filtering...) - Filter.Set_Min_Filter(TextureFilterClass::FILTER_TYPE_FAST); - Filter.Set_Mag_Filter(TextureFilterClass::FILTER_TYPE_FAST); - if (mip_level_count!=MIP_LEVELS_1) Filter.Set_Mip_Mapping(TextureFilterClass::FILTER_TYPE_FAST); - break; + if (invalidation_time_override) + { + if (age>invalidation_time_override) + { + tex->Invalidate(); + tex->LastInactivationSyncTime=synctime; + } + } + else + { + // Not used in the last n milliseconds? + if (age>(tex->InactivationTime+tex->ExtendedInactivationTime)) + { + tex->Invalidate(); + tex->LastInactivationSyncTime=synctime; + } + } } } - Set_Texture_Name(name); - Set_Full_Path(full_path); - WWASSERT(name[0]!='\0'); - if (!WW3D::Is_Texturing_Enabled()) - { - Initialized=true; - D3DTexture=0; - } - else if (WW3D::Get_Thumbnail_Enabled()==false || mip_level_count==MIP_LEVELS_1) - { - Initialized=true; - D3DTexture=0; - TextureLoader::Request_High_Priority_Loading(this,mip_level_count); - } - else { - Load_Locked_Surface(); - TextureFormat=texture_format; // Locked surface may be in a wrong format - } - LastAccessed=WW3D::Get_Sync_Time(); } -// ---------------------------------------------------------------------------- -TextureClass::TextureClass(SurfaceClass *surface, MipCountType mip_level_count) - : - D3DTexture(NULL), - texture_id(unused_texture_id++), - Initialized(true), - Filter(mip_level_count), - MipLevelCount(mip_level_count), - Pool(POOL_MANAGED), - Dirty(false), - IsLightmap(false), - Name(""), - IsProcedural(true), - TextureFormat(surface->Get_Surface_Format()), - IsCompressionAllowed(false), - TextureLoadTask(NULL), - Width(0), - Height(0) -{ - SurfaceClass::SurfaceDescription sd; - surface->Get_Description(sd); - Width=sd.Width; - Height=sd.Height; - switch (sd.Format) - { - case WW3D_FORMAT_DXT1: - case WW3D_FORMAT_DXT2: - case WW3D_FORMAT_DXT3: - case WW3D_FORMAT_DXT4: - case WW3D_FORMAT_DXT5: - IsCompressionAllowed=true; - break; - default: break; - } - D3DTexture = DX8Wrapper::_Create_DX8_Texture(surface->Peek_D3D_Surface(), mip_level_count); - LastAccessed=WW3D::Get_Sync_Time(); -} -// ---------------------------------------------------------------------------- -TextureClass::TextureClass(IDirect3DTexture8* d3d_texture) - : - D3DTexture(d3d_texture), - texture_id(unused_texture_id++), - Initialized(true), - Filter((MipCountType)d3d_texture->GetLevelCount()), - MipLevelCount((MipCountType)d3d_texture->GetLevelCount()), - Pool(POOL_MANAGED), - Dirty(false), - IsLightmap(false), - Name(""), - IsProcedural(true), - IsCompressionAllowed(false), - TextureLoadTask(NULL), - Width(0), - Height(0) +//********************************************************************************************** +//! Invalidate this texture +/*! +*/ +void TextureBaseClass::Invalidate() { - D3DTexture->AddRef(); - IDirect3DSurface8* surface; - DX8_ErrorCode(Peek_D3D_Texture()->GetSurfaceLevel(0,&surface)); - D3DSURFACE_DESC d3d_desc; - ::ZeroMemory(&d3d_desc, sizeof(D3DSURFACE_DESC)); - DX8_ErrorCode(surface->GetDesc(&d3d_desc)); - Width=d3d_desc.Width; - Height=d3d_desc.Height; - TextureFormat=D3DFormat_To_WW3DFormat(d3d_desc.Format); - switch (TextureFormat) - { - case WW3D_FORMAT_DXT1: - case WW3D_FORMAT_DXT2: - case WW3D_FORMAT_DXT3: - case WW3D_FORMAT_DXT4: - case WW3D_FORMAT_DXT5: - IsCompressionAllowed=true; - break; - default: break; + if (TextureLoadTask) { + return; + } + if (ThumbnailLoadTask) { + return; } - LastAccessed=WW3D::Get_Sync_Time(); -} - -// ---------------------------------------------------------------------------- - -TextureClass::~TextureClass(void) -{ - TextureLoadTaskClass::Release_Instance(TextureLoadTask); - TextureLoadTask=NULL; - - if (!Initialized) { - WWDEBUG_SAY(("Warning: Texture %s was loaded but never used",Get_Texture_Name().str())); + // Don't invalidate procedural textures + if (IsProcedural) { + return; } - if (D3DTexture) { + if (D3DTexture) + { D3DTexture->Release(); D3DTexture = NULL; } - DX8TextureManagerClass::Remove(this); -} - -// ---------------------------------------------------------------------------- -void TextureClass::Init() -{ - // If the texture has already been initialised we should exit now - if (Initialized) return; + Initialized=false; - TextureLoader::Add_Load_Task(this); LastAccessed=WW3D::Get_Sync_Time(); -} +/* was battlefield version// If the texture has already been initialised we should exit now + if (Initialized) return; -void TextureClass::Invalidate() -{ - // Don't invalidate procedural textures - if (IsProcedural) return; + WWPROFILE(("TextureClass::Init()")); - // Don't invalidate missing texture - if (Is_Missing_Texture()) return; + // If the texture has recently been inactivated, increase the inactivation time (this texture obviously + // should not have been inactivated yet). - if (D3DTexture) { - D3DTexture->Release(); - D3DTexture = NULL; + if (InactivationTime && LastInactivationSyncTime) { + if ((WW3D::Get_Sync_Time()-LastInactivationSyncTime)Release(); + D3DTexture = NULL; } + + Initialized=false; + + LastAccessed=WW3D::Get_Sync_Time();*/ } //********************************************************************************************** //! Returns a pointer to the d3d texture /*! */ -IDirect3DBaseTexture8 * TextureClass::Peek_D3D_Base_Texture() const +IDirect3DBaseTexture8 * TextureBaseClass::Peek_D3D_Base_Texture() const { LastAccessed=WW3D::Get_Sync_Time(); return D3DTexture; @@ -383,7 +261,7 @@ IDirect3DBaseTexture8 * TextureClass::Peek_D3D_Base_Texture() const //! Set the d3d texture pointer. Handles ref counts properly. /*! */ -void TextureClass::Set_D3D_Base_Texture(IDirect3DBaseTexture8* tex) +void TextureBaseClass::Set_D3D_Base_Texture(IDirect3DBaseTexture8* tex) { // (gth) Generals does stuff directly with the D3DTexture pointer so lets // reset the access timer whenever someon messes with this pointer. @@ -398,212 +276,176 @@ void TextureClass::Set_D3D_Base_Texture(IDirect3DBaseTexture8* tex) } } -// ---------------------------------------------------------------------------- -void TextureClass::Load_Locked_Surface() +//********************************************************************************************** +//! Load locked surface +/*! +*/ +void TextureBaseClass::Load_Locked_Surface() { + WWPROFILE(("TextureClass::Load_Locked_Surface()")); if (D3DTexture) D3DTexture->Release(); D3DTexture=0; TextureLoader::Request_Thumbnail(this); Initialized=false; } -// ---------------------------------------------------------------------------- -bool TextureClass::Is_Missing_Texture() +//********************************************************************************************** +//! Is missing texture +/*! +*/ +bool TextureBaseClass::Is_Missing_Texture() { bool flag = false; - IDirect3DTexture8 *missing_texture = MissingTexture::_Get_Missing_Texture(); + IDirect3DBaseTexture8 *missing_texture = MissingTexture::_Get_Missing_Texture(); - if(D3DTexture == missing_texture) + if (D3DTexture == missing_texture) flag = true; - if(missing_texture) + if (missing_texture) + { missing_texture->Release(); + } return flag; } -// ---------------------------------------------------------------------------- -void TextureClass::Set_Texture_Name(const char * name) +//********************************************************************************************** +//! Set texture name +/*! +*/ +void TextureBaseClass::Set_Texture_Name(const char * name) { Name=name; } -// ---------------------------------------------------------------------------- - -unsigned int TextureClass::Get_Mip_Level_Count(void) -{ - if (!D3DTexture) { - WWASSERT_PRINT(0, "Get_Mip_Level_Count: D3DTexture is NULL!"); - return 0; - } - - return D3DTexture->GetLevelCount(); -} - -// ---------------------------------------------------------------------------- - -void TextureClass::Get_Level_Description(SurfaceClass::SurfaceDescription &surface_desc, unsigned int level) -{ - if (!D3DTexture) { - WWASSERT_PRINT(0, "Get_Surface_Description: D3DTexture is NULL!"); - } - - D3DSURFACE_DESC d3d_surf_desc; - DX8_ErrorCode(Peek_D3D_Texture()->GetLevelDesc(level, &d3d_surf_desc)); - surface_desc.Format = D3DFormat_To_WW3DFormat(d3d_surf_desc.Format); - surface_desc.Height = d3d_surf_desc.Height; - surface_desc.Width = d3d_surf_desc.Width; -} - -// ---------------------------------------------------------------------------- -SurfaceClass *TextureClass::Get_Surface_Level(unsigned int level) -{ - IDirect3DSurface8 *d3d_surface = NULL; - DX8_ErrorCode(Peek_D3D_Texture()->GetSurfaceLevel(level, &d3d_surface)); - SurfaceClass *surface = W3DNEW SurfaceClass(d3d_surface); - d3d_surface->Release(); - return surface; -} -// ---------------------------------------------------------------------------- -unsigned int TextureClass::Get_Priority(void) +//********************************************************************************************** +//! Get priority +/*! +*/ +unsigned int TextureBaseClass::Get_Priority(void) { - if (!D3DTexture) { + if (!D3DTexture) + { WWASSERT_PRINT(0, "Get_Priority: D3DTexture is NULL!"); return 0; } +#ifndef _XBOX return D3DTexture->GetPriority(); +#else + return 0; +#endif } -// ---------------------------------------------------------------------------- -unsigned int TextureClass::Set_Priority(unsigned int priority) +//********************************************************************************************** +//! Set priority +/*! +*/ +unsigned int TextureBaseClass::Set_Priority(unsigned int priority) { - if (!D3DTexture) { + if (!D3DTexture) + { WWASSERT_PRINT(0, "Set_Priority: D3DTexture is NULL!"); return 0; } +#ifndef _XBOX return D3DTexture->SetPriority(priority); +#else + return 0; +#endif } -unsigned TextureClass::Get_Reduction() const + +//********************************************************************************************** +//! Get reduction mip levels +/*! +*/ +unsigned TextureBaseClass::Get_Reduction() const { + // don't reduce if the texture is too small already or + // has no mip map levels if (MipLevelCount==MIP_LEVELS_1) return 0; + if (Width <= 32 || Height <= 32) return 0; int reduction=WW3D::Get_Texture_Reduction(); + + // 'large texture extra reduction' causes textures above 256x256 to be reduced one more step. + if (WW3D::Is_Large_Texture_Extra_Reduction_Enabled() && (Width > 256 || Height > 256)) { + reduction++; + } if (MipLevelCount && reduction>MipLevelCount) { reduction=MipLevelCount; } return reduction; } -// ---------------------------------------------------------------------------- - -void TextureClass::Apply(unsigned int stage) -{ - if (!Initialized) - { - Init(); - } - LastAccessed=WW3D::Get_Sync_Time(); - - DX8_RECORD_TEXTURE(this); - - // Set texture itself - if (WW3D::Is_Texturing_Enabled()) - { - DX8Wrapper::Set_DX8_Texture(stage, D3DTexture); - } - else - { - DX8Wrapper::Set_DX8_Texture(stage, NULL); - } - - Filter.Apply(stage); -} -// ---------------------------------------------------------------------------- -void TextureClass::Apply_Null(unsigned int stage) +//********************************************************************************************** +//! Apply NULL texture state +/*! +*/ +void TextureBaseClass::Apply_Null(unsigned int stage) { // This function sets the render states for a "NULL" texture DX8Wrapper::Set_DX8_Texture(stage, NULL); } // ---------------------------------------------------------------------------- - -void TextureClass::Apply_New_Surface(bool initialized) -{ - if (D3DTexture) D3DTexture->Release(); - D3DTexture=TextureLoadTask->Peek_D3D_Texture(); - D3DTexture->AddRef(); - if (initialized) Initialized=true; - - WWASSERT(D3DTexture); - IDirect3DSurface8* surface; - DX8_ErrorCode(Peek_D3D_Texture()->GetSurfaceLevel(0,&surface)); - D3DSURFACE_DESC d3d_desc; - ::ZeroMemory(&d3d_desc, sizeof(D3DSURFACE_DESC)); - DX8_ErrorCode(surface->GetDesc(&d3d_desc)); -// if (TextureFormat==WW3D_FORMAT_UNKNOWN) { - TextureFormat=D3DFormat_To_WW3DFormat(d3d_desc.Format); - Width=d3d_desc.Width; - Height=d3d_desc.Height; -// } -// else { -// WWASSERT(D3DFormat_To_WW3DFormat(d3d_desc.Format)==TextureFormat); -// } - surface->Release(); -} - +// Setting HSV_Shift value is always relative to the original texture. This function invalidates the +// texture surface and causes the texture to be reloaded. For thumbnailable textures, the hue shifting +// is done in the background loading thread. // ---------------------------------------------------------------------------- - -unsigned TextureClass::Get_Texture_Memory_Usage() const +void TextureBaseClass::Set_HSV_Shift(const Vector3 &hsv_shift) { - if (/*!ReductionEnabled || */!Initialized) return Calculate_Texture_Memory_Usage(this,0); -// unsigned reduction=WW3D::Get_Texture_Reduction(); -// if (CurrentReductionFactor>reduction) reduction=CurrentReductionFactor; - return Calculate_Texture_Memory_Usage(this,0);//reduction); + Invalidate(); + HSVShift=hsv_shift; } -// ---------------------------------------------------------------------------- - -int TextureClass::_Get_Total_Locked_Surface_Size() +//********************************************************************************************** +//! Get total locked surface size +/*! KM +*/ +int TextureBaseClass::_Get_Total_Locked_Surface_Size() { int total_locked_surface_size=0; HashTemplateIterator ite(WW3DAssetManager::Get_Instance()->Texture_Hash()); // Loop through all the textures in the manager - for (ite.First ();!ite.Is_Done();ite.Next ()) { - + for (ite.First ();!ite.Is_Done();ite.Next ()) + { // Get the current texture - TextureClass* tex=ite.Peek_Value(); - if (!tex->Initialized) { -// total_locked_surface_size+=tex->Get_Non_Reduced_Texture_Memory_Usage(); + TextureBaseClass* tex=ite.Peek_Value(); + if (!tex->Initialized) + { total_locked_surface_size+=tex->Get_Texture_Memory_Usage(); } } return total_locked_surface_size; } -// ---------------------------------------------------------------------------- - -int TextureClass::_Get_Total_Texture_Size() +//********************************************************************************************** +//! Get total texture size +/*! KM +*/ +int TextureBaseClass::_Get_Total_Texture_Size() { int total_texture_size=0; HashTemplateIterator ite(WW3DAssetManager::Get_Instance()->Texture_Hash()); // Loop through all the textures in the manager - for (ite.First ();!ite.Is_Done();ite.Next ()) { + for (ite.First ();!ite.Is_Done();ite.Next ()) + { // Get the current texture - TextureClass* tex=ite.Peek_Value(); + TextureBaseClass* tex=ite.Peek_Value(); total_texture_size+=tex->Get_Texture_Memory_Usage(); } return total_texture_size; @@ -611,49 +453,64 @@ int TextureClass::_Get_Total_Texture_Size() // ---------------------------------------------------------------------------- -int TextureClass::_Get_Total_Lightmap_Texture_Size() + +//********************************************************************************************** +//! Get total lightmap texture size +/*! +*/ +int TextureBaseClass::_Get_Total_Lightmap_Texture_Size() { int total_texture_size=0; HashTemplateIterator ite(WW3DAssetManager::Get_Instance()->Texture_Hash()); // Loop through all the textures in the manager - for (ite.First ();!ite.Is_Done();ite.Next ()) { + for (ite.First ();!ite.Is_Done();ite.Next ()) + { // Get the current texture - TextureClass* tex=ite.Peek_Value(); - if (tex->Is_Lightmap()) { + TextureBaseClass* tex=ite.Peek_Value(); + if (tex->Is_Lightmap()) + { total_texture_size+=tex->Get_Texture_Memory_Usage(); } } return total_texture_size; } -// ---------------------------------------------------------------------------- -int TextureClass::_Get_Total_Procedural_Texture_Size() +//********************************************************************************************** +//! Get total procedural texture size +/*! +*/ +int TextureBaseClass::_Get_Total_Procedural_Texture_Size() { int total_texture_size=0; HashTemplateIterator ite(WW3DAssetManager::Get_Instance()->Texture_Hash()); // Loop through all the textures in the manager - for (ite.First ();!ite.Is_Done();ite.Next ()) { + for (ite.First ();!ite.Is_Done();ite.Next ()) + { // Get the current texture - TextureClass* tex=ite.Peek_Value(); - if (tex->Is_Procedural()) { + TextureBaseClass* tex=ite.Peek_Value(); + if (tex->Is_Procedural()) + { total_texture_size+=tex->Get_Texture_Memory_Usage(); } } return total_texture_size; } -// ---------------------------------------------------------------------------- - -int TextureClass::_Get_Total_Texture_Count() +//********************************************************************************************** +//! Get total texture count +/*! +*/ +int TextureBaseClass::_Get_Total_Texture_Count() { int texture_count=0; HashTemplateIterator ite(WW3DAssetManager::Get_Instance()->Texture_Hash()); // Loop through all the textures in the manager - for (ite.First ();!ite.Is_Done();ite.Next ()) { + for (ite.First ();!ite.Is_Done();ite.Next ()) + { texture_count++; } @@ -662,14 +519,21 @@ int TextureClass::_Get_Total_Texture_Count() // ---------------------------------------------------------------------------- -int TextureClass::_Get_Total_Lightmap_Texture_Count() + +//********************************************************************************************** +//! Get total light map texture count +/*! +*/ +int TextureBaseClass::_Get_Total_Lightmap_Texture_Count() { int texture_count=0; HashTemplateIterator ite(WW3DAssetManager::Get_Instance()->Texture_Hash()); // Loop through all the textures in the manager - for (ite.First ();!ite.Is_Done();ite.Next ()) { - if (ite.Peek_Value()->Is_Lightmap()) { + for (ite.First ();!ite.Is_Done();ite.Next ()) + { + if (ite.Peek_Value()->Is_Lightmap()) + { texture_count++; } } @@ -677,16 +541,20 @@ int TextureClass::_Get_Total_Lightmap_Texture_Count() return texture_count; } -// ---------------------------------------------------------------------------- - -int TextureClass::_Get_Total_Procedural_Texture_Count() +//********************************************************************************************** +//! Get total procedural texture count +/*! +*/ +int TextureBaseClass::_Get_Total_Procedural_Texture_Count() { int texture_count=0; HashTemplateIterator ite(WW3DAssetManager::Get_Instance()->Texture_Hash()); // Loop through all the textures in the manager - for (ite.First ();!ite.Is_Done();ite.Next ()) { - if (ite.Peek_Value()->Is_Procedural()) { + for (ite.First ();!ite.Is_Done();ite.Next ()) + { + if (ite.Peek_Value()->Is_Procedural()) + { texture_count++; } } @@ -694,199 +562,1347 @@ int TextureClass::_Get_Total_Procedural_Texture_Count() return texture_count; } -// ---------------------------------------------------------------------------- -int TextureClass::_Get_Total_Locked_Surface_Count() +//********************************************************************************************** +//! Get total locked surface count +/*! +*/ +int TextureBaseClass::_Get_Total_Locked_Surface_Count() { int texture_count=0; HashTemplateIterator ite(WW3DAssetManager::Get_Instance()->Texture_Hash()); // Loop through all the textures in the manager - for (ite.First ();!ite.Is_Done();ite.Next ()) { + for (ite.First ();!ite.Is_Done();ite.Next ()) + { // Get the current texture - TextureClass* tex=ite.Peek_Value(); - if (!tex->Initialized) { + TextureBaseClass* tex=ite.Peek_Value(); + if (!tex->Initialized) + { texture_count++; } } return texture_count; } -/* -bool Validate_Filters(unsigned type) -{ - ShaderClass shader=ShaderClass::_PresetOpaqueShader; - shader.Apply(); - DX8Wrapper::Set_DX8_Texture(0, MissingTexture::_Get_Missing_Texture()); - DX8Wrapper::Set_DX8_Texture_Stage_State(0,D3DTSS_MINFILTER,_MinTextureFilters[type]); - DX8Wrapper::Set_DX8_Texture_Stage_State(0,D3DTSS_MAGFILTER,_MagTextureFilters[type]); - DX8Wrapper::Set_DX8_Texture_Stage_State(0,D3DTSS_MIPFILTER,_MipMapFilters[type]); - unsigned long passes; - HRESULT hres=DX8Wrapper::_Get_D3D_Device8()->ValidateDevice(&passes); - return !FAILED(hres); -} -*/ - -// Utility functions -TextureClass* Load_Texture(ChunkLoadClass & cload) +/************************************************************************* +** TextureClass +*************************************************************************/ +TextureClass::TextureClass +( + unsigned width, + unsigned height, + WW3DFormat format, + MipCountType mip_level_count, + PoolType pool, + bool rendertarget, + bool allow_reduction +) +: TextureBaseClass(width, height, mip_level_count, pool, rendertarget,allow_reduction), + Filter(mip_level_count), + TextureFormat(format) { - // Assume failure - TextureClass *newtex = NULL; + Initialized=true; + IsProcedural=true; + IsReducible=false; - char name[256]; - if (cload.Open_Chunk () && (cload.Cur_Chunk_ID () == W3D_CHUNK_TEXTURE)) + switch (format) { + case WW3D_FORMAT_DXT1: + case WW3D_FORMAT_DXT2: + case WW3D_FORMAT_DXT3: + case WW3D_FORMAT_DXT4: + case WW3D_FORMAT_DXT5: + IsCompressionAllowed=true; + break; + default : break; + } - W3dTextureInfoStruct texinfo; - bool hastexinfo = false; - - /* - ** Read in the texture filename, and a possible texture info structure. - */ - while (cload.Open_Chunk()) { - switch (cload.Cur_Chunk_ID()) { - case W3D_CHUNK_TEXTURE_NAME: - cload.Read(&name,cload.Cur_Chunk_Length()); - break; - - case W3D_CHUNK_TEXTURE_INFO: - cload.Read(&texinfo,sizeof(W3dTextureInfoStruct)); - hastexinfo = true; - break; - }; - cload.Close_Chunk(); - } - cload.Close_Chunk(); - - /* - ** Get the texture from the asset manager - */ - if (hastexinfo) - { - - MipCountType mipcount; - - bool no_lod = ((texinfo.Attributes & W3DTEXTURE_NO_LOD) == W3DTEXTURE_NO_LOD); + D3DPOOL d3dpool=(D3DPOOL)0; + switch(pool) + { + case POOL_DEFAULT : d3dpool=D3DPOOL_DEFAULT; break; + case POOL_MANAGED : d3dpool=D3DPOOL_MANAGED; break; + case POOL_SYSTEMMEM : d3dpool=D3DPOOL_SYSTEMMEM; break; + default: WWASSERT(0); + } - if (no_lod) - { - mipcount = MIP_LEVELS_1; - } - else - { - switch (texinfo.Attributes & W3DTEXTURE_MIP_LEVELS_MASK) { + Poke_Texture + ( + DX8Wrapper::_Create_DX8_Texture + ( + width, + height, + format, + mip_level_count, + d3dpool, + rendertarget + ) + ); - case W3DTEXTURE_MIP_LEVELS_ALL: - mipcount = MIP_LEVELS_ALL; - break; + if (pool==POOL_DEFAULT) + { + Set_Dirty(); + DX8TextureTrackerClass *track=new DX8TextureTrackerClass + ( + width, + height, + format, + mip_level_count, + this, + rendertarget + ); + DX8TextureManagerClass::Add(track); + } + LastAccessed=WW3D::Get_Sync_Time(); +} - case W3DTEXTURE_MIP_LEVELS_2: - mipcount = MIP_LEVELS_2; - break; - case W3DTEXTURE_MIP_LEVELS_3: - mipcount = MIP_LEVELS_3; - break; - case W3DTEXTURE_MIP_LEVELS_4: - mipcount = MIP_LEVELS_4; - break; +// ---------------------------------------------------------------------------- +TextureClass::TextureClass +( + const char *name, + const char *full_path, + MipCountType mip_level_count, + WW3DFormat texture_format, + bool allow_compression, + bool allow_reduction +) +: TextureBaseClass(0, 0, mip_level_count), + Filter(mip_level_count), + TextureFormat(texture_format) +{ + IsCompressionAllowed=allow_compression; + InactivationTime=DEFAULT_INACTIVATION_TIME; // Default inactivation time 30 seconds + IsReducible=allow_reduction; - default: - WWASSERT (false); - mipcount = MIP_LEVELS_ALL; - break; + switch (TextureFormat) + { + case WW3D_FORMAT_DXT1: + case WW3D_FORMAT_DXT2: + case WW3D_FORMAT_DXT3: + case WW3D_FORMAT_DXT4: + case WW3D_FORMAT_DXT5: + IsCompressionAllowed=true; + break; + case WW3D_FORMAT_U8V8: // Bumpmap + case WW3D_FORMAT_L6V5U5: // Bumpmap + case WW3D_FORMAT_X8L8V8U8: // Bumpmap + // If requesting bumpmap format that isn't available we'll just return the surface in whatever color + // format the texture file is in. (This is illegal case, the format support should always be queried + // before creating a bump texture!) + if (!DX8Wrapper::Is_Initted() || !DX8Wrapper::Get_Current_Caps()->Support_Texture_Format(TextureFormat)) + { + TextureFormat=WW3D_FORMAT_UNKNOWN; + } + // If bump format is valid, make sure compression is not allowed so that we don't even attempt to load + // from a compressed file (quality isn't good enough for bump map). Also disable mipmapping. + else + { + IsCompressionAllowed=false; + MipLevelCount=MIP_LEVELS_1; + Filter.Set_Mip_Mapping(TextureFilterClass::FILTER_TYPE_NONE); + } + break; + default: break; + } + + WWASSERT_PRINT(name && name[0], "TextureClass CTor: NULL or empty texture name"); + int len=strlen(name); + for (int i=0;iGet_Original_Texture_Width(); + Height=thumb->Get_Original_Texture_Height(); + if (MipLevelCount!=MIP_LEVELS_1) { + MipLevelCount=(MipCountType)thumb->Get_Original_Texture_Mip_Level_Count(); + } + } + + LastAccessed=WW3D::Get_Sync_Time(); + + // If the thumbnails are not enabled, init the texture at this point to avoid stalling when the + // mesh is rendered. + if (!WW3D::Get_Thumbnail_Enabled()) + { + if (TextureLoader::Is_DX8_Thread()) + { + Init(); + } + } +} + +// ---------------------------------------------------------------------------- +TextureClass::TextureClass +( + SurfaceClass *surface, + MipCountType mip_level_count +) +: TextureBaseClass(0,0,mip_level_count), + Filter(mip_level_count), + TextureFormat(surface->Get_Surface_Format()) +{ + IsProcedural=true; + Initialized=true; + IsReducible=false; + + SurfaceClass::SurfaceDescription sd; + surface->Get_Description(sd); + Width=sd.Width; + Height=sd.Height; + switch (sd.Format) + { + case WW3D_FORMAT_DXT1: + case WW3D_FORMAT_DXT2: + case WW3D_FORMAT_DXT3: + case WW3D_FORMAT_DXT4: + case WW3D_FORMAT_DXT5: + IsCompressionAllowed=true; + break; + default: break; + } + + Poke_Texture + ( + DX8Wrapper::_Create_DX8_Texture + ( + surface->Peek_D3D_Surface(), + mip_level_count + ) + ); + LastAccessed=WW3D::Get_Sync_Time(); +} + +// ---------------------------------------------------------------------------- +TextureClass::TextureClass(IDirect3DBaseTexture8* d3d_texture) +: TextureBaseClass + ( + 0, + 0, + ((MipCountType)d3d_texture->GetLevelCount()) + ), + Filter((MipCountType)d3d_texture->GetLevelCount()) +{ + Initialized=true; + IsProcedural=true; + IsReducible=false; + + Set_D3D_Base_Texture(d3d_texture); + IDirect3DSurface8* surface; + DX8_ErrorCode(Peek_D3D_Texture()->GetSurfaceLevel(0,&surface)); + D3DSURFACE_DESC d3d_desc; + ::ZeroMemory(&d3d_desc, sizeof(D3DSURFACE_DESC)); + DX8_ErrorCode(surface->GetDesc(&d3d_desc)); + Width=d3d_desc.Width; + Height=d3d_desc.Height; + TextureFormat=D3DFormat_To_WW3DFormat(d3d_desc.Format); + switch (TextureFormat) + { + case WW3D_FORMAT_DXT1: + case WW3D_FORMAT_DXT2: + case WW3D_FORMAT_DXT3: + case WW3D_FORMAT_DXT4: + case WW3D_FORMAT_DXT5: + IsCompressionAllowed=true; + break; + default: break; + } + + LastAccessed=WW3D::Get_Sync_Time(); +} + +//********************************************************************************************** +//! Initialise the texture +/*! +*/ +void TextureClass::Init() +{ + // If the texture has already been initialised we should exit now + if (Initialized) return; + + WWPROFILE("TextureClass::Init"); + + // If the texture has recently been inactivated, increase the inactivation time (this texture obviously + // should not have been inactivated yet). + if (InactivationTime && LastInactivationSyncTime) + { + if ((WW3D::Get_Sync_Time()-LastInactivationSyncTime)Release(); + + Poke_Texture(d3d_texture);//TextureLoadTask->Peek_D3D_Texture(); + d3d_texture->AddRef(); + + if (initialized) Initialized=true; + if (disable_auto_invalidation) InactivationTime = 0; + + WWASSERT(d3d_texture); + IDirect3DSurface8* surface; + DX8_ErrorCode(Peek_D3D_Texture()->GetSurfaceLevel(0,&surface)); + D3DSURFACE_DESC d3d_desc; + ::ZeroMemory(&d3d_desc, sizeof(D3DSURFACE_DESC)); + DX8_ErrorCode(surface->GetDesc(&d3d_desc)); + if (initialized) + { + TextureFormat=D3DFormat_To_WW3DFormat(d3d_desc.Format); + Width=d3d_desc.Width; + Height=d3d_desc.Height; + } + surface->Release(); + +} + + +//********************************************************************************************** +//! Apply texture states +/*! +*/ +void TextureClass::Apply(unsigned int stage) +{ + // Initialization needs to be done when texture is used if it hasn't been done before. + // XBOX always initializes textures at creation time. + if (!Initialized) + { + Init(); + + /* was in battlefield// Non-thumbnailed textures are always initialized when used + if (MipLevelCount==MIP_LEVELS_1) + { + } + // Thumbnailed textures have delayed initialization and a background loading system + else + { + // Limit the number of texture initializations per frame to reduce stuttering + if (TexturesAppliedPerFrameGet_Texture (name, mipcount); + }*/ + } + LastAccessed=WW3D::Get_Sync_Time(); + + DX8_RECORD_TEXTURE(this); + + // Set texture itself + if (WW3D::Is_Texturing_Enabled()) + { + DX8Wrapper::Set_DX8_Texture(stage, Peek_D3D_Base_Texture()); + } + else + { + DX8Wrapper::Set_DX8_Texture(stage, NULL); + } + + Filter.Apply(stage); +} + +//********************************************************************************************** +//! Get surface from mip level +/*! +*/ +SurfaceClass *TextureClass::Get_Surface_Level(unsigned int level) +{ + if (!Peek_D3D_Texture()) + { + WWASSERT_PRINT(0, "Get_Surface_Level: D3DTexture is NULL!"); + return 0; + } + + IDirect3DSurface8 *d3d_surface = NULL; + DX8_ErrorCode(Peek_D3D_Texture()->GetSurfaceLevel(level, &d3d_surface)); + SurfaceClass *surface = new SurfaceClass(d3d_surface); + d3d_surface->Release(); + + return surface; +} + +//********************************************************************************************** +//! Get surface description for a mip level +/*! +*/ +void TextureClass::Get_Level_Description( SurfaceClass::SurfaceDescription & desc, unsigned int level ) +{ + SurfaceClass * surf = Get_Surface_Level(level); + if (surf != NULL) { + surf->Get_Description(desc); + } + REF_PTR_RELEASE(surf); +} + +//********************************************************************************************** +//! Get D3D surface from mip level +/*! +*/ +IDirect3DSurface8 *TextureClass::Get_D3D_Surface_Level(unsigned int level) +{ + if (!Peek_D3D_Texture()) + { + WWASSERT_PRINT(0, "Get_D3D_Surface_Level: D3DTexture is NULL!"); + return 0; + } + + IDirect3DSurface8 *d3d_surface = NULL; + DX8_ErrorCode(Peek_D3D_Texture()->GetSurfaceLevel(level, &d3d_surface)); + return d3d_surface; +} + +//********************************************************************************************** +//! Get texture memory usage +/*! +*/ +unsigned TextureClass::Get_Texture_Memory_Usage() const +{ + int size=0; + if (!Peek_D3D_Texture()) return 0; + for (unsigned i=0;iGetLevelCount();++i) + { + D3DSURFACE_DESC desc; + DX8_ErrorCode(Peek_D3D_Texture()->GetLevelDesc(i,&desc)); + size+=desc.Size; + } + return size; +} + + +// Utility functions +TextureClass* Load_Texture(ChunkLoadClass & cload) +{ + // Assume failure + TextureClass *newtex = NULL; + + char name[256]; + if (cload.Open_Chunk () && (cload.Cur_Chunk_ID () == W3D_CHUNK_TEXTURE)) + { + + W3dTextureInfoStruct texinfo; + bool hastexinfo = false; + + /* + ** Read in the texture filename, and a possible texture info structure. + */ + while (cload.Open_Chunk()) { + switch (cload.Cur_Chunk_ID()) { + case W3D_CHUNK_TEXTURE_NAME: + cload.Read(&name,cload.Cur_Chunk_Length()); + break; + + case W3D_CHUNK_TEXTURE_INFO: + cload.Read(&texinfo,sizeof(W3dTextureInfoStruct)); + hastexinfo = true; + break; + }; + cload.Close_Chunk(); + } + cload.Close_Chunk(); + + /* + ** Get the texture from the asset manager + */ + if (hastexinfo) + { + + MipCountType mipcount; + + bool no_lod = ((texinfo.Attributes & W3DTEXTURE_NO_LOD) == W3DTEXTURE_NO_LOD); + + if (no_lod) + { + mipcount = MIP_LEVELS_1; + } + else + { + switch (texinfo.Attributes & W3DTEXTURE_MIP_LEVELS_MASK) { + + case W3DTEXTURE_MIP_LEVELS_ALL: + mipcount = MIP_LEVELS_ALL; + break; + + case W3DTEXTURE_MIP_LEVELS_2: + mipcount = MIP_LEVELS_2; + break; + + case W3DTEXTURE_MIP_LEVELS_3: + mipcount = MIP_LEVELS_3; + break; + + case W3DTEXTURE_MIP_LEVELS_4: + mipcount = MIP_LEVELS_4; + break; + + default: + WWASSERT (false); + mipcount = MIP_LEVELS_ALL; + break; + } + } + + WW3DFormat format=WW3D_FORMAT_UNKNOWN; + + switch (texinfo.Attributes & W3DTEXTURE_TYPE_MASK) + { + + case W3DTEXTURE_TYPE_COLORMAP: + // Do nothing. + break; + + case W3DTEXTURE_TYPE_BUMPMAP: + { + if (DX8Wrapper::Is_Initted() && DX8Wrapper::Get_Current_Caps()->Support_Bump_Envmap()) + { + // No mipmaps to bumpmap for now + mipcount=MIP_LEVELS_1; + + if (DX8Wrapper::Get_Current_Caps()->Support_Texture_Format(WW3D_FORMAT_U8V8)) format=WW3D_FORMAT_U8V8; + else if (DX8Wrapper::Get_Current_Caps()->Support_Texture_Format(WW3D_FORMAT_X8L8V8U8)) format=WW3D_FORMAT_X8L8V8U8; + else if (DX8Wrapper::Get_Current_Caps()->Support_Texture_Format(WW3D_FORMAT_L6V5U5)) format=WW3D_FORMAT_L6V5U5; + } + break; + } + + default: + WWASSERT (false); + break; + } + + newtex = WW3DAssetManager::Get_Instance()->Get_Texture (name, mipcount, format); + + if (no_lod) + { + newtex->Get_Filter().Set_Mip_Mapping(TextureFilterClass::FILTER_TYPE_NONE); + } + bool u_clamp = ((texinfo.Attributes & W3DTEXTURE_CLAMP_U) != 0); + newtex->Get_Filter().Set_U_Addr_Mode(u_clamp ? TextureFilterClass::TEXTURE_ADDRESS_CLAMP : TextureFilterClass::TEXTURE_ADDRESS_REPEAT); + bool v_clamp = ((texinfo.Attributes & W3DTEXTURE_CLAMP_V) != 0); + newtex->Get_Filter().Set_V_Addr_Mode(v_clamp ? TextureFilterClass::TEXTURE_ADDRESS_CLAMP : TextureFilterClass::TEXTURE_ADDRESS_REPEAT); + + } else + { + newtex = WW3DAssetManager::Get_Instance()->Get_Texture(name); + } + + WWASSERT(newtex); + } + + // Return a pointer to the new texture + return newtex; +} + +// Utility function used by Save_Texture +void setup_texture_attributes(TextureClass * tex, W3dTextureInfoStruct * texinfo) +{ + texinfo->Attributes = 0; + + if (tex->Get_Filter().Get_Mip_Mapping() == TextureFilterClass::FILTER_TYPE_NONE) texinfo->Attributes |= W3DTEXTURE_NO_LOD; + if (tex->Get_Filter().Get_U_Addr_Mode() == TextureFilterClass::TEXTURE_ADDRESS_CLAMP) texinfo->Attributes |= W3DTEXTURE_CLAMP_U; + if (tex->Get_Filter().Get_V_Addr_Mode() == TextureFilterClass::TEXTURE_ADDRESS_CLAMP) texinfo->Attributes |= W3DTEXTURE_CLAMP_V; +} + + +void Save_Texture(TextureClass * texture,ChunkSaveClass & csave) +{ + const char * filename; + W3dTextureInfoStruct texinfo; + memset(&texinfo,0,sizeof(texinfo)); + + filename = texture->Get_Full_Path(); + + setup_texture_attributes(texture, &texinfo); + + csave.Begin_Chunk(W3D_CHUNK_TEXTURE_NAME); + csave.Write(filename,strlen(filename)+1); + csave.End_Chunk(); + + if ((texinfo.Attributes != 0) || (texinfo.AnimType != 0) || (texinfo.FrameCount != 0)) { + csave.Begin_Chunk(W3D_CHUNK_TEXTURE_INFO); + csave.Write(&texinfo, sizeof(texinfo)); + csave.End_Chunk(); + } +} + + +/*! + * KJM depth stencil texture constructor + */ +ZTextureClass::ZTextureClass +( + unsigned width, + unsigned height, + WW3DZFormat zformat, + MipCountType mip_level_count, + PoolType pool +) +: TextureBaseClass(width,height, mip_level_count, pool), + DepthStencilTextureFormat(zformat) +{ + D3DPOOL d3dpool=(D3DPOOL)0; + switch (pool) + { + case POOL_DEFAULT: d3dpool=D3DPOOL_DEFAULT; break; + case POOL_MANAGED: d3dpool=D3DPOOL_MANAGED; break; + case POOL_SYSTEMMEM: d3dpool=D3DPOOL_SYSTEMMEM; break; + default: WWASSERT(0); + } + + Poke_Texture + ( + DX8Wrapper::_Create_DX8_ZTexture + ( + width, + height, + zformat, + mip_level_count, + d3dpool + ) + ); + + if (pool==POOL_DEFAULT) + { + Set_Dirty(); + DX8ZTextureTrackerClass *track=new DX8ZTextureTrackerClass + ( + width, + height, + zformat, + mip_level_count, + this + ); + DX8TextureManagerClass::Add(track); + } + Initialized=true; + IsProcedural=true; + IsReducible=false; + + LastAccessed=WW3D::Get_Sync_Time(); +} + + +//********************************************************************************************** +//! Apply depth stencil texture +/*! KM +*/ +void ZTextureClass::Apply(unsigned int stage) +{ + DX8Wrapper::Set_DX8_Texture(stage, Peek_D3D_Base_Texture()); +} + +//********************************************************************************************** +//! Apply new surface to texture +/*! KM +*/ +void ZTextureClass::Apply_New_Surface +( + IDirect3DBaseTexture8* d3d_texture, + bool initialized, + bool disable_auto_invalidation +) +{ + IDirect3DBaseTexture8* d3d_tex=Peek_D3D_Base_Texture(); + + if (d3d_tex) d3d_tex->Release(); + + Poke_Texture(d3d_texture);//TextureLoadTask->Peek_D3D_Texture(); + d3d_texture->AddRef(); + + if (initialized) Initialized=true; + if (disable_auto_invalidation) InactivationTime = 0; + + WWASSERT(Peek_D3D_Texture()); + IDirect3DSurface8* surface; + DX8_ErrorCode(Peek_D3D_Texture()->GetSurfaceLevel(0,&surface)); + D3DSURFACE_DESC d3d_desc; + ::ZeroMemory(&d3d_desc, sizeof(D3DSURFACE_DESC)); + DX8_ErrorCode(surface->GetDesc(&d3d_desc)); + if (initialized) + { + DepthStencilTextureFormat=D3DFormat_To_WW3DZFormat(d3d_desc.Format); + Width=d3d_desc.Width; + Height=d3d_desc.Height; + } + surface->Release(); +} + +//********************************************************************************************** +//! Get D3D surface from mip level +/*! +*/ +IDirect3DSurface8* ZTextureClass::Get_D3D_Surface_Level(unsigned int level) +{ + if (!Peek_D3D_Texture()) + { + WWASSERT_PRINT(0, "Get_D3D_Surface_Level: D3DTexture is NULL!"); + return 0; + } + + IDirect3DSurface8 *d3d_surface = NULL; + DX8_ErrorCode(Peek_D3D_Texture()->GetSurfaceLevel(level, &d3d_surface)); + return d3d_surface; +} + +//********************************************************************************************** +//! Get texture memory usage +/*! +*/ +unsigned ZTextureClass::Get_Texture_Memory_Usage() const +{ + int size=0; + if (!Peek_D3D_Texture()) return 0; + for (unsigned i=0;iGetLevelCount();++i) + { + D3DSURFACE_DESC desc; + DX8_ErrorCode(Peek_D3D_Texture()->GetLevelDesc(i,&desc)); + size+=desc.Size; + } + return size; +} + + + +/************************************************************************* +** CubeTextureClass +*************************************************************************/ +CubeTextureClass::CubeTextureClass +( + unsigned width, + unsigned height, + WW3DFormat format, + MipCountType mip_level_count, + PoolType pool, + bool rendertarget, + bool allow_reduction +) +: TextureClass(width, height, format, mip_level_count, pool, rendertarget) +{ + Initialized=true; + IsProcedural=true; + IsReducible=false; + + switch (format) + { + case WW3D_FORMAT_DXT1: + case WW3D_FORMAT_DXT2: + case WW3D_FORMAT_DXT3: + case WW3D_FORMAT_DXT4: + case WW3D_FORMAT_DXT5: + IsCompressionAllowed=true; + break; + default : break; + } + + D3DPOOL d3dpool=(D3DPOOL)0; + switch(pool) + { + case POOL_DEFAULT : d3dpool=D3DPOOL_DEFAULT; break; + case POOL_MANAGED : d3dpool=D3DPOOL_MANAGED; break; + case POOL_SYSTEMMEM : d3dpool=D3DPOOL_SYSTEMMEM; break; + default: WWASSERT(0); + } + + Poke_Texture + ( + DX8Wrapper::_Create_DX8_Cube_Texture + ( + width, + height, + format, + mip_level_count, + d3dpool, + rendertarget + ) + ); + + if (pool==POOL_DEFAULT) + { + Set_Dirty(); + DX8TextureTrackerClass *track=new DX8TextureTrackerClass + ( + width, + height, + format, + mip_level_count, + this, + rendertarget + ); + DX8TextureManagerClass::Add(track); + } + LastAccessed=WW3D::Get_Sync_Time(); +} + + + +// ---------------------------------------------------------------------------- +CubeTextureClass::CubeTextureClass +( + const char *name, + const char *full_path, + MipCountType mip_level_count, + WW3DFormat texture_format, + bool allow_compression, + bool allow_reduction +) +: TextureClass(0,0,mip_level_count, POOL_MANAGED, false, texture_format) +{ + IsCompressionAllowed=allow_compression; + InactivationTime=DEFAULT_INACTIVATION_TIME; // Default inactivation time 30 seconds + + switch (TextureFormat) + { + case WW3D_FORMAT_DXT1: + case WW3D_FORMAT_DXT2: + case WW3D_FORMAT_DXT3: + case WW3D_FORMAT_DXT4: + case WW3D_FORMAT_DXT5: + IsCompressionAllowed=true; + break; + case WW3D_FORMAT_U8V8: // Bumpmap + case WW3D_FORMAT_L6V5U5: // Bumpmap + case WW3D_FORMAT_X8L8V8U8: // Bumpmap + // If requesting bumpmap format that isn't available we'll just return the surface in whatever color + // format the texture file is in. (This is illegal case, the format support should always be queried + // before creating a bump texture!) + if (!DX8Wrapper::Is_Initted() || !DX8Wrapper::Get_Current_Caps()->Support_Texture_Format(TextureFormat)) + { + TextureFormat=WW3D_FORMAT_UNKNOWN; + } + // If bump format is valid, make sure compression is not allowed so that we don't even attempt to load + // from a compressed file (quality isn't good enough for bump map). Also disable mipmapping. + else + { + IsCompressionAllowed=false; + MipLevelCount=MIP_LEVELS_1; + Filter.Set_Mip_Mapping(TextureFilterClass::FILTER_TYPE_NONE); + } + break; + default: break; + } + + WWASSERT_PRINT(name && name[0], "TextureClass CTor: NULL or empty texture name"); + int len=strlen(name); + for (int i=0;iGet_Original_Texture_Width(); + Height=thumb->Get_Original_Texture_Height(); + if (MipLevelCount!=MIP_LEVELS_1) { + MipLevelCount=(MipCountType)thumb->Get_Original_Texture_Mip_Level_Count(); + } + } + + LastAccessed=WW3D::Get_Sync_Time(); + + // If the thumbnails are not enabled, init the texture at this point to avoid stalling when the + // mesh is rendered. + if (!WW3D::Get_Thumbnail_Enabled()) + { + if (TextureLoader::Is_DX8_Thread()) + { + Init(); + } + } +} + +// don't know if these are needed +#if 0 +// ---------------------------------------------------------------------------- +CubeTextureClass::CubeTextureClass +( + SurfaceClass *surface, + MipCountType mip_level_count +) +: TextureClass(0,0,mip_level_count, POOL_MANAGED, false, surface->Get_Surface_Format()) +{ + IsProcedural=true; + Initialized=true; + IsReducible=false; + + SurfaceClass::SurfaceDescription sd; + surface->Get_Description(sd); + Width=sd.Width; + Height=sd.Height; + switch (sd.Format) + { + case WW3D_FORMAT_DXT1: + case WW3D_FORMAT_DXT2: + case WW3D_FORMAT_DXT3: + case WW3D_FORMAT_DXT4: + case WW3D_FORMAT_DXT5: + IsCompressionAllowed=true; + break; + default: break; + } + + Poke_Texture + ( + DX8Wrapper::_Create_DX8_Cube_Texture + ( + surface->Peek_D3D_Surface(), + mip_level_count + ) + ); + LastAccessed=WW3D::Get_Sync_Time(); +} + +// ---------------------------------------------------------------------------- +CubeTextureClass::CubeTextureClass(IDirect3DBaseTexture8* d3d_texture) +: TextureBaseClass + ( + 0, + 0, + ((MipCountType)d3d_texture->GetLevelCount()) + ), + Filter((MipCountType)d3d_texture->GetLevelCount()) +{ + Initialized=true; + IsProcedural=true; + IsReducible=false; - if (no_lod) - { - newtex->Get_Filter().Set_Mip_Mapping(TextureFilterClass::FILTER_TYPE_NONE); - } - bool u_clamp = ((texinfo.Attributes & W3DTEXTURE_CLAMP_U) != 0); - newtex->Get_Filter().Set_U_Addr_Mode(u_clamp ? TextureFilterClass::TEXTURE_ADDRESS_CLAMP : TextureFilterClass::TEXTURE_ADDRESS_REPEAT); - bool v_clamp = ((texinfo.Attributes & W3DTEXTURE_CLAMP_V) != 0); - newtex->Get_Filter().Set_V_Addr_Mode(v_clamp ? TextureFilterClass::TEXTURE_ADDRESS_CLAMP : TextureFilterClass::TEXTURE_ADDRESS_REPEAT); + Peek_Texture()->AddRef(); + IDirect3DSurface8* surface; + DX8_ErrorCode(Peek_D3D_Texture()->GetSurfaceLevel(0,&surface)); + D3DSURFACE_DESC d3d_desc; + ::ZeroMemory(&d3d_desc, sizeof(D3DSURFACE_DESC)); + DX8_ErrorCode(surface->GetDesc(&d3d_desc)); + Width=d3d_desc.Width; + Height=d3d_desc.Height; + TextureFormat=D3DFormat_To_WW3DFormat(d3d_desc.Format); + switch (TextureFormat) + { + case WW3D_FORMAT_DXT1: + case WW3D_FORMAT_DXT2: + case WW3D_FORMAT_DXT3: + case WW3D_FORMAT_DXT4: + case WW3D_FORMAT_DXT5: + IsCompressionAllowed=true; + break; + default: break; + } - switch (texinfo.Attributes & W3DTEXTURE_TYPE_MASK) - { + LastAccessed=WW3D::Get_Sync_Time(); +} +#endif - case W3DTEXTURE_TYPE_COLORMAP: - // Do nothing. - break; +//********************************************************************************************** +//! Apply new surface to texture +/*! +*/ +void CubeTextureClass::Apply_New_Surface +( + IDirect3DBaseTexture8* d3d_texture, + bool initialized, + bool disable_auto_invalidation +) +{ + IDirect3DBaseTexture8* d3d_tex=Peek_D3D_Base_Texture(); - case W3DTEXTURE_TYPE_BUMPMAP: - { - TextureClass *releasetex = newtex; + if (d3d_tex) d3d_tex->Release(); - // Format is assumed to be a grayscale heightmap. Convert it to a bump map. - newtex = WW3DAssetManager::Get_Instance()->Get_Bumpmap_Based_On_Texture (newtex); - WW3DAssetManager::Get_Instance()->Release_Texture (releasetex); - break; - } + Poke_Texture(d3d_texture);//TextureLoadTask->Peek_D3D_Texture(); + d3d_texture->AddRef(); - default: - WWASSERT (false); - break; - } + if (initialized) Initialized=true; + if (disable_auto_invalidation) InactivationTime = 0; - } else { - newtex = WW3DAssetManager::Get_Instance()->Get_Texture(name); - } + WWASSERT(d3d_texture); + D3DSURFACE_DESC d3d_desc; + ::ZeroMemory(&d3d_desc, sizeof(D3DSURFACE_DESC)); + DX8_ErrorCode(Peek_D3D_CubeTexture()->GetLevelDesc(0,&d3d_desc)); - WWASSERT(newtex); + if (initialized) + { + TextureFormat=D3DFormat_To_WW3DFormat(d3d_desc.Format); + Width=d3d_desc.Width; + Height=d3d_desc.Height; } - - // Return a pointer to the new texture - return newtex; } -// Utility function used by Save_Texture -void setup_texture_attributes(TextureClass * tex, W3dTextureInfoStruct * texinfo) + +/************************************************************************* +** VolumeTextureClass +*************************************************************************/ +VolumeTextureClass::VolumeTextureClass +( + unsigned width, + unsigned height, + unsigned depth, + WW3DFormat format, + MipCountType mip_level_count, + PoolType pool, + bool rendertarget, + bool allow_reduction +) +: TextureClass(width, height, format, mip_level_count, pool, rendertarget), + Depth(depth) { - texinfo->Attributes = 0; + Initialized=true; + IsProcedural=true; + IsReducible=false; - if (tex->Get_Filter().Get_Mip_Mapping() == TextureFilterClass::FILTER_TYPE_NONE) texinfo->Attributes |= W3DTEXTURE_NO_LOD; - if (tex->Get_Filter().Get_U_Addr_Mode() == TextureFilterClass::TEXTURE_ADDRESS_CLAMP) texinfo->Attributes |= W3DTEXTURE_CLAMP_U; - if (tex->Get_Filter().Get_V_Addr_Mode() == TextureFilterClass::TEXTURE_ADDRESS_CLAMP) texinfo->Attributes |= W3DTEXTURE_CLAMP_V; + switch (format) + { + case WW3D_FORMAT_DXT1: + case WW3D_FORMAT_DXT2: + case WW3D_FORMAT_DXT3: + case WW3D_FORMAT_DXT4: + case WW3D_FORMAT_DXT5: + IsCompressionAllowed=true; + break; + default : break; + } + + D3DPOOL d3dpool=(D3DPOOL)0; + switch(pool) + { + case POOL_DEFAULT : d3dpool=D3DPOOL_DEFAULT; break; + case POOL_MANAGED : d3dpool=D3DPOOL_MANAGED; break; + case POOL_SYSTEMMEM : d3dpool=D3DPOOL_SYSTEMMEM; break; + default: WWASSERT(0); + } + + Poke_Texture + ( + DX8Wrapper::_Create_DX8_Volume_Texture + ( + width, + height, + depth, + format, + mip_level_count, + d3dpool + ) + ); + + if (pool==POOL_DEFAULT) + { + Set_Dirty(); + DX8TextureTrackerClass *track=new DX8TextureTrackerClass + ( + width, + height, + format, + mip_level_count, + this, + rendertarget + ); + DX8TextureManagerClass::Add(track); + } + LastAccessed=WW3D::Get_Sync_Time(); } -void Save_Texture(TextureClass * texture,ChunkSaveClass & csave) + +// ---------------------------------------------------------------------------- +VolumeTextureClass::VolumeTextureClass +( + const char *name, + const char *full_path, + MipCountType mip_level_count, + WW3DFormat texture_format, + bool allow_compression, + bool allow_reduction +) +: TextureClass(0,0,mip_level_count, POOL_MANAGED, false, texture_format), + Depth(0) { - const char * filename; - W3dTextureInfoStruct texinfo; - memset(&texinfo,0,sizeof(texinfo)); + IsCompressionAllowed=allow_compression; + InactivationTime=DEFAULT_INACTIVATION_TIME; // Default inactivation time 30 seconds - filename = texture->Get_Full_Path(); + switch (TextureFormat) + { + case WW3D_FORMAT_DXT1: + case WW3D_FORMAT_DXT2: + case WW3D_FORMAT_DXT3: + case WW3D_FORMAT_DXT4: + case WW3D_FORMAT_DXT5: + IsCompressionAllowed=true; + break; + case WW3D_FORMAT_U8V8: // Bumpmap + case WW3D_FORMAT_L6V5U5: // Bumpmap + case WW3D_FORMAT_X8L8V8U8: // Bumpmap + // If requesting bumpmap format that isn't available we'll just return the surface in whatever color + // format the texture file is in. (This is illegal case, the format support should always be queried + // before creating a bump texture!) + if (!DX8Wrapper::Is_Initted() || !DX8Wrapper::Get_Current_Caps()->Support_Texture_Format(TextureFormat)) + { + TextureFormat=WW3D_FORMAT_UNKNOWN; + } + // If bump format is valid, make sure compression is not allowed so that we don't even attempt to load + // from a compressed file (quality isn't good enough for bump map). Also disable mipmapping. + else + { + IsCompressionAllowed=false; + MipLevelCount=MIP_LEVELS_1; + Filter.Set_Mip_Mapping(TextureFilterClass::FILTER_TYPE_NONE); + } + break; + default: break; + } - setup_texture_attributes(texture, &texinfo); + WWASSERT_PRINT(name && name[0], "TextureClass CTor: NULL or empty texture name"); + int len=strlen(name); + for (int i=0;iGet_Original_Texture_Width(); + Height=thumb->Get_Original_Texture_Height(); + if (MipLevelCount!=MIP_LEVELS_1) { + MipLevelCount=(MipCountType)thumb->Get_Original_Texture_Mip_Level_Count(); + } + } + + LastAccessed=WW3D::Get_Sync_Time(); + + // If the thumbnails are not enabled, init the texture at this point to avoid stalling when the + // mesh is rendered. + if (!WW3D::Get_Thumbnail_Enabled()) + { + if (TextureLoader::Is_DX8_Thread()) + { + Init(); + } } } +// don't know if these are needed +#if 0 // ---------------------------------------------------------------------------- - -BumpmapTextureClass::BumpmapTextureClass(TextureClass* texture) - : -// TextureClass(texture->Get_Width(),texture->Get_Height(),texture->Get_Textur4e_Format(),MIP_LEVELS_1) - TextureClass(TextureLoader::Generate_Bumpmap(texture)) +CubeTextureClass::CubeTextureClass +( + SurfaceClass *surface, + MipCountType mip_level_count +) +: TextureClass(0,0,mip_level_count, POOL_MANAGED, false, surface->Get_Surface_Format()) { -// D3DTexture=TextureLoader::Generate_Bumpmap(texture); -// TextureLoader:::Generage_Bumpmap + IsProcedural=true; + Initialized=true; + IsReducible=false; + + SurfaceClass::SurfaceDescription sd; + surface->Get_Description(sd); + Width=sd.Width; + Height=sd.Height; + switch (sd.Format) + { + case WW3D_FORMAT_DXT1: + case WW3D_FORMAT_DXT2: + case WW3D_FORMAT_DXT3: + case WW3D_FORMAT_DXT4: + case WW3D_FORMAT_DXT5: + IsCompressionAllowed=true; + break; + default: break; + } + + Poke_Texture + ( + DX8Wrapper::_Create_DX8_Cube_Texture + ( + surface->Peek_D3D_Surface(), + mip_level_count + ) + ); + LastAccessed=WW3D::Get_Sync_Time(); } -BumpmapTextureClass::~BumpmapTextureClass() +// ---------------------------------------------------------------------------- +CubeTextureClass::CubeTextureClass(IDirect3DBaseTexture8* d3d_texture) +: TextureBaseClass + ( + 0, + 0, + ((MipCountType)d3d_texture->GetLevelCount()) + ), + Filter((MipCountType)d3d_texture->GetLevelCount()) { + Initialized=true; + IsProcedural=true; + IsReducible=false; + + Peek_Texture()->AddRef(); + IDirect3DSurface8* surface; + DX8_ErrorCode(Peek_D3D_Texture()->GetSurfaceLevel(0,&surface)); + D3DSURFACE_DESC d3d_desc; + ::ZeroMemory(&d3d_desc, sizeof(D3DSURFACE_DESC)); + DX8_ErrorCode(surface->GetDesc(&d3d_desc)); + Width=d3d_desc.Width; + Height=d3d_desc.Height; + TextureFormat=D3DFormat_To_WW3DFormat(d3d_desc.Format); + switch (TextureFormat) + { + case WW3D_FORMAT_DXT1: + case WW3D_FORMAT_DXT2: + case WW3D_FORMAT_DXT3: + case WW3D_FORMAT_DXT4: + case WW3D_FORMAT_DXT5: + IsCompressionAllowed=true; + break; + default: break; + } + + LastAccessed=WW3D::Get_Sync_Time(); } +#endif + + + + +//********************************************************************************************** +//! Apply new surface to texture +/*! +*/ +void VolumeTextureClass::Apply_New_Surface +( + IDirect3DBaseTexture8* d3d_texture, + bool initialized, + bool disable_auto_invalidation +) +{ + IDirect3DBaseTexture8* d3d_tex=Peek_D3D_Base_Texture(); + + if (d3d_tex) d3d_tex->Release(); + + Poke_Texture(d3d_texture);//TextureLoadTask->Peek_D3D_Texture(); + d3d_texture->AddRef(); + + if (initialized) Initialized=true; + if (disable_auto_invalidation) InactivationTime = 0; + WWASSERT(d3d_texture); + D3DVOLUME_DESC d3d_desc; + ::ZeroMemory(&d3d_desc, sizeof(D3DVOLUME_DESC)); + + DX8_ErrorCode(Peek_D3D_VolumeTexture()->GetLevelDesc(0,&d3d_desc)); + + if (initialized) + { + TextureFormat=D3DFormat_To_WW3DFormat(d3d_desc.Format); + Width=d3d_desc.Width; + Height=d3d_desc.Height; + Depth=d3d_desc.Depth; + } +} diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/texture.h b/Generals/Code/Libraries/Source/WWVegas/WW3D2/texture.h index 2efaef8a16d..47eff85d7fb 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/texture.h +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/texture.h @@ -24,12 +24,17 @@ * * * $Archive:: /Commando/Code/ww3d2/texture.h $* * * - * $Author:: Jani_p $* + * $Org Author:: Jani_p $* * * - * $Modtime:: 8/17/01 9:41a $* + * Author : Kenny Mitchell * * * - * $Revision:: 35 $* + * $Modtime:: 08/05/02 1:27p $* * * + * $Revision:: 46 $* + * * + * 05/16/02 KM Base texture class to abstract major texture types, e.g. 3d, z, cube, etc. + * 06/27/02 KM Texture class abstraction * + * 08/05/02 KM Texture class redesign (revisited) *---------------------------------------------------------------------------------------------* * Functions: * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -41,219 +46,430 @@ #include "surfaceclass.h" #include "ww3dformat.h" #include "wwstring.h" +#include "vector3.h" #include "texturefilter.h" struct IDirect3DBaseTexture8; struct IDirect3DTexture8; +struct IDirect3DCubeTexture8; +struct IDirect3DVolumeTexture8; class DX8Wrapper; class TextureLoader; class LoaderThreadClass; -class DX8TextureManagerClass; class TextureLoadTaskClass; +class CubeTextureClass; +class VolumeTextureClass; -/************************************************************************* -** TextureClass -** -** This is our texture class. For legacy reasons it contains some -** information beyond the D3D texture itself, such as texture addressing -** modes. -** -*************************************************************************/ -class TextureClass : public W3DMPO, public RefCountClass +class TextureBaseClass : public RefCountClass { - W3DMPO_GLUE(TextureClass) - + friend class TextureLoader; + friend class LoaderThreadClass; friend class DX8TextureTrackerClass; //(gth) so it can call Poke_Texture, + friend class DX8ZTextureTrackerClass; + +public: + + enum PoolType + { + POOL_DEFAULT=0, + POOL_MANAGED, + POOL_SYSTEMMEM + }; + + enum TexAssetType + { + TEX_REGULAR, + TEX_CUBEMAP, + TEX_VOLUME + }; + + // base constructor for derived classes + TextureBaseClass + ( + unsigned width, + unsigned height, + MipCountType mip_level_count=MIP_LEVELS_ALL, + PoolType pool=POOL_MANAGED, + bool rendertarget=false, + bool reducible=true + ); + + virtual ~TextureBaseClass(); + + virtual TexAssetType Get_Asset_Type() const=0; + + // Names + void Set_Texture_Name(const char * name); + void Set_Full_Path(const char * path) { FullPath = path; } + const StringClass& Get_Texture_Name(void) const { return Name; } + const StringClass& Get_Full_Path(void) const { if (FullPath.Is_Empty ()) return Name; return FullPath; } + + unsigned Get_ID() const { return texture_id; } // Each textrure has a unique id + + // The number of Mip levels in the texture + unsigned int Get_Mip_Level_Count(void) const + { + return MipLevelCount; + } + + // Note! Width and Height may be zero and may change if texture uses mipmaps + int Get_Width() const + { + return Width; + } + int Get_Height() const + { + return Height; + } + + // Time, after which the texture is invalidated if not used. Set to zero to indicate infinite. + // Time is in milliseconds. + void Set_Inactivation_Time(unsigned time) { InactivationTime=time; } + int Get_Inactivation_Time() const { return InactivationTime; } + + // Texture priority affects texture management and caching. + unsigned int Get_Priority(void); + unsigned int Set_Priority(unsigned int priority); // Returns previous priority + + // Debug utility functions for returning the texture memory usage + virtual unsigned Get_Texture_Memory_Usage() const=0; + + bool Is_Initialized() const { return Initialized; } + bool Is_Lightmap() const { return IsLightmap; } + bool Is_Procedural() const { return IsProcedural; } + bool Is_Reducible() const { return IsReducible; } //can texture be reduced in resolution for LOD purposes? + + static int _Get_Total_Locked_Surface_Size(); + static int _Get_Total_Texture_Size(); + static int _Get_Total_Lightmap_Texture_Size(); + static int _Get_Total_Procedural_Texture_Size(); + static int _Get_Total_Locked_Surface_Count(); + static int _Get_Total_Texture_Count(); + static int _Get_Total_Lightmap_Texture_Count(); + static int _Get_Total_Procedural_Texture_Count(); + + virtual void Init()=0; + + // This utility function processes the texture reduction (used during rendering) + void Invalidate(); + + // texture accessors (dx8) + IDirect3DBaseTexture8 *Peek_D3D_Base_Texture() const; + void Set_D3D_Base_Texture(IDirect3DBaseTexture8* tex); + + PoolType Get_Pool() const { return Pool; } + + bool Is_Missing_Texture(); - friend DX8Wrapper; - friend TextureLoader; - friend LoaderThreadClass; - friend DX8TextureManagerClass; - - public: - - enum PoolType { - POOL_DEFAULT=0, - POOL_MANAGED, - POOL_SYSTEMMEM - }; - - enum TexAssetType - { - TEX_REGULAR, - }; - - // Create texture with desired height, width and format. - TextureClass( - unsigned width, - unsigned height, - WW3DFormat format, - MipCountType mip_level_count=MIP_LEVELS_ALL, - PoolType pool=POOL_MANAGED, - bool rendertarget=false); - - // Create texture from a file. If format is specified the texture is converted to that format. - // Note that the format must be supported by the current device and that a texture can't exist - // in the system with the same name in multiple formats. - TextureClass( - const char *name, - const char *full_path=NULL, - MipCountType mip_level_count=MIP_LEVELS_ALL, - WW3DFormat texture_format=WW3D_FORMAT_UNKNOWN, - bool allow_compression=true); + // Support for self managed textures + bool Is_Dirty() { WWASSERT(Pool==POOL_DEFAULT); return Dirty; }; + void Set_Dirty() { WWASSERT(Pool==POOL_DEFAULT); Dirty=true; } + void Clean() { Dirty=false; }; - // Create texture from a surface. - TextureClass( - SurfaceClass *surface, - MipCountType mip_level_count=MIP_LEVELS_ALL); + void Set_HSV_Shift(const Vector3 &hsv_shift); + const Vector3& Get_HSV_Shift() { return HSVShift; } - TextureClass(IDirect3DTexture8* d3d_texture); - - virtual TexAssetType Get_Asset_Type() const { return TEX_REGULAR; } + bool Is_Compression_Allowed() const { return IsCompressionAllowed; } - virtual ~TextureClass(void); + unsigned Get_Reduction() const; - // Names - void Set_Texture_Name(const char * name); - void Set_Full_Path(const char * path) { FullPath = path; } - const StringClass& Get_Texture_Name(void) const { return Name; } - const StringClass& Get_Full_Path(void) const { if (FullPath.Is_Empty ()) return Name; return FullPath; } + // Background texture loader will call this when texture has been loaded + virtual void Apply_New_Surface(IDirect3DBaseTexture8* tex, bool initialized, bool disable_auto_invalidation = false)=0; // If the parameter is true, the texture will be flagged as initialised - unsigned Get_ID() const { return texture_id; } // Each textrure has a unique id - - // The number of Mip levels in the texture - unsigned int Get_Mip_Level_Count(void); - - // Note! Width and Height may be zero and may change if texture uses mipmaps - int Get_Width() const - { - return Width; - } - int Get_Height() const - { - return Height; - } + MipCountType MipLevelCount; - // Get surface description of a Mip level (defaults to the highest-resolution one) - void Get_Level_Description(SurfaceClass::SurfaceDescription &surface_desc, unsigned int level = 0); + // Inactivate textures that haven't been used in a while. Pass zero to use textures' + // own inactive times (default). In urgent need to free up texture memory, try + // calling with relatively small (just few seconds) time override to free up everything + // but the currently used textures. + static void Invalidate_Old_Unused_Textures(unsigned inactive_time_override); - TextureFilterClass& Get_Filter() { return Filter; } + // Apply this texture's settings into D3D + virtual void Apply(unsigned int stage)=0; - // Get the surface of one of the mipmap levels (defaults to highest-resolution one) - SurfaceClass *Get_Surface_Level(unsigned int level = 0); + // Apply a Null texture's settings into D3D + static void Apply_Null(unsigned int stage); - // Texture priority affects texture management and caching. - unsigned int Get_Priority(void); - unsigned int Set_Priority(unsigned int priority); // Returns previous priority + virtual TextureClass* As_TextureClass() { return NULL; } + virtual CubeTextureClass* As_CubeTextureClass() { return NULL; } + virtual VolumeTextureClass* As_VolumeTextureClass() { return NULL; } - // Debug utility functions for returning the texture memory usage - unsigned Get_Texture_Memory_Usage() const; - bool Is_Initialized() const { return Initialized; } - bool Is_Lightmap() const { return IsLightmap; } - bool Is_Procedural() const { return IsProcedural; } + IDirect3DTexture8* Peek_D3D_Texture() const { return (IDirect3DTexture8*)Peek_D3D_Base_Texture(); } + IDirect3DVolumeTexture8* Peek_D3D_VolumeTexture() const { return (IDirect3DVolumeTexture8*)Peek_D3D_Base_Texture(); } + IDirect3DCubeTexture8* Peek_D3D_CubeTexture() const { return (IDirect3DCubeTexture8*)Peek_D3D_Base_Texture(); } - static int _Get_Total_Locked_Surface_Size(); - static int _Get_Total_Texture_Size(); - static int _Get_Total_Lightmap_Texture_Size(); - static int _Get_Total_Procedural_Texture_Size(); - static int _Get_Total_Locked_Surface_Count(); - static int _Get_Total_Texture_Count(); - static int _Get_Total_Lightmap_Texture_Count(); - static int _Get_Total_Procedural_Texture_Count(); +protected: - static void _Set_Default_Min_Filter(TextureFilterClass::FilterType filter); - static void _Set_Default_Mag_Filter(TextureFilterClass::FilterType filter); - static void _Set_Default_Mip_Filter(TextureFilterClass::FilterType filter); + void Load_Locked_Surface(); + void Poke_Texture(IDirect3DBaseTexture8* tex) { D3DTexture = tex; } - // This utility function processes the texture reduction (used during rendering) - void Invalidate(); + bool Initialized; - IDirect3DTexture8 *Peek_D3D_Texture() const { return (IDirect3DTexture8 *)Peek_D3D_Base_Texture(); } + // For debug purposes the texture sets this true if it is a lightmap texture + bool IsLightmap; + bool IsCompressionAllowed; + bool IsProcedural; + bool IsReducible; - // texture accessors (dx8) - IDirect3DBaseTexture8 *Peek_D3D_Base_Texture() const; - void Set_D3D_Base_Texture(IDirect3DBaseTexture8* tex); - - PoolType Get_Pool() const { return Pool; } - bool Is_Missing_Texture(); + unsigned InactivationTime; // In milliseconds + unsigned ExtendedInactivationTime; // This is set by the engine, if needed + unsigned LastInactivationSyncTime; + mutable unsigned LastAccessed; - // Support for self managed textures - bool Is_Dirty() { WWASSERT(Pool==POOL_DEFAULT); return Dirty; }; - void Set_Dirty() { WWASSERT(Pool==POOL_DEFAULT); Dirty=true; } - void Clean() { Dirty=false; }; + // If this is non-zero, the texture will have a hue shift done at the next init (this + // value should only be changed by Set_HSV_Shift() function, which also invalidates the + // texture). + Vector3 HSVShift; - unsigned Get_Reduction() const; - WW3DFormat Get_Texture_Format() const { return TextureFormat; } - bool Is_Compression_Allowed() const { return IsCompressionAllowed; } + int Width; + int Height; - protected: - void Poke_Texture(IDirect3DBaseTexture8* tex) { D3DTexture = tex; } +private: - // Apply this texture's settings into D3D - virtual void Apply(unsigned int stage); - void Load_Locked_Surface(); + // Direct3D texture object + IDirect3DBaseTexture8 *D3DTexture; - void Init(); + // Name + StringClass Name; + StringClass FullPath; - // Apply a Null texture's settings into D3D - static void Apply_Null(unsigned int stage); + // Unique id + unsigned texture_id; - // State not contained in the Direct3D texture object: - TextureFilterClass Filter; + // Support for self-managed textures - // Direct3D texture object - IDirect3DBaseTexture8 *D3DTexture; - bool Initialized; + PoolType Pool; + bool Dirty; - // Name - StringClass Name; - StringClass FullPath; + friend class TextureLoadTaskClass; + friend class CubeTextureLoadTaskClass; + friend class VolumeTextureLoadTaskClass; + TextureLoadTaskClass* TextureLoadTask; + TextureLoadTaskClass* ThumbnailLoadTask; - // Unique id - unsigned texture_id; +}; - // NOTE: Since "texture wrapping" (NOT TEXTURE WRAP MODE - THIS IS - // SOMETHING ELSE) is a global state that affects all texture stages, - // and this class only affects its own stage, we will not worry about - // it for now. Later (probably when we implement world-oriented - // environment maps) we will consider where to put it. - // For debug purposes the texture sets this true if it is a lightmap texture - bool IsLightmap; - bool IsProcedural; - bool IsCompressionAllowed; +/************************************************************************* +** TextureClass +** +** This is our regular texture class. For legacy reasons it contains some +** information beyond the D3D texture itself, such as texture addressing +** modes. +** +*************************************************************************/ +class TextureClass : public TextureBaseClass +{ + W3DMPO_GLUE(TextureClass) +// friend DX8Wrapper; - mutable unsigned LastAccessed; - WW3DFormat TextureFormat; +public: - int Width; - int Height; + // Create texture with desired height, width and format. + TextureClass + ( + unsigned width, + unsigned height, + WW3DFormat format, + MipCountType mip_level_count=MIP_LEVELS_ALL, + PoolType pool=POOL_MANAGED, + bool rendertarget=false, + bool allow_reduction=true + ); + + // Create texture from a file. If format is specified the texture is converted to that format. + // Note that the format must be supported by the current device and that a texture can't exist + // in the system with the same name in multiple formats. + TextureClass + ( + const char *name, + const char *full_path=NULL, + MipCountType mip_level_count=MIP_LEVELS_ALL, + WW3DFormat texture_format=WW3D_FORMAT_UNKNOWN, + bool allow_compression=true, + bool allow_reduction=true + ); + + // Create texture from a surface. + TextureClass + ( + SurfaceClass *surface, + MipCountType mip_level_count=MIP_LEVELS_ALL + ); + + TextureClass(IDirect3DBaseTexture8* d3d_texture); + + // defualt constructors for derived classes (cube & vol) + TextureClass + ( + unsigned width, + unsigned height, + MipCountType mip_level_count=MIP_LEVELS_ALL, + PoolType pool=POOL_MANAGED, + bool rendertarget=false, + WW3DFormat format=WW3D_FORMAT_UNKNOWN, + bool allow_reduction=true + ) + : TextureBaseClass(width,height,mip_level_count,pool,rendertarget,allow_reduction), TextureFormat(format), Filter(mip_level_count) { } + + virtual TexAssetType Get_Asset_Type() const { return TEX_REGULAR; } + + virtual void Init(); + + // Background texture loader will call this when texture has been loaded + virtual void Apply_New_Surface(IDirect3DBaseTexture8* tex, bool initialized, bool disable_auto_invalidation = false); // If the parameter is true, the texture will be flagged as initialised + + // Get the surface of one of the mipmap levels (defaults to highest-resolution one) + SurfaceClass *Get_Surface_Level(unsigned int level = 0); + IDirect3DSurface8 *Get_D3D_Surface_Level(unsigned int level = 0); + void Get_Level_Description( SurfaceClass::SurfaceDescription & desc, unsigned int level = 0 ); + + TextureFilterClass& Get_Filter() { return Filter; } + + WW3DFormat Get_Texture_Format() const { return TextureFormat; } + + virtual void Apply(unsigned int stage); + + virtual unsigned Get_Texture_Memory_Usage() const; + + virtual TextureClass* As_TextureClass() { return this; } + +protected: + + WW3DFormat TextureFormat; + + // legacy + TextureFilterClass Filter; +}; - // Support for self-managed textures +class ZTextureClass : public TextureBaseClass +{ +public: + // Create a z texture with desired height, width and format + ZTextureClass + ( + unsigned width, + unsigned height, + WW3DZFormat zformat, + MipCountType mip_level_count=MIP_LEVELS_ALL, + PoolType pool=POOL_MANAGED + ); + + WW3DZFormat Get_Texture_Format() const { return DepthStencilTextureFormat; } + + virtual TexAssetType Get_Asset_Type() const { return TEX_REGULAR; } + + virtual void Init() {} + + // Background texture loader will call this when texture has been loaded + virtual void Apply_New_Surface(IDirect3DBaseTexture8* tex, bool initialized, bool disable_auto_invalidation = false); // If the parameter is true, the texture will be flagged as initialised + + virtual void Apply(unsigned int stage); - PoolType Pool; - bool Dirty; + IDirect3DSurface8 *Get_D3D_Surface_Level(unsigned int level = 0); + virtual unsigned Get_Texture_Memory_Usage() const; + +private: + + WW3DZFormat DepthStencilTextureFormat; +}; + +class CubeTextureClass : public TextureClass +{ public: - MipCountType MipLevelCount; - TextureLoadTaskClass* TextureLoadTask; - // Background texture loader will call this when texture has been loaded - void Apply_New_Surface(bool initialized); // If the parameter is true, the texture will be flagged as initialised + // Create texture with desired height, width and format. + CubeTextureClass + ( + unsigned width, + unsigned height, + WW3DFormat format, + MipCountType mip_level_count=MIP_LEVELS_ALL, + PoolType pool=POOL_MANAGED, + bool rendertarget=false, + bool allow_reduction=true + ); + + // Create texture from a file. If format is specified the texture is converted to that format. + // Note that the format must be supported by the current device and that a texture can't exist + // in the system with the same name in multiple formats. + CubeTextureClass + ( + const char *name, + const char *full_path=NULL, + MipCountType mip_level_count=MIP_LEVELS_ALL, + WW3DFormat texture_format=WW3D_FORMAT_UNKNOWN, + bool allow_compression=true, + bool allow_reduction=true + ); + + // Create texture from a surface. + CubeTextureClass + ( + SurfaceClass *surface, + MipCountType mip_level_count=MIP_LEVELS_ALL + ); + + CubeTextureClass(IDirect3DBaseTexture8* d3d_texture); + + virtual void Apply_New_Surface(IDirect3DBaseTexture8* tex, bool initialized, bool disable_auto_invalidation = false); // If the parameter is true, the texture will be flagged as initialised + + virtual TexAssetType Get_Asset_Type() const { return TEX_CUBEMAP; } + + virtual CubeTextureClass* As_CubeTextureClass() { return this; } }; -class BumpmapTextureClass : public TextureClass +class VolumeTextureClass : public TextureClass { public: - // Generate bumpmap texture procedurally from the source texture - BumpmapTextureClass(TextureClass* texture); - virtual ~BumpmapTextureClass(); + // Create texture with desired height, width and format. + VolumeTextureClass + ( + unsigned width, + unsigned height, + unsigned depth, + WW3DFormat format, + MipCountType mip_level_count=MIP_LEVELS_ALL, + PoolType pool=POOL_MANAGED, + bool rendertarget=false, + bool allow_reduction=true + ); + + // Create texture from a file. If format is specified the texture is converted to that format. + // Note that the format must be supported by the current device and that a texture can't exist + // in the system with the same name in multiple formats. + VolumeTextureClass + ( + const char *name, + const char *full_path=NULL, + MipCountType mip_level_count=MIP_LEVELS_ALL, + WW3DFormat texture_format=WW3D_FORMAT_UNKNOWN, + bool allow_compression=true, + bool allow_reduction=true + ); + + // Create texture from a surface. + VolumeTextureClass + ( + SurfaceClass *surface, + MipCountType mip_level_count=MIP_LEVELS_ALL + ); + + VolumeTextureClass(IDirect3DBaseTexture8* d3d_texture); + + virtual void Apply_New_Surface(IDirect3DBaseTexture8* tex, bool initialized, bool disable_auto_invalidation = false); // If the parameter is true, the texture will be flagged as initialised + + virtual TexAssetType Get_Asset_Type() const { return TEX_VOLUME; } + + virtual VolumeTextureClass* As_VolumeTextureClass() { return this; } + +protected: + + int Depth; }; // Utility functions for loading and saving texture descriptions from/to W3D files TextureClass *Load_Texture(ChunkLoadClass & cload); void Save_Texture(TextureClass * texture, ChunkSaveClass & csave); - -// TheSuperHackers @todo TextureBaseClass abstraction -typedef TextureClass TextureBaseClass; diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/texturefilter.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/texturefilter.cpp index 6ccbabc5c3c..690faf2ef46 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/texturefilter.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/texturefilter.cpp @@ -1,5 +1,5 @@ /* -** Command & Conquer Generals Zero Hour(tm) +** Command & Conquer Generals(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify @@ -39,11 +39,10 @@ #include "texturefilter.h" #include "dx8wrapper.h" -#include "meshmatdesc.h" -unsigned _MinTextureFilters[TextureFilterClass::FILTER_TYPE_COUNT]; -unsigned _MagTextureFilters[TextureFilterClass::FILTER_TYPE_COUNT]; -unsigned _MipMapFilters[TextureFilterClass::FILTER_TYPE_COUNT]; +unsigned _MinTextureFilters[MAX_TEXTURE_STAGES][TextureFilterClass::FILTER_TYPE_COUNT]; +unsigned _MagTextureFilters[MAX_TEXTURE_STAGES][TextureFilterClass::FILTER_TYPE_COUNT]; +unsigned _MipMapFilters[MAX_TEXTURE_STAGES][TextureFilterClass::FILTER_TYPE_COUNT]; /************************************************************************* ** TextureFilterClass @@ -70,9 +69,9 @@ TextureFilterClass::TextureFilterClass(MipCountType mip_level_count) */ void TextureFilterClass::Apply(unsigned int stage) { - DX8Wrapper::Set_DX8_Texture_Stage_State(stage,D3DTSS_MINFILTER,_MinTextureFilters[TextureMinFilter]); - DX8Wrapper::Set_DX8_Texture_Stage_State(stage,D3DTSS_MAGFILTER,_MagTextureFilters[TextureMagFilter]); - DX8Wrapper::Set_DX8_Texture_Stage_State(stage,D3DTSS_MIPFILTER,_MipMapFilters[MipMapFilter]); + DX8Wrapper::Set_DX8_Texture_Stage_State(stage,D3DTSS_MINFILTER,_MinTextureFilters[stage][TextureMinFilter]); + DX8Wrapper::Set_DX8_Texture_Stage_State(stage,D3DTSS_MAGFILTER,_MagTextureFilters[stage][TextureMagFilter]); + DX8Wrapper::Set_DX8_Texture_Stage_State(stage,D3DTSS_MIPFILTER,_MipMapFilters[stage][MipMapFilter]); switch (Get_U_Addr_Mode()) { @@ -101,51 +100,102 @@ void TextureFilterClass::Apply(unsigned int stage) //! Init filters (legacy) /*! */ -void TextureFilterClass::_Init_Filters(void) +void TextureFilterClass::_Init_Filters(TextureFilterMode filter_type) { const D3DCAPS8& dx8caps=DX8Wrapper::Get_Current_Caps()->Get_DX8_Caps(); - _MinTextureFilters[FILTER_TYPE_NONE]=D3DTEXF_POINT; - _MagTextureFilters[FILTER_TYPE_NONE]=D3DTEXF_POINT; - _MipMapFilters[FILTER_TYPE_NONE]=D3DTEXF_NONE; - - _MinTextureFilters[FILTER_TYPE_FAST]=D3DTEXF_LINEAR; - _MagTextureFilters[FILTER_TYPE_FAST]=D3DTEXF_LINEAR; - _MipMapFilters[FILTER_TYPE_FAST]=D3DTEXF_POINT; - - // Jani: Disabling anisotropic filtering as it doesn't seem to work with the latest nVidia drivers. - if (dx8caps.TextureFilterCaps&D3DPTFILTERCAPS_MAGFAFLATCUBIC) _MagTextureFilters[FILTER_TYPE_BEST]=D3DTEXF_FLATCUBIC; - else if (dx8caps.TextureFilterCaps&D3DPTFILTERCAPS_MAGFANISOTROPIC) _MagTextureFilters[FILTER_TYPE_BEST]=D3DTEXF_ANISOTROPIC; - else if (dx8caps.TextureFilterCaps&D3DPTFILTERCAPS_MAGFGAUSSIANCUBIC) _MagTextureFilters[FILTER_TYPE_BEST]=D3DTEXF_GAUSSIANCUBIC; - else if (dx8caps.TextureFilterCaps&D3DPTFILTERCAPS_MAGFLINEAR) _MagTextureFilters[FILTER_TYPE_BEST]=D3DTEXF_LINEAR; - else if (dx8caps.TextureFilterCaps&D3DPTFILTERCAPS_MAGFPOINT) _MagTextureFilters[FILTER_TYPE_BEST]=D3DTEXF_POINT; - else { - WWASSERT_PRINT(0,("No magnification filter found!")); +#ifndef _XBOX + _MinTextureFilters[0][FILTER_TYPE_NONE]=D3DTEXF_POINT; + _MagTextureFilters[0][FILTER_TYPE_NONE]=D3DTEXF_POINT; + _MipMapFilters[0][FILTER_TYPE_NONE]=D3DTEXF_NONE; + + _MinTextureFilters[0][FILTER_TYPE_FAST]=D3DTEXF_LINEAR; + _MagTextureFilters[0][FILTER_TYPE_FAST]=D3DTEXF_LINEAR; + _MipMapFilters[0][FILTER_TYPE_FAST]=D3DTEXF_POINT; + + _MagTextureFilters[0][FILTER_TYPE_BEST]=D3DTEXF_POINT; + _MinTextureFilters[0][FILTER_TYPE_BEST]=D3DTEXF_POINT; + _MipMapFilters[0][FILTER_TYPE_BEST]=D3DTEXF_POINT; +#else + _MinTextureFilters[0][FILTER_TYPE_NONE]=D3DTEXF_ANISOTROPIC; + _MagTextureFilters[0][FILTER_TYPE_NONE]=D3DTEXF_ANISOTROPIC; + _MipMapFilters[0][FILTER_TYPE_NONE]=D3DTEXF_LINEAR; + + _MinTextureFilters[0][FILTER_TYPE_FAST]=D3DTEXF_ANISOTROPIC; + _MagTextureFilters[0][FILTER_TYPE_FAST]=D3DTEXF_ANISOTROPIC; + _MipMapFilters[0][FILTER_TYPE_FAST]=D3DTEXF_LINEAR; + + _MagTextureFilters[0][FILTER_TYPE_BEST]=D3DTEXF_ANISOTROPIC; + _MinTextureFilters[0][FILTER_TYPE_BEST]=D3DTEXF_ANISOTROPIC; + _MipMapFilters[0][FILTER_TYPE_BEST]=D3DTEXF_LINEAR; +#endif + +#ifndef _XBOX + if (dx8caps.TextureFilterCaps&D3DPTFILTERCAPS_MAGFLINEAR) _MagTextureFilters[0][FILTER_TYPE_BEST]=D3DTEXF_LINEAR; + if (dx8caps.TextureFilterCaps&D3DPTFILTERCAPS_MINFLINEAR) _MinTextureFilters[0][FILTER_TYPE_BEST]=D3DTEXF_LINEAR; + + // Set anisotropic filtering only if requested and available + if (filter_type==TEXTURE_FILTER_ANISOTROPIC) { + if (dx8caps.TextureFilterCaps&D3DPTFILTERCAPS_MAGFANISOTROPIC) _MagTextureFilters[0][FILTER_TYPE_BEST]=D3DTEXF_ANISOTROPIC; + if (dx8caps.TextureFilterCaps&D3DPTFILTERCAPS_MINFANISOTROPIC) _MinTextureFilters[0][FILTER_TYPE_BEST]=D3DTEXF_ANISOTROPIC; } - if (dx8caps.TextureFilterCaps&D3DPTFILTERCAPS_MINFANISOTROPIC) _MinTextureFilters[FILTER_TYPE_BEST]=D3DTEXF_ANISOTROPIC; - else if (dx8caps.TextureFilterCaps&D3DPTFILTERCAPS_MINFLINEAR) _MinTextureFilters[FILTER_TYPE_BEST]=D3DTEXF_LINEAR; - else if (dx8caps.TextureFilterCaps&D3DPTFILTERCAPS_MINFPOINT) _MinTextureFilters[FILTER_TYPE_BEST]=D3DTEXF_POINT; - else { - WWASSERT_PRINT(0,("No minification filter found!")); + // Set linear mip filter only if requested trilinear or anisotropic, and linear available + if (filter_type==TEXTURE_FILTER_ANISOTROPIC || filter_type==TEXTURE_FILTER_TRILINEAR) { + if (dx8caps.TextureFilterCaps&D3DPTFILTERCAPS_MIPFLINEAR) _MipMapFilters[0][FILTER_TYPE_BEST]=D3DTEXF_LINEAR; } +#endif + + // For stages above zero, set best filter to the same as the stage zero, except if anisotropic + int i=1; + for (;i. */ +/*********************************************************************************************** + *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** + *********************************************************************************************** + * * + * Project Name : DX8 Texture Manager * + * * + * $Archive:: /Commando/Code/ww3d2/textureloader.h $* + * * + * Original Author:: vss_sync * + * * + * Author : Kenny Mitchell * + * * + * $Modtime:: 08/05/02 10:03a $* + * * + * $Revision:: 3 $* + * * + * 06/27/02 KM Texture class abstraction * + * 08/05/02 KM Texture class redesign (revisited) + *---------------------------------------------------------------------------------------------* + * Functions: * + * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + #include "textureloader.h" #include "mutex.h" #include "thread.h" @@ -36,14 +58,225 @@ #include "texturethumbnail.h" #include "ddsfile.h" #include "bitmaphandler.h" +#include "wwprofile.h" + +bool TextureLoader::TextureLoadSuspended; +int TextureLoader::TextureInactiveOverrideTime = 0; + +#define USE_MANAGED_TEXTURES + +//////////////////////////////////////////////////////////////////////////////// +// +// TextureLoadTaskListClass implementation +// +//////////////////////////////////////////////////////////////////////////////// + +TextureLoadTaskListClass::TextureLoadTaskListClass(void) +: Root() +{ + Root.Next = Root.Prev = &Root; +} + +void TextureLoadTaskListClass::Push_Front (TextureLoadTaskClass *task) +{ + // task should non-null and not on any list + WWASSERT(task != NULL && task->Next == NULL && task->Prev == NULL); + + // update inserted task to point to list + task->Next = Root.Next; + task->Prev = &Root; + task->List = this; + + // update list to point to inserted task + Root.Next->Prev = task; + Root.Next = task; +} + +void TextureLoadTaskListClass::Push_Back(TextureLoadTaskClass *task) +{ + // task should be non-null and not on any list + WWASSERT(task != NULL && task->Next == NULL && task->Prev == NULL); + + // update inserted task to point to list + task->Next = &Root; + task->Prev = Root.Prev; + task->List = this; + + // update list to point to inserted task + Root.Prev->Next = task; + Root.Prev = task; +} + +TextureLoadTaskClass *TextureLoadTaskListClass::Pop_Front(void) +{ + // exit early if list is empty + if (Is_Empty()) { + return 0; + } + + // otherwise, grab first task and remove it. + TextureLoadTaskClass *task = (TextureLoadTaskClass *)Root.Next; + Remove(task); + return task; + +} + +TextureLoadTaskClass *TextureLoadTaskListClass::Pop_Back(void) +{ + // exit early if list is empty + if (Is_Empty()) { + return 0; + } + + // otherwise, grab last task and remove it. + TextureLoadTaskClass *task = (TextureLoadTaskClass *)Root.Prev; + Remove(task); + return task; +} + +void TextureLoadTaskListClass::Remove(TextureLoadTaskClass *task) +{ + // exit early if task is not on this list. + if (task->List != this) { + return; + } + + // update list to skip task + task->Prev->Next = task->Next; + task->Next->Prev = task->Prev; + + // update task to no longer point at list + task->Prev = 0; + task->Next = 0; + task->List = 0; +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// SynchronizedTextureLoadTaskListClass implementation +// +//////////////////////////////////////////////////////////////////////////////// + +SynchronizedTextureLoadTaskListClass::SynchronizedTextureLoadTaskListClass(void) +: TextureLoadTaskListClass(), + CriticalSection() +{ +} + +void SynchronizedTextureLoadTaskListClass::Push_Front(TextureLoadTaskClass *task) +{ + FastCriticalSectionClass::LockClass lock(CriticalSection); + TextureLoadTaskListClass::Push_Front(task); +} + +void SynchronizedTextureLoadTaskListClass::Push_Back(TextureLoadTaskClass *task) +{ + FastCriticalSectionClass::LockClass lock(CriticalSection); + TextureLoadTaskListClass::Push_Back(task); +} + +TextureLoadTaskClass *SynchronizedTextureLoadTaskListClass::Pop_Front(void) +{ + // this duplicates code inside base class, but saves us an unnecessary lock. + if (Is_Empty()) { + return 0; + } + + FastCriticalSectionClass::LockClass lock(CriticalSection); + return TextureLoadTaskListClass::Pop_Front(); + +} + +TextureLoadTaskClass *SynchronizedTextureLoadTaskListClass::Pop_Back(void) +{ + // this duplicates code inside base class, but saves us an unnecessary lock. + if (Is_Empty()) { + return 0; + } + + FastCriticalSectionClass::LockClass lock(CriticalSection); + return TextureLoadTaskListClass::Pop_Back(); +} + +void SynchronizedTextureLoadTaskListClass::Remove(TextureLoadTaskClass *task) +{ + FastCriticalSectionClass::LockClass lock(CriticalSection); + TextureLoadTaskListClass::Remove(task); +} + + +// Locks + +// To prevent deadlock, threads should acquire locks in the order in which +// they are defined below. No ordering is necessary for the task list locks, +// since one thread can never hold two at once. + +static FastCriticalSectionClass _ForegroundCriticalSection; +static FastCriticalSectionClass _BackgroundCriticalSection; + +// Lists + +static SynchronizedTextureLoadTaskListClass _ForegroundQueue; +static SynchronizedTextureLoadTaskListClass _BackgroundQueue; + +static TextureLoadTaskListClass _TexLoadFreeList; +static TextureLoadTaskListClass _CubeTexLoadFreeList; +static TextureLoadTaskListClass _VolTexLoadFreeList; + + +// The background texture loading thread. +static class LoaderThreadClass : public ThreadClass +{ +public: +#ifdef Exception_Handler + LoaderThreadClass(const char *thread_name = "Texture loader thread") : ThreadClass(thread_name, &Exception_Handler) {} +#else + LoaderThreadClass(const char *thread_name = "Texture loader thread") : ThreadClass(thread_name) {} +#endif + + void Thread_Function(); +} _TextureLoadThread; + + +// TODO: Legacy - remove this call! +IDirect3DTexture8* Load_Compressed_Texture( + const StringClass& filename, + unsigned reduction_factor, + MipCountType mip_level_count, + WW3DFormat dest_format) +{ + // If DDS file isn't available, use TGA file to convert to DDS. + + DDSFileClass dds_file(filename,reduction_factor); + if (!dds_file.Is_Available()) return NULL; + if (!dds_file.Load()) return NULL; + + unsigned width=dds_file.Get_Width(0); + unsigned height=dds_file.Get_Height(0); + unsigned mips=dds_file.Get_Mip_Level_Count(); + + // If format isn't defined get the nearest valid texture format to the compressed file format + // Note that the nearest valid format could be anything, even uncompressed. + if (dest_format==WW3D_FORMAT_UNKNOWN) dest_format=Get_Valid_Texture_Format(dds_file.Get_Format(),true); -static TextureLoadTaskClass* LoadListHead; -static TextureLoadTaskClass* DeferredListHead; -static TextureLoadTaskClass* FinishedListHead; -static TextureLoadTaskClass* ThumbnailListHead; -static TextureLoadTaskClass* DeleteTaskListHead; + IDirect3DTexture8* d3d_texture = DX8Wrapper::_Create_DX8_Texture + ( + width, + height, + dest_format, + (MipCountType)mips + ); -TextureLoadTaskClass* TextureLoadTaskClass::FreeTaskListHead; + for (unsigned level=0;levelGetSurfaceLevel(level/*-reduction_factor*/,&d3d_surface)); + dds_file.Copy_Level_To_Surface(level,d3d_surface); + d3d_surface->Release(); + } + return d3d_texture; +} static bool Is_Format_Compressed(WW3DFormat texture_format,bool allow_compression) { @@ -77,46 +310,41 @@ static bool Is_Format_Compressed(WW3DFormat texture_format,bool allow_compressio return compressed; } -// ---------------------------------------------------------------------------- - -static CriticalSectionClass mutex; -static class LoaderThreadClass : public ThreadClass -{ - TextureLoadTaskClass* Get_Task_From_Load_List(); - - static void Add_Task_To_Finished_List(TextureLoadTaskClass* task); - -public: - LoaderThreadClass() : ThreadClass() {} - - void Thread_Function(); - - static void Add_Task_To_Load_List(TextureLoadTaskClass* task); -} thread; - -// ---------------------------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// +// +// TextureLoader implementation +// +//////////////////////////////////////////////////////////////////////////////// void TextureLoader::Init() { - WWASSERT(!thread.Is_Running()); + WWASSERT(!_TextureLoadThread.Is_Running()); - ThumbnailClass::Init(); + ThumbnailManagerClass::Init(); - thread.Execute(); - thread.Set_Priority(-3); + _TextureLoadThread.Execute(); + _TextureLoadThread.Set_Priority(-4); + TextureInactiveOverrideTime = 0; } -// ---------------------------------------------------------------------------- void TextureLoader::Deinit() { - CriticalSectionClass::LockClass m(mutex); - thread.Stop(); + FastCriticalSectionClass::LockClass lock(_BackgroundCriticalSection); + _TextureLoadThread.Stop(); + + ThumbnailManagerClass::Deinit(); + TextureLoadTaskClass::Delete_Free_Pool(); +} + - ThumbnailClass::Deinit(); +bool TextureLoader::Is_DX8_Thread(void) +{ + return (ThreadClass::_Get_Current_Thread_ID() == DX8Wrapper::_Get_Main_Thread_ID()); } + // ---------------------------------------------------------------------------- // // Modify given texture size to nearest valid size on current hardware. @@ -183,42 +411,49 @@ void TextureLoader::Validate_Texture_Size depth=poweroftwodepth; } -IDirect3DTexture8* TextureLoader::Load_Thumbnail(const StringClass& filename,WW3DFormat texture_format) +IDirect3DTexture8* TextureLoader::Load_Thumbnail(const StringClass& filename, const Vector3& hsv_shift)//,WW3DFormat texture_format) { - ThumbnailClass* thumb=ThumbnailClass::Peek_Instance(filename); + WWASSERT(Is_DX8_Thread()); + + ThumbnailClass* thumb=NULL; + thumb=ThumbnailManagerClass::Peek_Thumbnail_Instance_From_Any_Manager(filename); + + // If no thumb is found return a missing texture if (!thumb) { - thumb=W3DNEW ThumbnailClass(filename); - // If load failed, return missing texture - if (!thumb->Peek_Bitmap()) { - delete thumb; - return MissingTexture::_Get_Missing_Texture(); - } + return MissingTexture::_Get_Missing_Texture(); } - unsigned src_pitch=thumb->Get_Width()*4; // Thumbs are always 32 bits + WWASSERT(thumb->Get_Format()==WW3D_FORMAT_A4R4G4B4); + unsigned src_pitch=thumb->Get_Width()*2; // Thumbs are always 16 bits WW3DFormat dest_format; + WW3DFormat texture_format=WW3D_FORMAT_UNKNOWN; if (texture_format==WW3D_FORMAT_UNKNOWN) { - dest_format=Get_Valid_Texture_Format(WW3D_FORMAT_A8R8G8B8,false); // no compressed formats please + dest_format=Get_Valid_Texture_Format(WW3D_FORMAT_A4R4G4B4,false); // no compressed formats please } else { dest_format=Get_Valid_Texture_Format(texture_format,false); // no compressed formats please WWASSERT(dest_format==texture_format); } - IDirect3DTexture8* d3d_texture = DX8Wrapper::_Create_DX8_Texture( + IDirect3DTexture8* sysmem_texture = DX8Wrapper::_Create_DX8_Texture( thumb->Get_Width(), thumb->Get_Height(), dest_format, - MIP_LEVELS_ALL); + MIP_LEVELS_ALL, +#ifdef USE_MANAGED_TEXTURES + D3DPOOL_MANAGED); +#else + D3DPOOL_SYSTEMMEM); +#endif unsigned level=0; D3DLOCKED_RECT locked_rects[12]={0}; - WWASSERT(d3d_texture->GetLevelCount()<=12); + WWASSERT(sysmem_texture->GetLevelCount()<=12); // Lock all surfaces - for (level=0;levelGetLevelCount();++level) { + for (level=0;levelGetLevelCount();++level) { DX8_ErrorCode( - d3d_texture->LockRect( + sysmem_texture->LockRect( level, &locked_rects[level], NULL, @@ -226,11 +461,12 @@ IDirect3DTexture8* TextureLoader::Load_Thumbnail(const StringClass& filename,WW3 } unsigned char* src_surface=thumb->Peek_Bitmap(); - WW3DFormat src_format=WW3D_FORMAT_A8R8G8B8; + WW3DFormat src_format=thumb->Get_Format(); unsigned width=thumb->Get_Width(); unsigned height=thumb->Get_Height(); - for (level=0;levelGetLevelCount()-1;++level) { + Vector3 hsv=hsv_shift; + for (level=0;levelGetLevelCount()-1;++level) { BitmapHandlerClass::Copy_Image_Generate_Mipmap( width, height, @@ -241,7 +477,9 @@ IDirect3DTexture8* TextureLoader::Load_Thumbnail(const StringClass& filename,WW3 src_pitch, src_format, (unsigned char*)locked_rects[level+1].pBits, // mipmap - locked_rects[level+1].Pitch);// mipmap + locked_rects[level+1].Pitch, + hsv); + hsv=Vector3(0.0f,0.0f,0.0f); // Only do the shift for the first level, as the mipmaps are based on it. src_format=dest_format; src_surface=(unsigned char*)locked_rects[level].pBits; @@ -251,64 +489,27 @@ IDirect3DTexture8* TextureLoader::Load_Thumbnail(const StringClass& filename,WW3 } // Unlock all surfaces - for (level=0;levelGetLevelCount();++level) { - DX8_ErrorCode(d3d_texture->UnlockRect(level)); - } - - return d3d_texture; -} - -static bool Is_Power_Of_Two(unsigned i) -{ - if (!i) return false; - unsigned n=i; - unsigned shift=0; - while (n) { - shift++; - n>>=1; + for (level=0;levelGetLevelCount();++level) { + DX8_ErrorCode(sysmem_texture->UnlockRect(level)); } - return ((i>>(shift-1))<<(shift-1))==i; -} - -// ---------------------------------------------------------------------------- - -// TODO: Legacy - remove this call! -IDirect3DTexture8* Load_Compressed_Texture( - const StringClass& filename, - unsigned reduction_factor, - MipCountType mip_level_count, - WW3DFormat dest_format) -{ - // If DDS file isn't available, use TGA file to convert to DDS. - - DDSFileClass dds_file(filename,reduction_factor); - if (!dds_file.Is_Available()) return NULL; - if (!dds_file.Load()) return NULL; - - unsigned width=dds_file.Get_Width(0); - unsigned height=dds_file.Get_Height(0); - unsigned mips=dds_file.Get_Mip_Level_Count(); - - // If format isn't defined get the nearest valid texture format to the compressed file format - // Note that the nearest valid format could be anything, even uncompressed. - if (dest_format==WW3D_FORMAT_UNKNOWN) dest_format=Get_Valid_Texture_Format(dds_file.Get_Format(),true); - +#ifdef USE_MANAGED_TEXTURES + return sysmem_texture; +#else IDirect3DTexture8* d3d_texture = DX8Wrapper::_Create_DX8_Texture( - width, - height, + thumb->Get_Width(), + thumb->Get_Height(), dest_format, - (MipCountType)mips); + TextureBaseClass::MIP_LEVELS_ALL, + D3DPOOL_DEFAULT); + DX8CALL(UpdateTexture(sysmem_texture,d3d_texture)); + sysmem_texture->Release(); - for (unsigned level=0;levelGetSurfaceLevel(level/*-reduction_factor*/,&d3d_surface)); - dds_file.Copy_Level_To_Surface(level,d3d_surface); - d3d_surface->Release(); - } + WWDEBUG_SAY(("Created non-managed texture (%s)",filename)); return d3d_texture; +#endif } + // ---------------------------------------------------------------------------- // // Load image to a surface. The function tries to create texture that matches @@ -321,6 +522,8 @@ IDirect3DSurface8* TextureLoader::Load_Surface_Immediate( WW3DFormat texture_format, bool allow_compression) { + WWASSERT(Is_DX8_Thread()); + bool compressed=Is_Format_Compressed(texture_format,allow_compression); if (compressed) { @@ -423,967 +626,2194 @@ IDirect3DSurface8* TextureLoader::Load_Surface_Immediate( } -// ---------------------------------------------------------------------------- -// -// Load mipmap levels to a pre-generated and locked texture object based on -// information in load task object. Try loading from a DDS file first and if -// that fails try a TGA. -// -// ---------------------------------------------------------------------------- - -void TextureLoader::Load_Mipmap_Levels(TextureLoadTaskClass* task) +void TextureLoader::Request_Thumbnail(TextureBaseClass *tc) { - WWASSERT(task->Peek_D3D_Texture()); - WWMEMLOG(MEM_TEXTURE); + // Grab the foreground lock. This prevents the foreground thread + // from retiring any tasks related to this texture. It also + // serializes calls to Request_Thumbnail from multiple threads. + FastCriticalSectionClass::LockClass lock(_ForegroundCriticalSection); - if (task->Peek_Texture()->Is_Compression_Allowed()) { - DDSFileClass dds_file(task->Peek_Texture()->Get_Full_Path(),task->Get_Reduction()); - if (dds_file.Is_Available() && dds_file.Load()) { - unsigned width=task->Get_Width(); - unsigned height=task->Get_Height(); - for (unsigned level=0;levelGet_Mip_Level_Count();++level) { - WWASSERT(width && height); - dds_file.Copy_Level_To_Surface( - level, - task->Get_Format(), - width, - height, - task->Get_Locked_Surface_Ptr(level), - task->Get_Locked_Surface_Pitch(level)); - width>>=1; - height>>=1; - } - return; + // Has a Direct3D texture already been loaded? + if (tc->Peek_D3D_Base_Texture()) { + return; + } + + TextureLoadTaskClass *task = tc->ThumbnailLoadTask; + + if (Is_DX8_Thread()) { + // load the thumbnail immediately + TextureLoader::Load_Thumbnail(tc); + + // clear any pending thumbnail load + if (task) { + _ForegroundQueue.Remove(task); + task->Destroy(); + } + + } else { + TextureLoadTaskClass *load_task = tc->TextureLoadTask; + + // if texture is not already loading a thumbnail and there is no + // background load near completion. (a background load waiting + // to be applied will be ready at the same time as a queued thumbnail. + // Why do the extra work?) + if (!task && (!load_task || load_task->Get_State() < TextureLoadTaskClass::STATE_LOAD_MIPMAP)) { + + // create a thumbnail load task and add to foreground queue. + task = TextureLoadTaskClass::Create(tc, TextureLoadTaskClass::TASK_THUMBNAIL, TextureLoadTaskClass::PRIORITY_LOW); + _ForegroundQueue.Push_Back(task); } } - if (Load_Uncompressed_Mipmap_Levels_From_TGA(task)) return; } -// ---------------------------------------------------------------------------- -// -// Use load task to load texture surface from a targa file. Calculate mipmaps -// if needed. -// -// ---------------------------------------------------------------------------- -bool TextureLoader::Load_Uncompressed_Mipmap_Levels_From_TGA(TextureLoadTaskClass* task) +void TextureLoader::Request_Background_Loading(TextureBaseClass *tc) { - if (!task->Get_Mip_Level_Count()) return false; - TextureBaseClass* texture=task->Peek_Texture(); - - Targa targa; - if (TARGA_ERROR_HANDLER(targa.Open(texture->Get_Full_Path(), TGA_READMODE),texture->Get_Full_Path())) { - task->Set_Fail(true); - return false; + WWPROFILE(("TextureLoader::Request_Background_Loading()")); + // Grab the foreground lock. This prevents the foreground thread + // from retiring any tasks related to this texture. It also + // serializes calls to Request_Background_Loading from other + // threads. + FastCriticalSectionClass::LockClass foreground_lock(_ForegroundCriticalSection); + + // Has the texture already been loaded? + if (tc->Is_Initialized()) { + return; } - // DX8 uses image upside down compared to TGA - targa.Header.ImageDescriptor ^= TGAIDF_YORIGIN; - WW3DFormat src_format,dest_format; - unsigned src_bpp=0; - Get_WW3D_Format(dest_format,src_format,src_bpp,targa); -// WWASSERT(task->Get_Format()==dest_format); - dest_format=task->Get_Format(); // Texture can be requested in different format than the most obvious from the TGA + TextureLoadTaskClass *task = tc->TextureLoadTask; - char palette[256*4]; - targa.SetPalette(palette); + // if texture already has a load task, we don't need to create another one. + if (task) { + return; + } - unsigned src_width=targa.Header.Width; - unsigned src_height=targa.Header.Height; - unsigned width=task->Get_Width(); - unsigned height=task->Get_Height(); + task = TextureLoadTaskClass::Create(tc, TextureLoadTaskClass::TASK_LOAD, TextureLoadTaskClass::PRIORITY_LOW); - // NOTE: We load the palette but we do not yet support paletted textures! - if (TARGA_ERROR_HANDLER(targa.Load(texture->Get_Full_Path(), TGAF_IMAGE, false),texture->Get_Full_Path())) { - task->Set_Fail(true); - return false; + if (Is_DX8_Thread()) { + Begin_Load_And_Queue(task); + } else { + _ForegroundQueue.Push_Back(task); } - unsigned char* src_surface=(unsigned char*)targa.GetImage(); +} - // No paletted format allowed when generating mipmaps - unsigned char* converted_surface=NULL; - if (src_format==WW3D_FORMAT_A1R5G5B5 || src_format==WW3D_FORMAT_R5G6B5 || src_format==WW3D_FORMAT_A4R4G4B4 || - src_format==WW3D_FORMAT_P8 || src_format==WW3D_FORMAT_L8 || src_width!=width || src_height!=height) { - converted_surface=W3DNEWARRAY unsigned char[width*height*4]; - dest_format=Get_Valid_Texture_Format(WW3D_FORMAT_A8R8G8B8,false); - BitmapHandlerClass::Copy_Image( - converted_surface, - width, - height, - width*4, - WW3D_FORMAT_A8R8G8B8, //dest_format, - src_surface, - src_width, - src_height, - src_width*src_bpp, - src_format, - (unsigned char*)targa.GetPalette(), - targa.Header.CMapDepth>>3, - false); - src_surface=converted_surface; - src_format=WW3D_FORMAT_A8R8G8B8; //dest_format; - src_width=width; - src_height=height; - src_bpp=Get_Bytes_Per_Pixel(src_format); + +void TextureLoader::Request_Foreground_Loading(TextureBaseClass *tc) +{ + WWPROFILE(("TextureLoader::Request_Foreground_Loading()")); + // Grab the foreground lock. This prevents the foreground thread + // from retiring the load tasks for this texture. It also + // serializes calls to Request_Foreground_Loading from other + // threads. + FastCriticalSectionClass::LockClass foreground_lock(_ForegroundCriticalSection); + + // Has the texture already been loaded? + if (tc->Is_Initialized()) { + return; } - unsigned src_pitch=src_width*src_bpp; + TextureLoadTaskClass *task = tc->TextureLoadTask; + TextureLoadTaskClass *task_thumb = tc->ThumbnailLoadTask; - for (unsigned level=0;levelGet_Mip_Level_Count();++level) { - WWASSERT(task->Get_Locked_Surface_Ptr(level)); - BitmapHandlerClass::Copy_Image( - task->Get_Locked_Surface_Ptr(level), - width, - height, - task->Get_Locked_Surface_Pitch(level), - task->Get_Format(), - src_surface, - src_width, - src_height, - src_pitch, - src_format, - NULL, - 0, - true); + if (Is_DX8_Thread()) { - width>>=1; - height>>=1; - src_width>>=1; - src_height>>=1; - if (!width || !height || !src_width || !src_height) break; - } + // since we're in the DX8 thread, we can load the entire + // texture right now. - delete[] converted_surface; + // if we have a thumbnail task waiting, kill it. + if (task_thumb) { + _ForegroundQueue.Remove(task_thumb); + task_thumb->Destroy(); + } - return true; -} + if (task) { + // we need to remove the task from any queue, since we're going + // to finish it up right now. + + // halt background thread. After we're holding this lock, + // we know the background thread cannot begin loading + // mipmap levels for this texture. + FastCriticalSectionClass::LockClass background_lock(_BackgroundCriticalSection); + _ForegroundQueue.Remove(task); + _BackgroundQueue.Remove(task); + } else { + // Since the task manages all the state associated with loading + // a texture, we temporarily create one. + task = TextureLoadTaskClass::Create(tc, TextureLoadTaskClass::TASK_LOAD, TextureLoadTaskClass::PRIORITY_HIGH); + } -// ---------------------------------------------------------------------------- -// -// Return a task from the load list head. The loading thread uses this function -// to retrieve tasks from the load list. -// -// ---------------------------------------------------------------------------- + // finish loading the task and destroy it. + task->Finish_Load(); + task->Destroy(); -TextureLoadTaskClass* LoaderThreadClass::Get_Task_From_Load_List() -{ - CriticalSectionClass::LockClass m(mutex); + } else { + // we are not in the DX8 thread. We need to add a high-priority loading + // task to the foreground queue. - TextureLoadTaskClass* task=LoadListHead; - if (task) { - LoadListHead=task->Peek_Succ(); - task->Set_Succ(NULL); + // Grab the background lock. After we're holding this lock, we + // know the background thread cannot begin loading mipmap levels + // for this texture. + FastCriticalSectionClass::LockClass background_lock(_BackgroundCriticalSection); + + // if we have a thumbnail task, we should cancel it. Since we are not + // the foreground thread, we are not allowed to call Destroy(). Instead, + // leave it queued in the completed state so it will be destroyed by Update(). + if (task_thumb) { + task_thumb->Set_State(TextureLoadTaskClass::STATE_COMPLETE); + } + + if (task) { + // if a load task is waiting on the background queue, we need to + // move it to the foreground queue. + if (task->Get_List() == &_BackgroundQueue) { + + // remove task from list + _BackgroundQueue.Remove(task); + + // add to foreground queue. + _ForegroundQueue.Push_Back(task); + } + + // upgrade the task priority + task->Set_Priority(TextureLoadTaskClass::PRIORITY_HIGH); + + } else { + // allocate high priority load task + task = TextureLoadTaskClass::Create(tc, TextureLoadTaskClass::TASK_LOAD, TextureLoadTaskClass::PRIORITY_HIGH); + + // add to back of foreground queue. + _ForegroundQueue.Push_Back(task); + } } - return task; } -// ---------------------------------------------------------------------------- -// -// This function adds a load task to the head of the loading thread task list. -// The latest added task will be the next processed (There are good reasons -// for such ordering). The loading thread will process tasks from this list -// as soons as it can and then move the tasks to finished list. -// -// ---------------------------------------------------------------------------- -void LoaderThreadClass::Add_Task_To_Load_List(TextureLoadTaskClass* task) +void TextureLoader::Flush_Pending_Load_Tasks(void) { - CriticalSectionClass::LockClass m(mutex); + // This function can only be called from the main thread. + // (Only the main thread can make the DX8 calls necessary + // to complete texture loading. If we wanted to flush + // the pending tasks from another thread, we'd probably + // want to set a bool that is checked by Update(). + WWASSERT(Is_DX8_Thread()); - WWASSERT(task->Peek_Succ()==NULL); + for (;;) { + bool done = false; - task->Set_Succ(LoadListHead); - LoadListHead=task; + { + // we have no pending load tasks when both queues are empty + // and the background thread is not processing a texture. + + // Grab the background lock. Once we're holding it, we + // know that the background thread is not processing any + // textures. + + // NOTE: It's important that we do only hold on to the background + // lock while we check for completion. Otherwise, we will either + // violate the lock order when we call Update() (which grabs + // the foreground lock) or never give the background thread + // a chance to empty its queue. + FastCriticalSectionClass::LockClass background_lock(_BackgroundCriticalSection); + done = _BackgroundQueue.Is_Empty() && _ForegroundQueue.Is_Empty(); + } + + // exit loop if no entries in list + if (done) { + break; + } + + Update(); + ThreadClass::Switch_Thread(); + } } -// ---------------------------------------------------------------------------- -// -// After the loading thread is done with the texture, it is moved to the list -// of finished tasks so that the main thread can then finish up by unlocking -// the surfaces and applying the changes to the texture class object. -// -// ---------------------------------------------------------------------------- -void LoaderThreadClass::Add_Task_To_Finished_List(TextureLoadTaskClass* task) +// Nework update macro for texture loader. +#pragma warning(disable:4201) // warning C4201: nonstandard extension used : nameless struct/union +#include +#define UPDATE_NETWORK \ + if (network_callback) { \ + unsigned long time2 = timeGetTime(); \ + if (time2 - time > 20) { \ + network_callback(); \ + time = time2; \ + } \ + } \ + + +void TextureLoader::Update(void (*network_callback)(void)) { - CriticalSectionClass::LockClass m(mutex); + WWASSERT_PRINT(Is_DX8_Thread(), "TextureLoader::Update must be called from the main thread!"); + + if (TextureLoadSuspended) { + return; + } + + // grab foreground lock to prevent any other thread from + // modifying texture tasks. + FastCriticalSectionClass::LockClass lock(_ForegroundCriticalSection); + + unsigned long time = timeGetTime(); - WWASSERT(task->Peek_Succ()==NULL); + // while we have tasks on the foreground queue + while (TextureLoadTaskClass *task = _ForegroundQueue.Pop_Front()) { + UPDATE_NETWORK; + // dispatch to proper task handler + switch (task->Get_Type()) { + case TextureLoadTaskClass::TASK_THUMBNAIL: + Process_Foreground_Thumbnail(task); + break; + + case TextureLoadTaskClass::TASK_LOAD: + Process_Foreground_Load(task); + break; + } + } - task->Set_Succ(FinishedListHead); - FinishedListHead=task; + TextureBaseClass::Invalidate_Old_Unused_Textures(TextureInactiveOverrideTime); } -// ---------------------------------------------------------------------------- -// -// If we need to find out if the load task list is empty this is the function -// to use. We can't use Get_Task_From_Load_List() as if the list isn't empty -// it also removes the head node from the list. -// -// ---------------------------------------------------------------------------- +void TextureLoader::Suspend_Texture_Load() +{ + WWASSERT_PRINT(Is_DX8_Thread(),"TextureLoader::Suspend_Texture_Load must be called from the main thread!"); + TextureLoadSuspended=true; +} -bool Is_Load_List_Empty() +void TextureLoader::Continue_Texture_Load() { - return !LoadListHead; + WWASSERT_PRINT(Is_DX8_Thread(),"TextureLoader::Continue_Texture_Load must be called from the main thread!"); + TextureLoadSuspended=false; } -// ---------------------------------------------------------------------------- -// -// Texture loading thread loads textures that appear in loading_task_list. -// If the list is empty the thread sleeps. -// -// ---------------------------------------------------------------------------- -void LoaderThreadClass::Thread_Function() +void TextureLoader::Process_Foreground_Thumbnail(TextureLoadTaskClass *task) { - while (running) { - TextureLoadTaskClass* task=Get_Task_From_Load_List(); - if (task) { - TextureLoader::Load_Mipmap_Levels(task); - Add_Task_To_Finished_List(task); - } + switch (task->Get_State()) { + case TextureLoadTaskClass::STATE_NONE: + Load_Thumbnail(task->Peek_Texture()); + FALLTHROUGH; // NOTE: fall-through is intentional - Switch_Thread(); + case TextureLoadTaskClass::STATE_COMPLETE: + task->Destroy(); + break; } } -// ---------------------------------------------------------------------------- -// -// Update refreshes all completed texture loading tasks -// -// ---------------------------------------------------------------------------- -TextureLoadTaskClass* Get_Finished_Task() +void TextureLoader::Process_Foreground_Load(TextureLoadTaskClass *task) { - CriticalSectionClass::LockClass m(mutex); + // Is high-priority task? + if (task->Get_Priority() == TextureLoadTaskClass::PRIORITY_HIGH) { + task->Finish_Load(); + task->Destroy(); + return; + } - TextureLoadTaskClass* task=FinishedListHead; - if (task) { - FinishedListHead=task->Peek_Succ(); - task->Set_Succ(NULL); + // otherwise, must be a low-priority task. + + switch (task->Get_State()) { + case TextureLoadTaskClass::STATE_NONE: + Begin_Load_And_Queue(task); + break; + + case TextureLoadTaskClass::STATE_LOAD_MIPMAP: + task->End_Load(); + task->Destroy(); + break; } - return task; } -TextureLoadTaskClass* Get_Thumbnail_Task() -{ - CriticalSectionClass::LockClass m(mutex); - TextureLoadTaskClass* task=ThumbnailListHead; - if (task) { - ThumbnailListHead=task->Peek_Succ(); - task->Set_Succ(NULL); +void TextureLoader::Begin_Load_And_Queue(TextureLoadTaskClass *task) +{ + // should only be called from the DX8 thread. + WWASSERT(Is_DX8_Thread()); + + if (task->Begin_Load()) { + // add to front of background queue. This means the + // background load thread will service tasks in LIFO + // (last in, first out) order. + + // NOTE: this was how the old code did it, with a + // comment that mentioned good reasons for doing so, + // without actually listing the reasons. I suspect + // it has something to do with visually important textures, + // like those in the foreground, starting their load last. + _BackgroundQueue.Push_Front(task); + } else { + // unable to load. + task->Apply_Missing_Texture(); + task->Destroy(); } - return task; } -void Add_Thumbnail_Task(TextureLoadTaskClass* task) + +void TextureLoader::Load_Thumbnail(TextureBaseClass *tc) { - CriticalSectionClass::LockClass m(mutex); + // All D3D operations must run from main thread + WWASSERT(Is_DX8_Thread()); - WWASSERT(task->Peek_Succ()==NULL); + // load thumbnail texture + IDirect3DTexture8 *d3d_texture = Load_Thumbnail(tc->Get_Full_Path(),tc->Get_HSV_Shift()); - task->Set_Succ(ThumbnailListHead); - ThumbnailListHead=task; + // apply thumbnail to texture + if (tc->Get_Asset_Type()==TextureBaseClass::TEX_REGULAR) + { + tc->Apply_New_Surface(d3d_texture, false); + } + // release our reference to thumbnail texture + d3d_texture->Release(); + d3d_texture = 0; } -// ---------------------------------------------------------------------------- -// -// The main thread's update function deletes tasks from the load task list -// once a frame. -// -// ---------------------------------------------------------------------------- -TextureLoadTaskClass* Get_Task_From_Delete_List() +void LoaderThreadClass::Thread_Function(void) { - WWASSERT(ThreadClass::_Get_Current_Thread_ID()==DX8Wrapper::_Get_Main_Thread_ID()); + while (running) { + // if there are no tasks on the background queue, no need to grab background lock. + if (!_BackgroundQueue.Is_Empty()) { + // Grab background load so other threads know we could be + // loading a texture. + FastCriticalSectionClass::LockClass lock(_BackgroundCriticalSection); + + // try to remove a task from the background queue. This could fail + // if another thread modified the queue between our test above and + // grabbing the lock. + TextureLoadTaskClass* task = _BackgroundQueue.Pop_Front(); + if (task) { + // verify task is in proper state for background processing. + WWASSERT(task->Get_Type() == TextureLoadTaskClass::TASK_LOAD); + WWASSERT(task->Get_State() == TextureLoadTaskClass::STATE_LOAD_BEGUN); + + // load mip map levels and return to foreground queue for final step. + task->Load(); + _ForegroundQueue.Push_Back(task); + } + } - TextureLoadTaskClass* task=DeleteTaskListHead; - if (task) { - DeleteTaskListHead=task->Peek_Succ(); - task->Set_Succ(NULL); + Switch_Thread(); } - return task; } -// ---------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// // -// When task wants to delete itself it adds itself to a delete list. This list -// can only be accessed from the main thread. +// TextureLoaderTaskClass implementation // -// ---------------------------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// -void Add_Task_To_Delete_List(TextureLoadTaskClass* task) +TextureLoadTaskClass::TextureLoadTaskClass() +: Texture (0), + D3DTexture (0), + Format (WW3D_FORMAT_UNKNOWN), + Width (0), + Height (0), + MipLevelCount (0), + Reduction (0), + Type (TASK_NONE), + Priority (PRIORITY_LOW), + State (STATE_NONE), + HSVShift (0.0f,0.0f,0.0f) { - WWASSERT(ThreadClass::_Get_Current_Thread_ID()==DX8Wrapper::_Get_Main_Thread_ID()); + // because texture load tasks are pooled, the constructor and destructor + // don't need to do much. The work of attaching a task to a texture is + // is done by Init() and Deinit(). + + for (int i = 0; i < MIP_LEVELS_MAX; ++i) { + LockedSurfacePtr[i] = NULL; + LockedSurfacePitch[i] = 0; + } +} - WWASSERT(task->Peek_Succ()==NULL); - task->Set_Succ(DeleteTaskListHead); - DeleteTaskListHead=task; +TextureLoadTaskClass::~TextureLoadTaskClass(void) +{ + Deinit(); } -TextureLoadTaskClass* Get_Deferred_Task() + +TextureLoadTaskClass *TextureLoadTaskClass::Create(TextureBaseClass *tc, TaskType type, PriorityType priority) { - CriticalSectionClass::LockClass m(mutex); + // recycle or create a new texture load task with the given type + // and priority, then associate the texture with the task. - TextureLoadTaskClass* task=DeferredListHead; - if (task) { - DeferredListHead=task->Peek_Succ(); - task->Set_Succ(NULL); + // pull a load task from front of free list + TextureLoadTaskClass *task = NULL; + switch (tc->Get_Asset_Type()) + { + case TextureBaseClass::TEX_REGULAR : task=_TexLoadFreeList.Pop_Front(); break; + case TextureBaseClass::TEX_CUBEMAP : task=_CubeTexLoadFreeList.Pop_Front(); break; + case TextureBaseClass::TEX_VOLUME : task=_VolTexLoadFreeList.Pop_Front(); break; + default : WWASSERT(0); + }; + + // if no tasks on free list, allocate a new task + if (!task) + { + switch (tc->Get_Asset_Type()) + { + case TextureBaseClass::TEX_REGULAR : task=new TextureLoadTaskClass; break; + case TextureBaseClass::TEX_CUBEMAP : task=new CubeTextureLoadTaskClass; break; + case TextureBaseClass::TEX_VOLUME : task=new VolumeTextureLoadTaskClass; break; + default : WWASSERT(0); + } } + task->Init(tc, type, priority); return task; } -void Add_Deferred_Task(TextureLoadTaskClass* task) -{ - CriticalSectionClass::LockClass m(mutex); - - WWASSERT(task->Peek_Succ()==NULL); - task->Set_Succ(DeferredListHead); - DeferredListHead=task; -} -void TextureLoader::Flush_Pending_Load_Tasks() +void TextureLoadTaskClass::Destroy(void) { - while (!Is_Load_List_Empty()) { - Update(); - ThreadClass::Switch_Thread(); - } + // detach the task from its texture, and return to free pool. + Deinit(); + _TexLoadFreeList.Push_Front(this); } -void TextureLoader::Update() -{ - WWASSERT_PRINT(DX8Wrapper::_Get_Main_Thread_ID()==ThreadClass::_Get_Current_Thread_ID(),"TextureLoader::Update must be called from the main thread!"); - - while (TextureLoadTaskClass* task=Get_Deferred_Task()) { - task->Begin_Texture_Load(); // This will add the task to load list - } - while (TextureLoadTaskClass* task=Get_Finished_Task()) { - task->End_Load(); - task->Apply(true); - TextureLoadTaskClass::Release_Instance(task); +void TextureLoadTaskClass::Delete_Free_Pool(void) +{ + // (gth) We should probably just MEMPool these task objects... + while (TextureLoadTaskClass *task = _TexLoadFreeList.Pop_Front()) { + delete task; } - - while (TextureLoadTaskClass* task=Get_Thumbnail_Task()) { - task->Begin_Thumbnail_Load(); + while (TextureLoadTaskClass *task = _CubeTexLoadFreeList.Pop_Front()) { + delete task; } - - while (TextureLoadTaskClass* task=Get_Task_From_Delete_List()) { -// delete task; - TextureLoadTaskClass::Release_Instance(task); + while (TextureLoadTaskClass *task = _VolTexLoadFreeList.Pop_Front()) { + delete task; } } -// ---------------------------------------------------------------------------- -static DWORD VectortoRGBA( D3DXVECTOR3* v, FLOAT fHeight ) +void TextureLoadTaskClass::Init(TextureBaseClass* tc, TaskType type, PriorityType priority) { - DWORD r = (DWORD)( 127.0f * v->x + 128.0f ); - DWORD g = (DWORD)( 127.0f * v->y + 128.0f ); - DWORD b = (DWORD)( 127.0f * v->z + 128.0f ); - DWORD a = (DWORD)( 255.0f * fHeight ); + WWASSERT(tc); - return( (a<<24L) + (r<<16L) + (g<<8L) + (b<<0L) ); -} + // NOTE: we must be in the main thread to avoid corrupting the texture's refcount. + WWASSERT(TextureLoader::Is_DX8_Thread()); + REF_PTR_SET(Texture, tc); -IDirect3DTexture8* TextureLoader::Generate_Bumpmap(TextureBaseClass* texture) -{ - WW3DFormat bump_format=WW3D_FORMAT_U8V8; - if (!DX8Wrapper::Get_Current_Caps()->Support_Texture_Format(bump_format)) { - return MissingTexture::_Get_Missing_Texture(); - } + // Make sure texture has a filename. + WWASSERT(!Texture->Get_Full_Path().Is_Empty()); - D3DSURFACE_DESC desc; - IDirect3DTexture8* src_d3d_tex=texture->Peek_D3D_Texture(); - WWASSERT(src_d3d_tex); - DX8_ErrorCode(src_d3d_tex->GetLevelDesc(0,&desc)); - unsigned width=desc.Width; - unsigned height=desc.Height; + Type = type; + Priority = priority; + State = STATE_NONE; - IDirect3DTexture8* d3d_texture = DX8Wrapper::_Create_DX8_Texture( - width, - height, - bump_format, - MIP_LEVELS_1); + D3DTexture = 0; - D3DLOCKED_RECT src_locked_rect; - DX8_ErrorCode( - texture->Peek_D3D_Texture()->LockRect( - 0, - &src_locked_rect, - NULL, - D3DLOCK_READONLY)); + TextureClass* tex=Texture->As_TextureClass(); + + if (tex) + { + Format = tex->Get_Texture_Format(); // don't assume format yet KM + } + else + { + Format = WW3D_FORMAT_UNKNOWN; + } + + Width = 0; + Height = 0; + MipLevelCount = Texture->MipLevelCount; + Reduction = Texture->Get_Reduction(); + HSVShift = Texture->Get_HSV_Shift(); - D3DLOCKED_RECT dest_locked_rect; - DX8_ErrorCode( - d3d_texture->LockRect( - 0, - &dest_locked_rect, - NULL, - 0)); - WW3DFormat format=D3DFormat_To_WW3DFormat(desc.Format); - unsigned bpp=Get_Bytes_Per_Pixel(format); + for (int i = 0; i < MIP_LEVELS_MAX; ++i) + { + LockedSurfacePtr[i] = NULL; + LockedSurfacePitch[i] = 0; + } - for( unsigned y=0; yThumbnailLoadTask == NULL); + Texture->ThumbnailLoadTask = this; + break; - if( y == desc.Height-1 ) // Don't go past the last line - src_ptr_next_line = src_ptr_mid; - if( y == 0 ) // Don't go before first line - src_ptr_prev_line = src_ptr_mid; + case TASK_LOAD: + WWASSERT(Texture->TextureLoadTask == NULL); + Texture->TextureLoadTask = this; + break; + } +} - for( unsigned x=0; x1 ) ? 63 : 127; +void TextureLoadTaskClass::Deinit() +{ + // task should not be on any list when it is being detached from texture. + WWASSERT(Next == NULL); + WWASSERT(Prev == NULL); - switch( bump_format ) - { - case WW3D_FORMAT_U8V8: - *dest_ptr++ = (unsigned char)iDu; - *dest_ptr++ = (unsigned char)iDv; - break; + WWASSERT(D3DTexture == NULL); - case WW3D_FORMAT_L6V5U5: - *(unsigned short*)dest_ptr = (unsigned short)( ( (iDu>>3) & 0x1f ) << 0 ); - *(unsigned short*)dest_ptr |= (unsigned short)( ( (iDv>>3) & 0x1f ) << 5 ); - *(unsigned short*)dest_ptr |= (unsigned short)( ( ( uL>>2) & 0x3f ) << 10 ); - dest_ptr += 2; - break; + for (int i = 0; i < MIP_LEVELS_MAX; ++i) { + WWASSERT(LockedSurfacePtr[i] == NULL); + } - case WW3D_FORMAT_X8L8V8U8: - *dest_ptr++ = (unsigned char)iDu; - *dest_ptr++ = (unsigned char)iDv; - *dest_ptr++ = (unsigned char)uL; - *dest_ptr++ = (unsigned char)0L; + if (Texture) { + switch (Type) { + case TASK_THUMBNAIL: + WWASSERT(Texture->ThumbnailLoadTask == this); + Texture->ThumbnailLoadTask = NULL; break; - } - // Move one pixel to the left (src is 32-bpp) - src_ptr_mid+=bpp; - src_ptr_prev_line+=bpp; - src_ptr_next_line+=bpp; + case TASK_LOAD: + WWASSERT(Texture->TextureLoadTask == this); + Texture->TextureLoadTask = NULL; + break; } - } - DX8_ErrorCode(d3d_texture->UnlockRect(0)); - DX8_ErrorCode(texture->Peek_D3D_Texture()->UnlockRect(0)); - return d3d_texture; + // NOTE: we must be in main thread to avoid corrupting Texture's refcount. + WWASSERT(TextureLoader::Is_DX8_Thread()); + REF_PTR_RELEASE(Texture); + } } -// ---------------------------------------------------------------------------- -// -// Public texture request functions. These functions can be used to request -// texture loading. -// -// ---------------------------------------------------------------------------- -void TextureLoader::Add_Load_Task(TextureBaseClass* tc) +bool TextureLoadTaskClass::Begin_Load(void) { - // If the texture is already being loaded we just exit here. - if (tc->TextureLoadTask) return; - - TextureLoadTaskClass* task=TextureLoadTaskClass::Get_Instance(tc,false); - task->Begin_Texture_Load(); -} + WWASSERT(TextureLoader::Is_DX8_Thread()); -// ---------------------------------------------------------------------------- + bool loaded = false; -void TextureLoader::Request_High_Priority_Loading( - TextureBaseClass* tc, - MipCountType mip_level_count) -{ - TextureLoadTaskClass* task=TextureLoadTaskClass::Get_Instance(tc,true); - task->Begin_Texture_Load(); -} + // if allowed, begin a compressed load + if (Texture->Is_Compression_Allowed()) { + loaded = Begin_Compressed_Load(); + } -// ---------------------------------------------------------------------------- + // otherwise, begin an uncompressed load + if (!loaded) { + loaded = Begin_Uncompressed_Load(); + } -void TextureLoader::Request_Thumbnail(TextureBaseClass* tc) -{ - // If the texture is already being loaded we just exit here. - if (tc->TextureLoadTask) return; + // if not loaded, abort. + if (!loaded) { + return false; + } - TextureLoadTaskClass* task=TextureLoadTaskClass::Get_Instance(tc,false); - task->Begin_Thumbnail_Load(); -} + // lock surfaces in preparation for copy + Lock_Surfaces(); -// ---------------------------------------------------------------------------- -// -// Texture loader task handler -// -// ---------------------------------------------------------------------------- + State = STATE_LOAD_BEGUN; -TextureLoadTaskClass::TextureLoadTaskClass() - : - Texture(0), - Succ(0), - D3DTexture(0), - Width(0), - Height(0), - Format(WW3D_FORMAT_UNKNOWN), - IsLoading(false), - HasFailed(false), - MipLevelCount(0), - HighPriorityRequested(false), - Reduction(0) -{ + return true; } + // ---------------------------------------------------------------------------- // -// Destruct texture load task. The load task deinitialization will fail from -// any other than the main thread so the task must be either deleted from the -// main thread or deinitialized in the main thread prior to deleting it in -// another thread. +// Load mipmap levels to a pre-generated and locked texture object based on +// information in load task object. Try loading from a DDS file first and if +// that fails try a TGA. // // ---------------------------------------------------------------------------- - -TextureLoadTaskClass::~TextureLoadTaskClass() -{ - Deinit(); -} - -void TextureLoadTaskClass::Init(TextureBaseClass* tc,bool high_priority) +bool TextureLoadTaskClass::Load(void) { - // Make sure texture has a filename. - REF_PTR_SET(Texture,tc); - //WWASSERT(!Texture->Get_Full_Path().Is_Empty()); + WWMEMLOG(MEM_TEXTURE); + WWASSERT(Peek_D3D_Texture()); - Reduction=Texture->Get_Reduction(); - HighPriorityRequested=high_priority; - IsLoading=false; - HasFailed=false; - MipLevelCount=tc->MipLevelCount; - D3DTexture=0; - Width=0; - Height=0; - Format=Texture->Get_Texture_Format(); + bool loaded = false; - Texture->TextureLoadTask=this; - for (int i=0;iIs_Compression_Allowed()) { + loaded = Load_Compressed_Mipmap(); } -} -void TextureLoadTaskClass::Deinit() -{ - WWASSERT(Succ==NULL); - WWASSERT(D3DTexture==NULL); - WWASSERT(IsLoading==false); - for (int i=0;iTextureLoadTask==this); - Texture->TextureLoadTask=NULL; + // otherwise, load uncompressed mipmaps + if (!loaded) { + loaded = Load_Uncompressed_Mipmap(); } - REF_PTR_RELEASE(Texture); - WWASSERT(!D3DTexture); -} - -// ---------------------------------------------------------------------------- -// -// -// -// ---------------------------------------------------------------------------- + State = STATE_LOAD_MIPMAP; -void TextureLoadTaskClass::Begin_Texture_Load() -{ - // If we're in main thread, init for loading and add to the load list - if (ThreadClass::_Get_Current_Thread_ID()==DX8Wrapper::_Get_Main_Thread_ID()) { - - bool loaded=false; - if (Texture->Is_Compression_Allowed()) { - DDSFileClass dds_file(Texture->Get_Full_Path(),Get_Reduction()); - if (dds_file.Is_Available()) { - // Destination size will be the next power of two square from the larger width and height... - unsigned width=0, height=0, depth=1; - width=dds_file.Get_Width(0); - height=dds_file.Get_Height(0); - TextureLoader::Validate_Texture_Size(width,height,depth); - - // If the size doesn't match, try and see if texture reduction would help... (mainly for - // cases where loaded texture is larger than hardware limit) - if (width!=dds_file.Get_Width(0) || height!=dds_file.Get_Height(0)) { - for (unsigned i=1;iIs_Compression_Allowed()); - - unsigned mip_level_count=Get_Mip_Level_Count(); - // If texture wants all mip levels, take as many as the file contains (not necessarily all) - // Otherwise take as many mip levels as the texture wants, not to exceed the count in file... - if (!mip_level_count) mip_level_count=dds_file.Get_Mip_Level_Count(); - else if (mip_level_count>dds_file.Get_Mip_Level_Count()) mip_level_count=dds_file.Get_Mip_Level_Count(); - - // Once more, verify that the mip level count is correct (in case it was changed here it might not - // match the size...well actually it doesn't have to match but it can't be bigger than the size) - unsigned max_mip_level_count=1; - unsigned w=4; - unsigned h=4; - while (wmax_mip_level_count) mip_level_count=max_mip_level_count; - - D3DTexture=DX8Wrapper::_Create_DX8_Texture(Width,Height,Format,(MipCountType)mip_level_count); - MipLevelCount=mip_level_count; - //Texture->MipLevelCount); - loaded=true; - } - } + return loaded; +} - if (!loaded) { - Targa targa; - if (TARGA_ERROR_HANDLER(targa.Open(Texture->Get_Full_Path(), TGA_READMODE),Texture->Get_Full_Path())) { - D3DTexture=MissingTexture::_Get_Missing_Texture(); - HasFailed=true; - IsLoading=false; - End_Load(); - Apply(true); - Add_Task_To_Delete_List(this); - return; - } +void TextureLoadTaskClass::End_Load(void) +{ + WWASSERT(TextureLoader::Is_DX8_Thread()); - unsigned bpp; - WW3DFormat src_format,dest_format; - Get_WW3D_Format(dest_format,src_format,bpp,targa); - if (src_format!=WW3D_FORMAT_A8R8G8B8 && - src_format!=WW3D_FORMAT_R8G8B8 && - src_format!=WW3D_FORMAT_X8R8G8B8) { - WWDEBUG_SAY(("Invalid TGA format used in %s - only 24 and 32 bit formats should be used!",Texture->Get_Full_Path().str())); - } + Unlock_Surfaces(); + Apply(true); - // Destination size will be the next power of two square from the larger width and height... - unsigned width=targa.Header.Width, height=targa.Header.Height, depth=1; - int ReductionFactor=Get_Reduction(); - int MipLevels=0; - - //Figure out how many mip levels this texture will occupy - for (int i=width, j=height; i > 0 && j > 0; i>>=1, j>>=1) - MipLevels++; - - //Adjust the reduction factor to keep textures above some minimum dimensions - if (MipLevels <= WW3D::Get_Texture_Min_Dimension()) - ReductionFactor=0; - else - { int mipToDrop=MipLevels-WW3D::Get_Texture_Min_Dimension(); - if (ReductionFactor >= mipToDrop) - ReductionFactor=mipToDrop; - } + State = STATE_LOAD_COMPLETE; +} - width=targa.Header.Width>>ReductionFactor; - height=targa.Header.Height>>ReductionFactor; - unsigned ow=width; - unsigned oh=height; - TextureLoader::Validate_Texture_Size(width,height,depth); - if (width!=ow || height!=oh) { - WWDEBUG_SAY(("Invalid texture size, scaling required. Texture: %s, size: %d x %d -> %d x %d",Texture->Get_Full_Path().str(),ow,oh,width,height)); - } - IsLoading=true; - Width=width; - Height=height; +void TextureLoadTaskClass::Finish_Load(void) +{ + switch (State) { + // NOTE: fall-through below is intentional. - if (Format==WW3D_FORMAT_UNKNOWN) { - Format=Get_Valid_Texture_Format(dest_format,false); - } - else { - Format=Get_Valid_Texture_Format(Format,false); + case STATE_NONE: + if (!Begin_Load()) { + Apply_Missing_Texture(); + break; } + FALLTHROUGH; - D3DTexture=DX8Wrapper::_Create_DX8_Texture(Width,Height,Format,Texture->MipLevelCount); - } - - MipLevelCount=D3DTexture->GetLevelCount(); - for (unsigned i=0;iLockRect( - i, - &locked_rect, - NULL, - 0)); - LockedSurfacePtr[i]=(unsigned char*)locked_rect.pBits; - LockedSurfacePitch[i]=locked_rect.Pitch; - } + case STATE_LOAD_BEGUN: + Load(); + FALLTHROUGH; - if (HighPriorityRequested) { - TextureLoader::Load_Mipmap_Levels(this); + case STATE_LOAD_MIPMAP: End_Load(); - Apply(true); - Add_Task_To_Delete_List(this); - } - else { - LoaderThreadClass::Add_Task_To_Load_List(this); - } - } - // Otherwise add to deferred list which will be handled by main thread - else { - Add_Deferred_Task(this); + FALLTHROUGH; + + default: + break; } } -/* file_auto_ptr my_tga_file(_TheFileFactory,Texture->Get_Full_Path()); - if (my_tga_file->Is_Available()) { - my_tga_file->Open(); - unsigned size=my_tga_file->Size(); - char* tga_memory=W3DNEWARRAY char[size]; - my_tga_file->Read(tga_memory,size); - my_tga_file->Close(); - StringClass pth("data\\"); - pth+=Texture->Get_Texture_Name(); - RawFileClass tmp_tga_file(pth); - tmp_tga_file.Create(); - tmp_tga_file.Write(tga_memory,size); - tmp_tga_file.Close(); - delete[] tga_memory; +void TextureLoadTaskClass::Apply_Missing_Texture(void) +{ + WWASSERT(TextureLoader::Is_DX8_Thread()); + WWASSERT(!D3DTexture); + + D3DTexture = MissingTexture::_Get_Missing_Texture(); + Apply(true); +} + + +void TextureLoadTaskClass::Apply(bool initialize) +{ + WWASSERT(D3DTexture); + + // Verify that none of the mip levels are locked + for (unsigned i=0;iApply_New_Surface(D3DTexture, initialize); + + D3DTexture->Release(); + D3DTexture = NULL; +} + +static bool Get_Texture_Information +( + const char* filename, + unsigned& reduction, + unsigned& w, + unsigned& h, + unsigned& d, + WW3DFormat& format, + unsigned& mip_count, + bool compressed +) +{ + ThumbnailClass* thumb=ThumbnailManagerClass::Peek_Thumbnail_Instance_From_Any_Manager(filename); + + if (!thumb) + { + if (compressed) + { + DDSFileClass dds_file(filename, 0); + if (!dds_file.Is_Available()) return false; + + // Destination size will be the next power of two square from the larger width and height... + w = dds_file.Get_Width(0); + h = dds_file.Get_Height(0); + d = dds_file.Get_Depth(0); + format = dds_file.Get_Format(); + mip_count = dds_file.Get_Mip_Level_Count(); + //Figure out correct reduction + int reqReduction=WW3D::Get_Texture_Reduction(); //requested reduction + + if (reqReduction >= mip_count) + reqReduction=mip_count-1; //leave only the lowest level + + //Clamp reduction + int curReduction=0; + int curWidth=w; + int curHeight=h; + int minDim=WW3D::Get_Texture_Min_Dimension(); + + while (curReduction < reqReduction && curWidth > minDim && curHeight > minDim) + { curWidth >>=1; //keep dividing + curHeight >>=1; + curReduction++; + } + reduction=curReduction; + return true; + } + + Targa targa; + if (TARGA_ERROR_HANDLER(targa.Open(filename, TGA_READMODE), filename)) + { + return false; + } + + unsigned int bpp; + WW3DFormat dest_format; + Get_WW3D_Format(dest_format,format,bpp,targa); + + mip_count = 0; + + //Figure out how many mip levels this texture will occupy + for (int i=targa.Header.Width, j=targa.Header.Height; i > 0 && j > 0; i>>=1, j>>=1) + mip_count++; + + //Figure out correct reduction + int reqReduction=WW3D::Get_Texture_Reduction(); //requested reduction + + if (reqReduction >= mip_count) + reqReduction=mip_count-1; //leave only the lowest level + + //Clamp reduction + int curReduction=0; + int curWidth=targa.Header.Width; + int curHeight=targa.Header.Height; + int minDim=WW3D::Get_Texture_Min_Dimension(); + + while (curReduction < reqReduction && curWidth > minDim && curHeight > minDim) + { curWidth >>=1; //keep dividing + curHeight >>=1; + curReduction++; + } + reduction=curReduction; + + // Destination size will be the next power of two square from the larger width and height... + w = targa.Header.Width; + h = targa.Header.Height; + d = 1; + return true; + } + + if (compressed && + thumb->Get_Original_Texture_Format()!=WW3D_FORMAT_DXT1 && + thumb->Get_Original_Texture_Format()!=WW3D_FORMAT_DXT2 && + thumb->Get_Original_Texture_Format()!=WW3D_FORMAT_DXT3 && + thumb->Get_Original_Texture_Format()!=WW3D_FORMAT_DXT4 && + thumb->Get_Original_Texture_Format()!=WW3D_FORMAT_DXT5) { + return false; + } + + w=thumb->Get_Original_Texture_Width() >> reduction; + h=thumb->Get_Original_Texture_Height() >> reduction; + //d=thumb->Get_Original_Texture_Depth() >> reduction; // need to a volume texture support to thumbnails...maybe + mip_count=thumb->Get_Original_Texture_Mip_Level_Count(); + format=thumb->Get_Original_Texture_Format(); + return true; +} + + +bool TextureLoadTaskClass::Begin_Compressed_Load(void) +{ + unsigned orig_w,orig_h,orig_d,orig_mip_count,reduction; + WW3DFormat orig_format; + if (!Get_Texture_Information + ( + Texture->Get_Full_Path(), + reduction, + orig_w, + orig_h, + orig_d, + orig_format, + orig_mip_count, + true + ) + ) + { + return false; + } + + // Destination size will be the next power of two square from the larger width and height... + unsigned int width = orig_w; + unsigned int height = orig_h; + TextureLoader::Validate_Texture_Size(width, height,orig_d); + + // If the size doesn't match, try and see if texture reduction would help... (mainly for + // cases where loaded texture is larger than hardware limit) + if (width != orig_w || height != orig_h) + { + for (unsigned int i = 1; i < orig_mip_count; ++i) + { + unsigned w=orig_w>>i; + if (w<4) w=4; + unsigned h=orig_h>>i; + if (h<4) h=4; + unsigned tmp_w=w; + unsigned tmp_h=h; + + TextureLoader::Validate_Texture_Size(w,h,orig_d); + + if (w == tmp_w && h == tmp_h) + { + Reduction += i; + width = w; + height = h; + break; + } + } + } + + Width = width; + Height = height; + Format = Get_Valid_Texture_Format(orig_format, Texture->Is_Compression_Allowed()); + Reduction = reduction; + + + if (!Texture->Is_Reducible() || Texture->MipLevelCount == MIP_LEVELS_1) + Reduction = 0; //app doesn't want this texture to ever be reduced. + else + //Make sure we don't reduce below the level requested by the app + if (Texture->MipLevelCount != MIP_LEVELS_ALL && (Texture->MipLevelCount - Reduction) < 1) + Reduction = Texture->MipLevelCount - 1; + + //Another sanity check + if (Reduction >= orig_mip_count) + Reduction = 0; //should not be possible to get here, but check just in case. + + unsigned int mip_level_count = Get_Mip_Level_Count(); + int reducedWidth=Width; + int reducedHeight=Height; + + // If texture wants all mip levels, take as many as the file contains (not necessarily all) + // Otherwise take as many mip levels as the texture wants, not to exceed the count in file... + if (!mip_level_count) + { + reducedWidth >>= Reduction; + reducedHeight >>= Reduction; + mip_level_count = orig_mip_count-Reduction;//dds_file.Get_Mip_Level_Count(); + if (mip_level_count < 1) + mip_level_count = 1; //sanity check to make sure something gets loaded. + } + else + { + if (mip_level_count > orig_mip_count) + { //dds_file.Get_Mip_Level_Count()) { + mip_level_count = orig_mip_count;//dds_file.Get_Mip_Level_Count(); + } + + if (Reduction) + { reducedWidth >>= Reduction; + reducedHeight >>= Reduction; + mip_level_count -= Reduction; //reduced requested number by those removed. + } + } + + // Once more, verify that the mip level count is correct (in case it was changed here it might not + // match the size...well actually it doesn't have to match but it can't be bigger than the size) + unsigned int max_mip_level_count = 1; + unsigned int w = 4; + unsigned int h = 4; + + while (w < Width && h < Height) + { + w += w; + h += h; + max_mip_level_count++; + } + + if (mip_level_count > max_mip_level_count) + { + mip_level_count = max_mip_level_count; + } + + D3DTexture = DX8Wrapper::_Create_DX8_Texture + ( + reducedWidth, + reducedHeight, + Format, + (MipCountType)mip_level_count, +#ifdef USE_MANAGED_TEXTURES + D3DPOOL_MANAGED +#else + D3DPOOL_SYSTEMMEM +#endif + ); + + MipLevelCount = mip_level_count; + + return true; +} + +bool TextureLoadTaskClass::Begin_Uncompressed_Load(void) +{ + unsigned width,height,depth,orig_mip_count,reduction; + WW3DFormat orig_format; + if (!Get_Texture_Information + ( + Texture->Get_Full_Path(), + reduction, + width, + height, + depth, + orig_format, + orig_mip_count, + false + ) + ) + { + return false; + } + + WW3DFormat src_format=orig_format; + WW3DFormat dest_format=src_format; + dest_format=Get_Valid_Texture_Format(dest_format,false); // No compressed destination format if reading from targa... + + if ( src_format != WW3D_FORMAT_A8R8G8B8 + && src_format != WW3D_FORMAT_R8G8B8 + && src_format != WW3D_FORMAT_X8R8G8B8 ) + { + WWDEBUG_SAY(("Invalid TGA format used in %s - only 24 and 32 bit formats should be used!", Texture->Get_Full_Path().str())); + } + + // Destination size will be the next power of two square from the larger width and height... + unsigned ow = width; + unsigned oh = height; + TextureLoader::Validate_Texture_Size(width, height,depth); + if (width != ow || height != oh) + { + WWDEBUG_SAY(("Invalid texture size, scaling required. Texture: %s, size: %d x %d -> %d x %d", Texture->Get_Full_Path().str(), ow, oh, width, height)); + } + + Width = width; + Height = height; + Reduction = reduction; + + if (!Texture->Is_Reducible() || Texture->MipLevelCount == MIP_LEVELS_1) + Reduction = 0; //app doesn't want this texture to ever be reduced. + else + //Make sure we don't reduce below the level requested by the app + if (Texture->MipLevelCount != MIP_LEVELS_ALL && (Texture->MipLevelCount - Reduction) < 1) + Reduction = Texture->MipLevelCount - 1; + + //Another sanity check + if (Reduction >= orig_mip_count) + Reduction = 0; //should not be possible to get here, but check just in case. + + if (Format == WW3D_FORMAT_UNKNOWN) + { + Format=dest_format; + // Format = Get_Valid_Texture_Format(dest_format, false); validated above + } + else + { + Format = Get_Valid_Texture_Format(Format, false); + } + + int reducedWidth=Width; + int reducedHeight=Height; + int reducedMipCount=Texture->MipLevelCount; + + if (Reduction) + { //we don't care about specific levels so reduce them if needed. + reducedWidth >>= Reduction; + reducedHeight >>= Reduction; + if (reducedMipCount != MIP_LEVELS_ALL) + reducedMipCount -= Reduction; + } + + D3DTexture = DX8Wrapper::_Create_DX8_Texture + ( + reducedWidth, + reducedHeight, + Format, + (MipCountType)reducedMipCount, +#ifdef USE_MANAGED_TEXTURES + D3DPOOL_MANAGED +#else + D3DPOOL_SYSTEMMEM +#endif + ); + + return true; +} + +/* +bool TextureLoadTaskClass::Begin_Compressed_Load(void) +{ + DDSFileClass dds_file(Texture->Get_Full_Path(), Get_Reduction()); + if (!dds_file.Is_Available()) { + return false; + } + + // Destination size will be the next power of two square from the larger width and height... + unsigned int width = dds_file.Get_Width(0); + unsigned int height = dds_file.Get_Height(0); + TextureLoader::Validate_Texture_Size(width, height); + + // If the size doesn't match, try and see if texture reduction would help... (mainly for + // cases where loaded texture is larger than hardware limit) + if (width != dds_file.Get_Width(0) || height != dds_file.Get_Height(0)) { + for (unsigned int i = 1; i < dds_file.Get_Mip_Level_Count(); ++i) { + unsigned int w = dds_file.Get_Width(i); + unsigned int h = dds_file.Get_Height(i); + TextureLoader::Validate_Texture_Size(w,h); + + if (w == dds_file.Get_Width(i) && h == dds_file.Get_Height(i)) { + Reduction += i; + width = w; + height = h; + break; + } + } + } + + Width = width; + Height = height; + Format = Get_Valid_Texture_Format(dds_file.Get_Format(), Texture->Is_Compression_Allowed()); + + unsigned int mip_level_count = Get_Mip_Level_Count(); + + // If texture wants all mip levels, take as many as the file contains (not necessarily all) + // Otherwise take as many mip levels as the texture wants, not to exceed the count in file... + if (!mip_level_count) { + mip_level_count = dds_file.Get_Mip_Level_Count(); + } else if (mip_level_count > dds_file.Get_Mip_Level_Count()) { + mip_level_count = dds_file.Get_Mip_Level_Count(); + } + + // Once more, verify that the mip level count is correct (in case it was changed here it might not + // match the size...well actually it doesn't have to match but it can't be bigger than the size) + unsigned int max_mip_level_count = 1; + unsigned int w = 4; + unsigned int h = 4; + + while (w < Width && h < Height) { + w += w; + h += h; + max_mip_level_count++; + } + + if (mip_level_count > max_mip_level_count) { + mip_level_count = max_mip_level_count; + } + + D3DTexture = DX8Wrapper::_Create_DX8_Texture( + Width, + Height, + Format, + (TextureBaseClass::MipCountType)mip_level_count, +#ifdef USE_MANAGED_TEXTURES + D3DPOOL_MANAGED); +#else + D3DPOOL_SYSTEMMEM); +#endif + MipLevelCount = mip_level_count; + return true; +} + + +bool TextureLoadTaskClass::Begin_Uncompressed_Load(void) +{ + Targa targa; + if (TARGA_ERROR_HANDLER(targa.Open(Texture->Get_Full_Path(), TGA_READMODE), Texture->Get_Full_Path())) { + return false; + } + + unsigned int bpp; + WW3DFormat src_format, dest_format; + Get_WW3D_Format(dest_format,src_format,bpp,targa); + + if ( src_format != WW3D_FORMAT_A8R8G8B8 + && src_format != WW3D_FORMAT_R8G8B8 + && src_format != WW3D_FORMAT_X8R8G8B8) { + WWDEBUG_SAY(("Invalid TGA format used in %s - only 24 and 32 bit formats should be used!", Texture->Get_Full_Path())); + } + + // Destination size will be the next power of two square from the larger width and height... + unsigned width=targa.Header.Width, height=targa.Header.Height; + int ReductionFactor=Get_Reduction(); + int MipLevels=0; + + //Figure out how many mip levels this texture will occupy + for (int i=width, j=height; i > 0 && j > 0; i>>=1, j>>=1) + MipLevels++; + + //Adjust the reduction factor to keep textures above some minimum dimensions + if (MipLevels <= WW3D::Get_Texture_Min_Mip_Levels()) + ReductionFactor=0; + else + { int mipToDrop=MipLevels-WW3D::Get_Texture_Min_Mip_Levels(); + if (ReductionFactor >= mipToDrop) + ReductionFactor=mipToDrop; + } + + width=targa.Header.Width>>ReductionFactor; + height=targa.Header.Height>>ReductionFactor; + unsigned ow = width; + unsigned oh = height; + TextureLoader::Validate_Texture_Size(width, height); + if (width != ow || height != oh) { + WWDEBUG_SAY(("Invalid texture size, scaling required. Texture: %s, size: %d x %d -> %d x %d", Texture->Get_Full_Path(), ow, oh, width, height)); + } + + Width = width; + Height = height; + + // changed because format was being read from previous loading task?! KJM + Format=dest_format; + //if (Format == WW3D_FORMAT_UNKNOWN) { + // Format = Get_Valid_Texture_Format(dest_format, false); + //} else { + // Format = Get_Valid_Texture_Format(Format, false); + //} + + D3DTexture = DX8Wrapper::_Create_DX8_Texture + ( + Width, + Height, + Format, + Texture->MipLevelCount, +#ifdef USE_MANAGED_TEXTURES + D3DPOOL_MANAGED); +#else + D3DPOOL_SYSTEMMEM); +#endif + return true; +} +*/ + +void TextureLoadTaskClass::Lock_Surfaces(void) +{ + MipLevelCount = D3DTexture->GetLevelCount(); + + for (unsigned int i = 0; i < MipLevelCount; ++i) + { + D3DLOCKED_RECT locked_rect; + DX8_ErrorCode + ( + Peek_D3D_Texture()->LockRect + ( + i, + &locked_rect, + NULL, + 0 + ) + ); + LockedSurfacePtr[i] = (unsigned char *)locked_rect.pBits; + LockedSurfacePitch[i] = locked_rect.Pitch; + } +} + + +void TextureLoadTaskClass::Unlock_Surfaces(void) +{ + for (unsigned int i = 0; i < MipLevelCount; ++i) + { + if (LockedSurfacePtr[i]) + { + WWASSERT(ThreadClass::_Get_Current_Thread_ID() == DX8Wrapper::_Get_Main_Thread_ID()); + DX8_ErrorCode(Peek_D3D_Texture()->UnlockRect(i)); + } + LockedSurfacePtr[i] = NULL; + } + +#ifndef USE_MANAGED_TEXTURES + IDirect3DTexture8* tex = DX8Wrapper::_Create_DX8_Texture(Width, Height, Format, Texture->MipLevelCount,D3DPOOL_DEFAULT); + DX8CALL(UpdateTexture(Peek_D3D_Texture(),tex)); + Peek_D3D_Texture()->Release(); + D3DTexture=tex; + WWDEBUG_SAY(("Created non-managed texture (%s)",Texture->Get_Full_Path())); +#endif + +} + + +bool TextureLoadTaskClass::Load_Compressed_Mipmap(void) +{ + DDSFileClass dds_file(Texture->Get_Full_Path(), Get_Reduction()); + + // if we can't load from file, indicate rror. + if (!dds_file.Is_Available() || !dds_file.Load()) + { + return false; + } + + // regular 2d texture + unsigned int width = Get_Width(); + unsigned int height = Get_Height(); + + if (Reduction) + { for (unsigned int level = 0; level < Reduction; ++level) { + width >>= 1; + height >>= 1; + } + } + + for (unsigned int level = 0; level < Get_Mip_Level_Count(); ++level) + { + WWASSERT(width && height); + dds_file.Copy_Level_To_Surface + ( + level, + Get_Format(), + width, + height, + Get_Locked_Surface_Ptr(level), + Get_Locked_Surface_Pitch(level), + HSVShift + ); + + width >>= 1; + height >>= 1; + } + + return true; +} + + +bool TextureLoadTaskClass::Load_Uncompressed_Mipmap(void) +{ + if (!Get_Mip_Level_Count()) + { + return false; + } + + Targa targa; + if (TARGA_ERROR_HANDLER(targa.Open(Texture->Get_Full_Path(), TGA_READMODE), Texture->Get_Full_Path())) { + return false; + } + + // DX8 uses image upside down compared to TGA + targa.Header.ImageDescriptor ^= TGAIDF_YORIGIN; + + WW3DFormat src_format; + WW3DFormat dest_format; + unsigned int src_bpp = 0; + Get_WW3D_Format(dest_format,src_format,src_bpp,targa); + if (src_format==WW3D_FORMAT_UNKNOWN) return false; + + dest_format = Get_Format(); // Texture can be requested in different format than the most obvious from the TGA + + char palette[256*4]; + targa.SetPalette(palette); + + unsigned int src_width = targa.Header.Width; + unsigned int src_height = targa.Header.Height; + unsigned int width = Get_Width(); + unsigned int height = Get_Height(); + + // NOTE: We load the palette but we do not yet support paletted textures! + if (TARGA_ERROR_HANDLER(targa.Load(Texture->Get_Full_Path(), TGAF_IMAGE, false), Texture->Get_Full_Path())) { + return false; + } + + unsigned char * src_surface = (unsigned char*)targa.GetImage(); + unsigned char * converted_surface = NULL; + + // No paletted format allowed when generating mipmaps + Vector3 hsv_shift=HSVShift; + if ( src_format == WW3D_FORMAT_A1R5G5B5 + || src_format == WW3D_FORMAT_R5G6B5 + || src_format == WW3D_FORMAT_A4R4G4B4 + || src_format == WW3D_FORMAT_P8 + || src_format == WW3D_FORMAT_L8 + || src_width != width + || src_height != height) { + + converted_surface = new unsigned char[width*height*4]; + dest_format = Get_Valid_Texture_Format(WW3D_FORMAT_A8R8G8B8, false); + + BitmapHandlerClass::Copy_Image( + converted_surface, + width, + height, + width*4, + WW3D_FORMAT_A8R8G8B8, //dest_format, + src_surface, + src_width, + src_height, + src_width*src_bpp, + src_format, + (unsigned char*)targa.GetPalette(), + targa.Header.CMapDepth>>3, + false, + hsv_shift); + hsv_shift=Vector3(0.0f,0.0f,0.0f); + + src_surface = converted_surface; + src_format = WW3D_FORMAT_A8R8G8B8; //dest_format; + src_width = width; + src_height = height; + src_bpp = Get_Bytes_Per_Pixel(src_format); + } + + unsigned src_pitch = src_width * src_bpp; + + if (Reduction) + { //texture needs to be reduced so allocate storage for full-sized version. + unsigned char * destination_surface = new unsigned char[width*height*4]; + //generate upper mip-levels that will be dropped in final texture + for (unsigned int level = 0; level < Reduction; ++level) { + BitmapHandlerClass::Copy_Image( + (unsigned char *)destination_surface, + width, + height, + src_pitch, + Get_Format(), + src_surface, + src_width, + src_height, + src_pitch, + src_format, + NULL, + 0, + true, + hsv_shift); + + width >>= 1; + height >>= 1; + src_width >>= 1; + src_height >>= 1; + } + delete [] destination_surface; + } + + for (unsigned int level = 0; level < Get_Mip_Level_Count(); ++level) { + WWASSERT(Get_Locked_Surface_Ptr(level)); + BitmapHandlerClass::Copy_Image( + Get_Locked_Surface_Ptr(level), + width, + height, + Get_Locked_Surface_Pitch(level), + Get_Format(), + src_surface, + src_width, + src_height, + src_pitch, + src_format, + NULL, + 0, + true, + hsv_shift); + hsv_shift=Vector3(0.0f,0.0f,0.0f); + + width >>= 1; + height >>= 1; + src_width >>= 1; + src_height >>= 1; + + if (!width || !height || !src_width || !src_height) { + break; + } + } + + delete[] converted_surface; + + return true; +} + + +unsigned char * TextureLoadTaskClass::Get_Locked_Surface_Ptr(unsigned int level) +{ + WWASSERT(levelGet_Full_Path().Is_Empty()); + + Type = type; + Priority = priority; + State = STATE_NONE; + + D3DTexture = 0; + + CubeTextureClass* tex=Texture->As_CubeTextureClass(); + + if (tex) + { + Format = tex->Get_Texture_Format(); // don't assume format yet KM + } + else + { + Format = WW3D_FORMAT_UNKNOWN; + } + + Width = 0; + Height = 0; + MipLevelCount = Texture->MipLevelCount; + Reduction = Texture->Get_Reduction(); + HSVShift = Texture->Get_HSV_Shift(); + + + for (int f=0; f<6; f++) + { + for (int i = 0; i < MIP_LEVELS_MAX; ++i) + { + LockedCubeSurfacePtr[f][i] = NULL; + LockedCubeSurfacePitch[f][i] = 0; + } + } + + switch (Type) + { + case TASK_THUMBNAIL: + WWASSERT(Texture->ThumbnailLoadTask == NULL); + Texture->ThumbnailLoadTask = this; + break; + + case TASK_LOAD: + WWASSERT(Texture->TextureLoadTask == NULL); + Texture->TextureLoadTask = this; + break; + } +} + + +void CubeTextureLoadTaskClass::Deinit() +{ + // task should not be on any list when it is being detached from texture. + WWASSERT(Next == NULL); + WWASSERT(Prev == NULL); + + WWASSERT(D3DTexture == NULL); + + for (int f=0; f<6; f++) + { + for (int i = 0; i < MIP_LEVELS_MAX; ++i) + { + WWASSERT(LockedCubeSurfacePtr[f][i] == NULL); + } + } + + if (Texture) + { + switch (Type) + { + case TASK_THUMBNAIL: + WWASSERT(Texture->ThumbnailLoadTask == this); + Texture->ThumbnailLoadTask = NULL; + break; + + case TASK_LOAD: + WWASSERT(Texture->TextureLoadTask == this); + Texture->TextureLoadTask = NULL; + break; + } + + // NOTE: we must be in main thread to avoid corrupting Texture's refcount. + WWASSERT(TextureLoader::Is_DX8_Thread()); + REF_PTR_RELEASE(Texture); + } +} + +void CubeTextureLoadTaskClass::Lock_Surfaces(void) +{ + for (unsigned int f=0; f<6; f++) + { + for (unsigned int i=0; iLockRect + ( + (D3DCUBEMAP_FACES)f, + i, + &locked_rect, + NULL, + 0 + ) + ); + LockedCubeSurfacePtr[f][i] = (unsigned char *)locked_rect.pBits; + LockedCubeSurfacePitch[f][i]= locked_rect.Pitch; + } + } +} +void CubeTextureLoadTaskClass::Unlock_Surfaces(void) +{ + for (unsigned int f=0; f<6; f++) + { + for (unsigned int i = 0; i < MipLevelCount; ++i) + { + if (LockedCubeSurfacePtr[f][i]) + { + WWASSERT(ThreadClass::_Get_Current_Thread_ID() == DX8Wrapper::_Get_Main_Thread_ID()); + DX8_ErrorCode + ( + Peek_D3D_Cube_Texture()->UnlockRect((D3DCUBEMAP_FACES)f,i) + ); + } + LockedCubeSurfacePtr[f][i] = NULL; + } } -*/ -// ---------------------------------------------------------------------------- -// -// -// -// ---------------------------------------------------------------------------- +#ifndef USE_MANAGED_TEXTURES + IDirect3DCubeTexture8* tex = DX8Wrapper::_Create_DX8_Cube_Texture + ( + Width, + Height, + Format, + Texture->MipLevelCount, + D3DPOOL_DEFAULT + ); + DX8CALL(UpdateTexture(Peek_D3D_Volume_Texture(),tex)); + Peek_D3D_Volume_Texture()->Release(); + D3DTexture=tex; + WWDEBUG_SAY(("Created non-managed texture (%s)",Texture->Get_Full_Path())); +#endif -void TextureLoadTaskClass::Begin_Thumbnail_Load() -{ -// CriticalSectionClass::LockClass m(mutex); - - unsigned thread_id=ThreadClass::_Get_Current_Thread_ID(); - if (thread_id==DX8Wrapper::_Get_Main_Thread_ID()) { - WW3DFormat format=Texture->Get_Texture_Format(); - // No compressed thumbnails - switch (format) { - case WW3D_FORMAT_DXT1: - case WW3D_FORMAT_DXT2: - case WW3D_FORMAT_DXT3: - case WW3D_FORMAT_DXT4: - case WW3D_FORMAT_DXT5: - format=WW3D_FORMAT_A8R8G8B8; break; - default: - break; +} + + + +bool CubeTextureLoadTaskClass::Begin_Compressed_Load() +{ + unsigned orig_w,orig_h,orig_d,orig_mip_count,reduction; + WW3DFormat orig_format; + if (!Get_Texture_Information + ( + Texture->Get_Full_Path(), + reduction, + orig_w, + orig_h, + orig_d, + orig_format, + orig_mip_count, + true + ) + ) + { + return false; + } + + // Destination size will be the next power of two square from the larger width and height... + unsigned int width = orig_w; + unsigned int height = orig_h; + TextureLoader::Validate_Texture_Size(width, height,orig_d); + + // If the size doesn't match, try and see if texture reduction would help... (mainly for + // cases where loaded texture is larger than hardware limit) + if (width != orig_w || height != orig_h) + { + for (unsigned int i = 1; i < orig_mip_count; ++i) + { + unsigned w=orig_w>>i; + if (w<4) w=4; + unsigned h=orig_h>>i; + if (h<4) h=4; + unsigned tmp_w=w; + unsigned tmp_h=h; + + TextureLoader::Validate_Texture_Size(w,h,orig_d); + + if (w == tmp_w && h == tmp_h) + { + Reduction += i; + width = w; + height = h; + break; + } } - D3DTexture=TextureLoader::Load_Thumbnail(Texture->Get_Full_Path(),format); + } - // Thumbnail loads are always high priority, so apply immediatelly - End_Load(); - Apply(false); - Add_Task_To_Delete_List(this); - return; + Width = width; + Height = height; + Format = Get_Valid_Texture_Format(orig_format, Texture->Is_Compression_Allowed()); + + unsigned int mip_level_count = Get_Mip_Level_Count(); + + // If texture wants all mip levels, take as many as the file contains (not necessarily all) + // Otherwise take as many mip levels as the texture wants, not to exceed the count in file... + if (!mip_level_count) + { + mip_level_count = orig_mip_count;//dds_file.Get_Mip_Level_Count(); } - else { - Add_Thumbnail_Task(this); + else if (mip_level_count > orig_mip_count) + {//dds_file.Get_Mip_Level_Count()) { + mip_level_count = orig_mip_count;//dds_file.Get_Mip_Level_Count(); + } + + // Once more, verify that the mip level count is correct (in case it was changed here it might not + // match the size...well actually it doesn't have to match but it can't be bigger than the size) + unsigned int max_mip_level_count = 1; + unsigned int w = 4; + unsigned int h = 4; + + while (w < Width && h < Height) + { + w += w; + h += h; + max_mip_level_count++; } + + if (mip_level_count > max_mip_level_count) + { + mip_level_count = max_mip_level_count; + } + + D3DTexture = DX8Wrapper::_Create_DX8_Cube_Texture + ( + Width, + Height, + Format, + (MipCountType)mip_level_count, +#ifdef USE_MANAGED_TEXTURES + D3DPOOL_MANAGED +#else + D3DPOOL_SYSTEMMEM +#endif + ); + + MipLevelCount = mip_level_count; + return true; } -// ---------------------------------------------------------------------------- -// -// Deinit can be called multiple times. If any surfaces are locked this call -// can only be called from the main thread. -// -// ---------------------------------------------------------------------------- +bool CubeTextureLoadTaskClass::Begin_Uncompressed_Load(void) +{ + unsigned width,height,depth,orig_mip_count,reduction; + WW3DFormat orig_format; + if (!Get_Texture_Information + ( + Texture->Get_Full_Path(), + reduction, + width, + height, + depth, + orig_format, + orig_mip_count, + false + ) + ) + { + return false; + } + + WW3DFormat src_format=orig_format; + WW3DFormat dest_format=src_format; + dest_format=Get_Valid_Texture_Format(dest_format,false); // No compressed destination format if reading from targa... + + if ( src_format != WW3D_FORMAT_A8R8G8B8 + && src_format != WW3D_FORMAT_R8G8B8 + && src_format != WW3D_FORMAT_X8R8G8B8 ) + { + WWDEBUG_SAY(("Invalid TGA format used in %s - only 24 and 32 bit formats should be used!", Texture->Get_Full_Path().str())); + } + + // Destination size will be the next power of two square from the larger width and height... + unsigned ow = width; + unsigned oh = height; + TextureLoader::Validate_Texture_Size(width, height,depth); + if (width != ow || height != oh) + { + WWDEBUG_SAY(("Invalid texture size, scaling required. Texture: %s, size: %d x %d -> %d x %d", Texture->Get_Full_Path().str(), ow, oh, width, height)); + } + + Width = width; + Height = height; + + if (Format == WW3D_FORMAT_UNKNOWN) + { + Format=dest_format; + } + else + { + Format = Get_Valid_Texture_Format(Format, false); + } + + D3DTexture = DX8Wrapper::_Create_DX8_Cube_Texture + ( + Width, + Height, + Format, + Texture->MipLevelCount, +#ifdef USE_MANAGED_TEXTURES + D3DPOOL_MANAGED +#else + D3DPOOL_SYSTEMMEM +#endif + ); + + return true; +} -void TextureLoadTaskClass::End_Load() +bool CubeTextureLoadTaskClass::Load_Compressed_Mipmap(void) { - for (unsigned i=0;iUnlockRect(i)); + DDSFileClass dds_file(Texture->Get_Full_Path(), Get_Reduction()); + + // if we can't load from file, indicate rror. + if (!dds_file.Is_Available() || !dds_file.Load()) + { + return false; + } + + // load cube map faces + for (unsigned int face=0; face<6; face++) + { + unsigned int width = Get_Width(); + unsigned int height = Get_Height(); + + for (unsigned int level=0; level>=1; + height>>=1; } - LockedSurfacePtr[i]=NULL; } - IsLoading=false; + return true; } -// ---------------------------------------------------------------------------- -// -// Link the node to another task node. This can only be done if the node isn't -// linked to something else already. If the node is linked to some other node, -// the only acceptable parameter to this function is NULL, which will unlink -// the connection. -// -// ---------------------------------------------------------------------------- +unsigned char* CubeTextureLoadTaskClass::Get_Locked_CubeMap_Surface_Pointer(unsigned int face, unsigned int level) +{ + WWASSERT(face<6 && levelGet_Full_Path().Is_Empty()); + + Type = type; + Priority = priority; + State = STATE_NONE; + + D3DTexture = 0; + + VolumeTextureClass* tex=Texture->As_VolumeTextureClass(); + + if (tex) + { + Format = tex->Get_Texture_Format(); // don't assume format yet KM + } + else + { + Format = WW3D_FORMAT_UNKNOWN; } - Texture->Apply_New_Surface(initialize); + Width = 0; + Height = 0; + Depth = 0; + MipLevelCount = Texture->MipLevelCount; + Reduction = Texture->Get_Reduction(); + HSVShift = Texture->Get_HSV_Shift(); - D3DTexture->Release(); - D3DTexture=NULL; -} -// ---------------------------------------------------------------------------- -// -// Return locked surface pointer at a specific level. The call will -// assert if level is greater or equal to the number of mip levels or if the -// requested level has not been locked. -// -// ---------------------------------------------------------------------------- + for (int i = 0; i < MIP_LEVELS_MAX; ++i) + { + LockedSurfacePtr[i] = NULL; + LockedSurfacePitch[i] = 0; + LockedSurfaceSlicePitch[i] = 0; + } -unsigned char* TextureLoadTaskClass::Get_Locked_Surface_Ptr(unsigned level) + switch (Type) + { + case TASK_THUMBNAIL: + WWASSERT(Texture->ThumbnailLoadTask == NULL); + Texture->ThumbnailLoadTask = this; + break; + + case TASK_LOAD: + WWASSERT(Texture->TextureLoadTask == NULL); + Texture->TextureLoadTask = this; + break; + } +} + +void VolumeTextureLoadTaskClass::Lock_Surfaces() { - WWASSERT(levelLockBox + ( + i, + &locked_box, + NULL, + 0 + ) + ); + LockedSurfacePtr[i] = (unsigned char *)locked_box.pBits; + LockedSurfacePitch[i] = locked_box.RowPitch; + LockedSurfaceSlicePitch[i] = locked_box.SlicePitch; + } } -// ---------------------------------------------------------------------------- -// -// Return locked surface pitch (in bytes) at a specific level. The call will -// assert if level is greater or equal to the number of mip levels or if the -// requested level has not been locked. -// -// ---------------------------------------------------------------------------- -unsigned TextureLoadTaskClass::Get_Locked_Surface_Pitch(unsigned level) const +void VolumeTextureLoadTaskClass::Unlock_Surfaces() { - WWASSERT(levelUnlockBox(i) + ); + } + LockedSurfacePtr[i] = NULL; + } + +#ifndef USE_MANAGED_TEXTURES + IDirect3DTexture8* tex = DX8Wrapper::_Create_DX8_Volume_Texture(Width, Height, Depth, Format, Texture->MipLevelCount,D3DPOOL_DEFAULT); + DX8CALL(UpdateTexture(Peek_D3D_Volume_Texture(),tex)); + Peek_D3D_Volume_Texture()->Release(); + D3DTexture=tex; + WWDEBUG_SAY(("Created non-managed texture (%s)",Texture->Get_Full_Path())); +#endif + } -// ---------------------------------------------------------------------------- -// -// Load tasks are stored in a pool when they are not used. If the pool is empty -// a new task is created. -// -// ---------------------------------------------------------------------------- -TextureLoadTaskClass* TextureLoadTaskClass::Get_Instance(TextureBaseClass* tc, bool high_priority) + +bool VolumeTextureLoadTaskClass::Begin_Compressed_Load() { - CriticalSectionClass::LockClass m(mutex); + unsigned orig_w,orig_h,orig_d,orig_mip_count,reduction; + WW3DFormat orig_format; + if (!Get_Texture_Information + ( + Texture->Get_Full_Path(), + reduction, + orig_w, + orig_h, + orig_d, + orig_format, + orig_mip_count, + true + ) + ) + { + return false; + } - TextureLoadTaskClass* task=FreeTaskListHead; - if (task) { - FreeTaskListHead=task->Peek_Succ(); - task->Set_Succ(NULL); + // Destination size will be the next power of two square from the larger width and height... + unsigned int width = orig_w; + unsigned int height = orig_h; + unsigned int depth = orig_d; + TextureLoader::Validate_Texture_Size(width, height, depth); + + // If the size doesn't match, try and see if texture reduction would help... (mainly for + // cases where loaded texture is larger than hardware limit) + if (width != orig_w || height != orig_h || depth != orig_d) + { + for (unsigned int i = 1; i < orig_mip_count; ++i) + { + unsigned w=orig_w>>i; + if (w<4) w=4; + unsigned h=orig_h>>i; + if (h<4) h=4; + unsigned d=orig_d>>i; + if (d<1) d=1; + unsigned tmp_w=w; + unsigned tmp_h=h; + unsigned tmp_d=d; + + TextureLoader::Validate_Texture_Size(w,h,d); + + if (w == tmp_w && h == tmp_h && d== tmp_d) + { + Reduction += i; + width = w; + height = h; + depth = d; + break; + } + } } - else { - task=W3DNEW TextureLoadTaskClass(); + + Width = width; + Height = height; + Depth = depth; + Format = Get_Valid_Texture_Format(orig_format, Texture->Is_Compression_Allowed()); + + unsigned int mip_level_count = Get_Mip_Level_Count(); + + // If texture wants all mip levels, take as many as the file contains (not necessarily all) + // Otherwise take as many mip levels as the texture wants, not to exceed the count in file... + if (!mip_level_count) + { + mip_level_count = orig_mip_count;//dds_file.Get_Mip_Level_Count(); } - task->Init(tc,high_priority); - return task; + else if (mip_level_count > orig_mip_count) + {//dds_file.Get_Mip_Level_Count()) { + mip_level_count = orig_mip_count;//dds_file.Get_Mip_Level_Count(); + } + + // Once more, verify that the mip level count is correct (in case it was changed here it might not + // match the size...well actually it doesn't have to match but it can't be bigger than the size) + unsigned int max_mip_level_count = 1; + unsigned int w = 4; + unsigned int h = 4; + + while (w < Width && h < Height) + { + w += w; + h += h; + max_mip_level_count++; + } + if (mip_level_count > max_mip_level_count) + { + mip_level_count = max_mip_level_count; + } + + D3DTexture = DX8Wrapper::_Create_DX8_Volume_Texture + ( + Width, + Height, + Depth, + Format, + (MipCountType)mip_level_count, +#ifdef USE_MANAGED_TEXTURES + D3DPOOL_MANAGED +#else + D3DPOOL_SYSTEMMEM +#endif + ); + + MipLevelCount = mip_level_count; + return true; } -// ---------------------------------------------------------------------------- -// -// When task is no longer needed it is returned to the pool. -// -// ---------------------------------------------------------------------------- +bool VolumeTextureLoadTaskClass::Begin_Uncompressed_Load(void) +{ + unsigned width,height,depth,orig_mip_count,reduction; + WW3DFormat orig_format; + if (!Get_Texture_Information + ( + Texture->Get_Full_Path(), + reduction, + width, + height, + depth, + orig_format, + orig_mip_count, + false + ) + ) + { + return false; + } + + WW3DFormat src_format=orig_format; + WW3DFormat dest_format=src_format; + dest_format=Get_Valid_Texture_Format(dest_format,false); // No compressed destination format if reading from targa... + + if ( src_format != WW3D_FORMAT_A8R8G8B8 + && src_format != WW3D_FORMAT_R8G8B8 + && src_format != WW3D_FORMAT_X8R8G8B8 ) + { + WWDEBUG_SAY(("Invalid TGA format used in %s - only 24 and 32 bit formats should be used!", Texture->Get_Full_Path().str())); + } + + // Destination size will be the next power of two square from the larger width and height... + unsigned ow = width; + unsigned oh = height; + unsigned od = depth; + TextureLoader::Validate_Texture_Size(width, height, depth); + if (width != ow || height != oh || depth != od) + { + WWDEBUG_SAY(("Invalid texture size, scaling required. Texture: %s, size: %d x %d -> %d x %d", Texture->Get_Full_Path().str(), ow, oh, width, height)); + } + + Width = width; + Height = height; + Depth = depth; + + if (Format == WW3D_FORMAT_UNKNOWN) + { + Format=dest_format; + } + else + { + Format = Get_Valid_Texture_Format(Format, false); + } -void TextureLoadTaskClass::Release_Instance(TextureLoadTaskClass* task) + D3DTexture = DX8Wrapper::_Create_DX8_Volume_Texture + ( + Width, + Height, + Depth, + Format, + Texture->MipLevelCount, +#ifdef USE_MANAGED_TEXTURES + D3DPOOL_MANAGED +#else + D3DPOOL_SYSTEMMEM +#endif + ); + + return true; +} + +bool VolumeTextureLoadTaskClass::Load_Compressed_Mipmap(void) { - if (!task) return; + DDSFileClass dds_file(Texture->Get_Full_Path(), Get_Reduction()); + + // if we can't load from file, indicate rror. + if (!dds_file.Is_Available() || !dds_file.Load()) + { + return false; + } - CriticalSectionClass::LockClass m(mutex); + // load volume + unsigned int depth=dds_file.Get_Depth(0); + unsigned int width=Get_Width(); + unsigned int height=Get_Height(); + + WWASSERT(width && height && depth); + + for (unsigned int level=0; level>=1; + height>>=1; + depth>>=1; + } - task->Deinit(); + return true; +} - // Task must not be in any list when it is being freed - WWASSERT(task->Peek_Succ()==NULL); +unsigned char* VolumeTextureLoadTaskClass::Get_Locked_Volume_Pointer(unsigned int level) +{ + WWASSERT(levelSet_Succ(FreeTaskListHead); - FreeTaskListHead=task; +unsigned int VolumeTextureLoadTaskClass::Get_Locked_Volume_Row_Pitch(unsigned int level) +{ + WWASSERT(level. */ +/*********************************************************************************************** + *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** + *********************************************************************************************** + * * + * Project Name : DX8 Texture Manager * + * * + * $Archive:: /Commando/Code/ww3d2/textureloader.h $* + * * + * Original Author:: vss_sync * + * * + * Author : Kenny Mitchell * + * * + * $Modtime:: 06/27/02 1:27p $* + * * + * $Revision:: 2 $* + * * + * 06/27/02 KM Texture class abstraction * + *---------------------------------------------------------------------------------------------* + * Functions: * + * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + #pragma once #include "always.h" @@ -27,107 +48,279 @@ class TextureLoadTaskClass; class TextureLoader { - static void Init_Load_Task(TextureBaseClass* tc); - - static bool Load_Uncompressed_Mipmap_Levels_From_TGA(TextureLoadTaskClass* texture); - public: - static void Init(); - static void Deinit(); + static void Init(void); + static void Deinit(void); // Modify given texture size to nearest valid size on current hardware. static void Validate_Texture_Size(unsigned& width, unsigned& height, unsigned& depth); - // Adds a loading task to the system. The task if processed in a separate - // thread as soon as possible. The task will appear in finished tasks list - // when it's been completed. The texture will be refreshed on the next - // update call after appearing to the finished tasks list. - static void Add_Load_Task(TextureBaseClass* tc); - static IDirect3DTexture8* Load_Thumbnail( - const StringClass& filename, - WW3DFormat texture_format); // Pass WW3D_FORMAT_UNKNOWN if you don't care - static void Load_Mipmap_Levels(TextureLoadTaskClass* texture); + static IDirect3DTexture8 * Load_Thumbnail( + const StringClass& filename,const Vector3& hsv_shift); +// WW3DFormat texture_format); // Pass WW3D_FORMAT_UNKNOWN if you don't care - static IDirect3DSurface8* Load_Surface_Immediate( + static IDirect3DSurface8 * Load_Surface_Immediate( const StringClass& filename, WW3DFormat surface_format, // Pass WW3D_FORMAT_UNKNOWN if you don't care bool allow_compression); + static void Request_Thumbnail(TextureBaseClass* tc); + + // Adds a loading task to the system. The task if processed in a separate + // thread as soon as possible. The task will appear in finished tasks list + // when it's been completed. The texture will be refreshed on the next + // update call after appearing to the finished tasks list. + static void Request_Background_Loading(TextureBaseClass* tc); + // Textures can only be created and locked by the main thread so this function sends a request to the texture // handling system to load the texture immediatelly next time it enters the main thread. If this function // is called from the main thread the texture is loaded immediatelly. - static void Request_High_Priority_Loading( - TextureBaseClass* texture, - MipCountType mip_level_count); - static void Request_Thumbnail(TextureBaseClass* tc); + static void Request_Foreground_Loading(TextureBaseClass* tc); + + static void Flush_Pending_Load_Tasks(void); + static void Update(void(*network_callback)(void) = NULL); + + // returns true if current thread of execution is allowed to make DX8 calls. + static bool Is_DX8_Thread(void); + + static void Suspend_Texture_Load(); + static void Continue_Texture_Load(); + + static void Set_Texture_Inactive_Override_Time(int time_ms) {TextureInactiveOverrideTime = time_ms;} + +private: + static void Process_Foreground_Load (TextureLoadTaskClass *task); + static void Process_Foreground_Thumbnail (TextureLoadTaskClass *task); + + static void Begin_Load_And_Queue (TextureLoadTaskClass *task); + static void Load_Thumbnail (TextureBaseClass *tc); + + static bool TextureLoadSuspended; + + // The time in ms before a texture is thrown out. + // The default is zero. The scripted movies set this to reduce texture stalls in movies. + static int TextureInactiveOverrideTime; +}; + +class TextureLoadTaskListNodeClass +{ + friend class TextureLoadTaskListClass; + + public: + TextureLoadTaskListNodeClass(void) : Next(0), Prev(0) { } + + TextureLoadTaskListClass *Get_List(void) { return List; } + + TextureLoadTaskListNodeClass *Next; + TextureLoadTaskListNodeClass *Prev; + TextureLoadTaskListClass * List; +}; + + +class TextureLoadTaskListClass +{ + // This class implements an unsynchronized, double-linked list of TextureLoadTaskClass + // objects, using an embedded list node. + + public: + TextureLoadTaskListClass(void); + + // Returns true if list is empty, false otherwise. + bool Is_Empty (void) const { return (Root.Next == &Root); } + + // Add a task to beginning of list + void Push_Front (TextureLoadTaskClass *task); + + // Add a task to end of list + void Push_Back (TextureLoadTaskClass *task); + + // Remove and return a task from beginning of list, or NULL if list is empty. + TextureLoadTaskClass * Pop_Front (void); + + // Remove and return a task from end of list, or NULL if list is empty + TextureLoadTaskClass * Pop_Back (void); + + // Remove specified task from list, if present + void Remove (TextureLoadTaskClass *task); + + private: + // This list is implemented using a sentinel node. + TextureLoadTaskListNodeClass Root; +}; + + +class SynchronizedTextureLoadTaskListClass : public TextureLoadTaskListClass +{ + // This class added thread-safety to the basic TextureLoadTaskListClass. - static void Update(); - static void Flush_Pending_Load_Tasks(); + public: + SynchronizedTextureLoadTaskListClass(void); - static IDirect3DTexture8* Generate_Bumpmap(TextureBaseClass* texture); + // See comments above for description of member functions. + void Push_Front (TextureLoadTaskClass *task); + void Push_Back (TextureLoadTaskClass *task); + TextureLoadTaskClass * Pop_Front (void); + TextureLoadTaskClass * Pop_Back (void); + void Remove (TextureLoadTaskClass *task); + private: + FastCriticalSectionClass CriticalSection; }; -// ---------------------------------------------------------------------------- -// -// Texture loader task handler -// -// ---------------------------------------------------------------------------- +/* +** (gth) The allocation system we're using for TextureLoadTaskClass has gotten a little +** complicated since Kenny added the new task types for Cube and Volume textures. The +** ::Destroy member is used to return a task to the pool now and must be over-ridden in +** each derived class to put the task back into the correct free list. +*/ + + +class TextureLoadTaskClass : public TextureLoadTaskListNodeClass +{ + public: + enum TaskType { + TASK_NONE, + TASK_THUMBNAIL, + TASK_LOAD, + }; + + enum PriorityType { + PRIORITY_LOW, + PRIORITY_HIGH, + }; + + enum StateType { + STATE_NONE, + + STATE_LOAD_BEGUN, + STATE_LOAD_MIPMAP, + STATE_LOAD_COMPLETE, + + STATE_COMPLETE, + }; + + + TextureLoadTaskClass(void); + ~TextureLoadTaskClass(void); + + static TextureLoadTaskClass * Create (TextureBaseClass *tc, TaskType type, PriorityType priority); + static void Delete_Free_Pool (void); + + virtual void Destroy (void); + virtual void Init (TextureBaseClass *tc, TaskType type, PriorityType priority); + virtual void Deinit (void); + + TaskType Get_Type (void) const { return Type; } + PriorityType Get_Priority (void) const { return Priority; } + StateType Get_State (void) const { return State; } + + WW3DFormat Get_Format (void) const { return Format; } + unsigned int Get_Width (void) const { return Width; } + unsigned int Get_Height (void) const { return Height; } + unsigned int Get_Mip_Level_Count (void) const { return MipLevelCount; } + unsigned int Get_Reduction (void) const { return Reduction; } + + unsigned char * Get_Locked_Surface_Ptr (unsigned int level); + unsigned int Get_Locked_Surface_Pitch(unsigned int level) const; + + TextureBaseClass * Peek_Texture (void) { return Texture; } + IDirect3DTexture8 * Peek_D3D_Texture (void) { return (IDirect3DTexture8*)D3DTexture; } -class TextureLoadTaskClass : public W3DMPO + void Set_Type (TaskType t) { Type = t; } + void Set_Priority (PriorityType p) { Priority = p; } + void Set_State (StateType s) { State = s; } + + bool Begin_Load (void); + bool Load (void); + void End_Load (void); + void Finish_Load (void); + void Apply_Missing_Texture (void); + + protected: + virtual bool Begin_Compressed_Load (void); + virtual bool Begin_Uncompressed_Load (void); + + virtual bool Load_Compressed_Mipmap (void); + virtual bool Load_Uncompressed_Mipmap(void); + + virtual void Lock_Surfaces (void); + virtual void Unlock_Surfaces (void); + + void Apply (bool initialize); + + TextureBaseClass* Texture; + IDirect3DBaseTexture8* D3DTexture; + WW3DFormat Format; + + unsigned int Width; + unsigned int Height; + unsigned int MipLevelCount; + unsigned int Reduction; + Vector3 HSVShift; + + unsigned char * LockedSurfacePtr[MIP_LEVELS_MAX]; + unsigned int LockedSurfacePitch[MIP_LEVELS_MAX]; + + TaskType Type; + PriorityType Priority; + StateType State; +}; + +class CubeTextureLoadTaskClass : public TextureLoadTaskClass { - W3DMPO_GLUE(TextureLoadTaskClass) - - static TextureLoadTaskClass* FreeTaskListHead; - - TextureBaseClass* Texture; - IDirect3DTexture8 *D3DTexture; - unsigned Width; - unsigned Height; - WW3DFormat Format; - unsigned char* LockedSurfacePtr[MIP_LEVELS_MAX]; - unsigned LockedSurfacePitch[MIP_LEVELS_MAX]; - unsigned MipLevelCount; - unsigned Reduction; - TextureLoadTaskClass* Succ; - bool IsLoading; - bool HasFailed; - bool HighPriorityRequested; - - ~TextureLoadTaskClass(); - TextureLoadTaskClass(); public: - static TextureLoadTaskClass* Get_Instance(TextureBaseClass* tc, bool high_priority); - static void Release_Instance(TextureLoadTaskClass* task); - static void shutdown(void) {TextureLoadTaskClass *pT; while (FreeTaskListHead) {pT = FreeTaskListHead; FreeTaskListHead = pT->Peek_Succ(); pT->Set_Succ(NULL); delete pT;} }; + CubeTextureLoadTaskClass(); - void Init(TextureBaseClass* tc,bool high_priority); - void Deinit(); + virtual void Destroy (void); + virtual void Init (TextureBaseClass *tc, TaskType type, PriorityType priority); + virtual void Deinit (void); + +protected: + virtual bool Begin_Compressed_Load (void); + virtual bool Begin_Uncompressed_Load (void); + + virtual bool Load_Compressed_Mipmap (void); +// virtual bool Load_Uncompressed_Mipmap(void); + + virtual void Lock_Surfaces (void); + virtual void Unlock_Surfaces (void); + +private: + unsigned char* Get_Locked_CubeMap_Surface_Pointer(unsigned int face, unsigned int level); + unsigned int Get_Locked_CubeMap_Surface_Pitch(unsigned int face, unsigned int level) const; + + IDirect3DCubeTexture8* Peek_D3D_Cube_Texture(void) { return (IDirect3DCubeTexture8*)D3DTexture; } + + unsigned char* LockedCubeSurfacePtr[6][MIP_LEVELS_MAX]; + unsigned int LockedCubeSurfacePitch[6][MIP_LEVELS_MAX]; +}; + +class VolumeTextureLoadTaskClass : public TextureLoadTaskClass +{ +public: + VolumeTextureLoadTaskClass(); - unsigned Get_Mip_Level_Count() const { return MipLevelCount; } - unsigned Get_Width() const { return Width; } - unsigned Get_Height() const { return Height; } - WW3DFormat Get_Format() const { return Format; } - unsigned Get_Reduction() const { return Reduction; } + virtual void Destroy (void); + virtual void Init (TextureBaseClass *tc, TaskType type, PriorityType priority); - unsigned char* Get_Locked_Surface_Ptr(unsigned level); - unsigned Get_Locked_Surface_Pitch(unsigned level) const; +protected: + virtual bool Begin_Compressed_Load (void); + virtual bool Begin_Uncompressed_Load (void); - bool Has_Failed() const { return HasFailed; } - void Set_Fail(bool b) { HasFailed=b; } + virtual bool Load_Compressed_Mipmap (void); +// virtual bool Load_Uncompressed_Mipmap(void); - // Init the task or put it to a deferred init list if called from outside the main thread - void Begin_Texture_Load(); - void Begin_Thumbnail_Load(); - void End_Load(); // Deinit must be called before Applying() + virtual void Lock_Surfaces (void); + virtual void Unlock_Surfaces (void); - void Apply(bool initialize); +private: + unsigned char* Get_Locked_Volume_Pointer(unsigned int level); + unsigned int Get_Locked_Volume_Row_Pitch(unsigned int level); + unsigned int Get_Locked_Volume_Slice_Pitch(unsigned int level); - TextureLoadTaskClass* Peek_Succ() { return Succ; } - void Set_Succ(TextureLoadTaskClass* succ); + IDirect3DVolumeTexture8* Peek_D3D_Volume_Texture(void) { return (IDirect3DVolumeTexture8*)D3DTexture; } - TextureBaseClass* Peek_Texture() { return Texture; } - IDirect3DTexture8* Peek_D3D_Texture() { return D3DTexture; } + unsigned int LockedSurfaceSlicePitch[MIP_LEVELS_MAX]; - void Set_D3D_Texture(IDirect3DTexture8* texture); + unsigned int Depth; }; diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/texturethumbnail.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/texturethumbnail.cpp index 65744fb9136..24d385fbf2f 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/texturethumbnail.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/texturethumbnail.cpp @@ -25,21 +25,69 @@ #include "textureloader.h" #include "bitmaphandler.h" #include "ffactory.h" +#include "RAWFILE.h" +#include "wwprofile.h" +#include -static HashTemplateClass thumbnail_hash; -static bool _ThumbHashModified; -static unsigned char* _ThumbnailMemory; -static const char *THUMBNAIL_FILENAME = "thumbnails.dat"; +static DLListClass ThumbnailManagerList; +static ThumbnailManagerClass* GlobalThumbnailManager; +bool ThumbnailManagerClass::CreateThumbnailIfNotFound=false; -ThumbnailClass::ThumbnailClass(const char* name, unsigned char* bitmap, unsigned w, unsigned h, bool allocated) +static void Create_Hash_Name(StringClass& name, const StringClass& thumb_name) +{ + name=thumb_name; + int len=name.Get_Length(); + WWASSERT(!stricmp(&name[len-4],".tga") || !stricmp(&name[len-4],".dds")); + name[len-4]='\0'; + _strlwr(name.Peek_Buffer()); +} + + /* file_auto_ptr my_tga_file(_TheFileFactory,filename); + if (my_tga_file->Is_Available()) { + my_tga_file->Open(); + unsigned size=my_tga_file->Size(); + char* tga_memory=new char[size]; + my_tga_file->Read(tga_memory,size); + my_tga_file->Close(); + + StringClass pth("data\\"); + pth+=filename; + RawFileClass tmp_tga_file(pth); + tmp_tga_file.Create(); + tmp_tga_file.Write(tga_memory,size); + tmp_tga_file.Close(); + delete[] tga_memory; + + } +*/ + + +ThumbnailClass::ThumbnailClass( + ThumbnailManagerClass* manager, + const char* name, + unsigned char* bitmap, + unsigned w, + unsigned h, + unsigned original_w, + unsigned original_h, + unsigned original_mip_level_count, + WW3DFormat original_format, + bool allocated, + unsigned long date_time) : + Manager(manager), Name(name), Bitmap(bitmap), Allocated(allocated), Width(w), - Height(h) + Height(h), + OriginalTextureWidth(original_w), + OriginalTextureHeight(original_h), + OriginalTextureMipLevelCount(original_mip_level_count), + OriginalTextureFormat(original_format), + DateTime(date_time) { - thumbnail_hash.Insert(Name,this); + Manager->Insert_To_Hash(this); } // ---------------------------------------------------------------------------- @@ -51,30 +99,56 @@ ThumbnailClass::ThumbnailClass(const char* name, unsigned char* bitmap, unsigned // // ---------------------------------------------------------------------------- -ThumbnailClass::ThumbnailClass(const StringClass& filename) +ThumbnailClass::ThumbnailClass(ThumbnailManagerClass* manager, const StringClass& filename) : + Manager(manager), Bitmap(0), Name(filename), Allocated(false), Width(0), - Height(0) + Height(0), + OriginalTextureWidth(0), + OriginalTextureHeight(0), + OriginalTextureMipLevelCount(0), + OriginalTextureFormat(WW3D_FORMAT_UNKNOWN), + DateTime(0) { + WWPROFILE(("ThumbnailClass::ThumbnailClass")); unsigned reduction_factor=3; // First, try loading image from a DDS file DDSFileClass dds_file(filename,reduction_factor); if (dds_file.Is_Available() && dds_file.Load()) { + DateTime=dds_file.Get_Date_Time(); + + int len=Name.Get_Length(); + WWASSERT(len>4); + Name[len-3]='d'; + Name[len-2]='d'; + Name[len-1]='s'; + + unsigned level=0; + while (dds_file.Get_Width(level)>32 || dds_file.Get_Height(level)>32) { + if (level>=dds_file.Get_Mip_Level_Count()) break; + level++; + } + + OriginalTextureWidth=dds_file.Get_Full_Width(); + OriginalTextureHeight=dds_file.Get_Full_Height(); + OriginalTextureFormat=dds_file.Get_Format(); + OriginalTextureMipLevelCount=dds_file.Get_Mip_Level_Count(); Width=dds_file.Get_Width(0); Height=dds_file.Get_Height(0); - Bitmap=W3DNEWARRAY unsigned char[Width*Height*4]; + Bitmap=W3DNEWARRAY unsigned char[Width*Height*2]; Allocated=true; dds_file.Copy_Level_To_Surface( 0, // Level - WW3D_FORMAT_A8R8G8B8, + WW3D_FORMAT_A4R4G4B4, Width, Height, Bitmap, - Width*4); + Width*2, + Vector3(0.0f,0.0f,0.0f));// We don't want to HSV-shift here } // If DDS file can't be used try loading from TGA else { @@ -87,13 +161,46 @@ ThumbnailClass::ThumbnailClass(const StringClass& filename) WW3DFormat src_format,dest_format; unsigned src_bpp=0; - Get_WW3D_Format(dest_format,src_format,src_bpp,targa); + Get_WW3D_Format(src_format,src_bpp,targa); + if (src_format==WW3D_FORMAT_UNKNOWN) { + WWDEBUG_SAY(("Unknown texture format for %s",filename.str())); + return; + } // Destination size will be the next power of two square from the larger width and height... + OriginalTextureWidth=targa.Header.Width; + OriginalTextureHeight=targa.Header.Height; + OriginalTextureFormat=src_format; Width=targa.Header.Width>>reduction_factor; Height=targa.Header.Height>>reduction_factor; - unsigned depth=1; - TextureLoader::Validate_Texture_Size(Width,Height,depth); + OriginalTextureMipLevelCount=1; + unsigned iw=1; + unsigned ih=1; + while (iw32 || Height>32) { + reduction_factor++; + Width>>=2; + Height>>=2; + } + + unsigned poweroftwowidth = 1; + while (poweroftwowidth < Width) { + poweroftwowidth <<= 1; + } + + unsigned poweroftwoheight = 1; + while (poweroftwoheight < Height) { + poweroftwoheight <<= 1; + } + + Width=poweroftwowidth; + Height=poweroftwoheight; + unsigned src_width=targa.Header.Width; unsigned src_height=targa.Header.Height; @@ -102,9 +209,24 @@ ThumbnailClass::ThumbnailClass(const StringClass& filename) targa.SetPalette(palette); if (TARGA_ERROR_HANDLER(targa.Load(filename, TGAF_IMAGE, false),filename)) return; + // Get time stamp from the tga file + { + file_auto_ptr my_tga_file(_TheFileFactory,filename); + WWASSERT(my_tga_file->Is_Available()); + my_tga_file->Open(); + DateTime=my_tga_file->Get_Date_Time(); + my_tga_file->Close(); + } + unsigned char* src_surface=(unsigned char*)targa.GetImage(); - Bitmap=W3DNEWARRAY unsigned char[Width*Height*4]; + int len=Name.Get_Length(); + WWASSERT(len>4); + Name[len-3]='t'; + Name[len-2]='g'; + Name[len-1]='a'; + + Bitmap=W3DNEWARRAY unsigned char[Width*Height*2]; Allocated=true; dest_format=WW3D_FORMAT_A8R8G8B8; @@ -112,8 +234,8 @@ ThumbnailClass::ThumbnailClass(const StringClass& filename) Bitmap, Width, Height, - Width*4, - WW3D_FORMAT_A8R8G8B8, + Width*2, + WW3D_FORMAT_A4R4G4B4, src_surface, src_width, src_height, @@ -124,168 +246,165 @@ ThumbnailClass::ThumbnailClass(const StringClass& filename) false); } - _ThumbHashModified=true; - thumbnail_hash.Insert(Name,this); + Manager->Insert_To_Hash(this); } ThumbnailClass::~ThumbnailClass() { if (Allocated) delete[] Bitmap; - thumbnail_hash.Remove(Name); + Manager->Remove_From_Hash(this); } -ThumbnailClass* ThumbnailClass::Peek_Instance(const StringClass& name) + +// ---------------------------------------------------------------------------- +ThumbnailManagerClass::ThumbnailManagerClass(const char* thumbnail_filename) + : + ThumbnailMemory(NULL), + ThumbnailFileName(thumbnail_filename), + PerTextureTimeStampUsed(false), + Changed(false), + DateTime(0) { - return thumbnail_hash.Get(name); } -void ThumbnailClass::Init() +// ---------------------------------------------------------------------------- +ThumbnailManagerClass::~ThumbnailManagerClass() { - WWASSERT(!_ThumbnailMemory); - - // If the thumbnail hash table file is available, init hash table -#if 0 // don't do thumbnail file. - file_auto_ptr thumb_file(_TheFileFactory, THUMBNAIL_FILENAME); - if (thumb_file->Is_Available()) { - thumb_file->Open(FileClass::READ); - - char tmp[4]; - thumb_file->Read(tmp,4); - if (tmp[0]=='T' && tmp[1]=='M' && tmp[2]=='B' && tmp[3]=='1') { - - int total_thumb_count; - int total_header_length; - int total_data_length; - thumb_file->Read(&total_thumb_count,sizeof(int)); - thumb_file->Read(&total_header_length,sizeof(int)); - thumb_file->Read(&total_data_length,sizeof(int)); - if (total_thumb_count) { - WWASSERT(total_data_length && total_header_length); - _ThumbnailMemory=W3DNEWARRAY unsigned char[total_data_length]; - // Load thumbs - for (int i=0;iRead(&offset,sizeof(int)); - thumb_file->Read(&width,sizeof(int)); - thumb_file->Read(&height,sizeof(int)); - thumb_file->Read(&date_time,sizeof(unsigned long)); - thumb_file->Read(&name_len,sizeof(int)); - WWASSERT(name_len<255); - thumb_file->Read(name,name_len); - name[name_len]='\0'; - - - // Make sure the file is available and the timestamp matches - file_auto_ptr myfile(_TheFileFactory,name); - if (myfile->Is_Available()) { - myfile->Open(FileClass::READ); - if (date_time==myfile->Get_Date_Time()) { - W3DNEW ThumbnailClass( - name, - _ThumbnailMemory+offset-total_header_length, - width, - height, - false); - } - myfile->Close(); - } - } - thumb_file->Read(_ThumbnailMemory,total_data_length); - } - } - thumb_file->Close(); + HashTemplateIterator ite(ThumbnailHash); + ite.First(); + while (!ite.Is_Done()) { + ThumbnailClass* thumb=ite.Peek_Value(); + delete thumb; + ite.First(); } -#endif + + delete[] ThumbnailMemory; + ThumbnailMemory=NULL; } -void ThumbnailClass::Deinit() +// ---------------------------------------------------------------------------- +ThumbnailManagerClass* ThumbnailManagerClass::Peek_Thumbnail_Manager(const char* thumbnail_filename) { - // If the thumbnail hash table was modified, save it to disk - HashTemplateIterator ite(thumbnail_hash); - if (_ThumbHashModified) { -#if 0 // don't write thumbnails. jba. - int total_header_length=0; - int total_data_length=0; - int total_thumb_count=0; - total_header_length+=4; // header 'TMB1' - total_header_length+=4; // thumb count - total_header_length+=4; // header size - total_header_length+=4; // data length - - for (ite.First();!ite.Is_Done();ite.Next()) { - total_header_length+=4; // int bitmap offset - total_header_length+=4; // int bitmap width - total_header_length+=4; // int bitmap height - total_header_length+=4; // unsigned long date_time - total_header_length+=4; // int name string length - ThumbnailClass* thumb=ite.Peek_Value(); - total_header_length+=strlen(thumb->Get_Name()); - total_data_length+=thumb->Get_Width()*thumb->Get_Height()*4; - total_thumb_count++; - } - int offset=total_header_length; + ThumbnailManagerClass* man=ThumbnailManagerList.Head(); + while (man) { + if (man->ThumbnailFileName==thumbnail_filename) return man; + man=man->Succ(); + } + if (GlobalThumbnailManager && + GlobalThumbnailManager->ThumbnailFileName==thumbnail_filename) return GlobalThumbnailManager; + return NULL; +} - file_auto_ptr thumb_file(_TheWritingFileFactory, THUMBNAIL_FILENAME); - if (thumb_file->Is_Available()) { - thumb_file->Delete(); +// ---------------------------------------------------------------------------- +void ThumbnailManagerClass::Add_Thumbnail_Manager(const char* thumbnail_filename) +{ + // First loop over all thumbnail managers to see if we already have this one created. This isn't + // supposed to be called often at all and there are usually just couple managers alive, + // so we'll do pure string compares here... + + // Must NOT add global manager with this function + WWASSERT(stricmp(thumbnail_filename,GLOBAL_THUMBNAIL_MANAGER_FILENAME)); + + ThumbnailManagerClass* man=Peek_Thumbnail_Manager(thumbnail_filename); + if (man) return; + + // Not found, create and add to the list. + man=new ThumbnailManagerClass(thumbnail_filename); + ThumbnailManagerList.Add_Tail(man); +} +// ---------------------------------------------------------------------------- +void ThumbnailManagerClass::Remove_Thumbnail_Manager(const char* thumbnail_filename) +{ + ThumbnailManagerClass* man=ThumbnailManagerList.Head(); + while (man) { + if (man->ThumbnailFileName==thumbnail_filename) { + delete man; + return; } - thumb_file->Create(); - thumb_file->Open(FileClass::WRITE); - - char* header="TMB1"; - thumb_file->Write(header,4); - thumb_file->Write(&total_thumb_count,sizeof(int)); - thumb_file->Write(&total_header_length,sizeof(int)); - thumb_file->Write(&total_data_length,sizeof(int)); - - // Save names and offsets - for (ite.First();!ite.Is_Done();ite.Next()) { - ThumbnailClass* thumb=ite.Peek_Value(); - const char* name=thumb->Get_Name(); - int name_len=strlen(name); - int width=thumb->Get_Width(); - int height=thumb->Get_Height(); - unsigned long date_time=0; - file_auto_ptr myfile(_TheFileFactory,name); - if (myfile->Is_Available()) { - myfile->Open(FileClass::READ); - date_time=myfile->Get_Date_Time(); - myfile->Close(); + man=man->Succ(); + } + if (GlobalThumbnailManager && + GlobalThumbnailManager->ThumbnailFileName==thumbnail_filename) { + delete GlobalThumbnailManager; + GlobalThumbnailManager=NULL; + } +} +// ---------------------------------------------------------------------------- +ThumbnailClass* ThumbnailManagerClass::Peek_Thumbnail_Instance(const StringClass& name) +{ + + return Get_From_Hash(name); +} + +ThumbnailClass* ThumbnailManagerClass::Peek_Thumbnail_Instance_From_Any_Manager(const StringClass& filename) +{ + WWPROFILE(("Peek_Thumbnail_Instance_From_Any_Manager")); + ThumbnailManagerClass* thumb_man=ThumbnailManagerList.Head(); + while (thumb_man) { + ThumbnailClass* thumb=thumb_man->Peek_Thumbnail_Instance(filename); + if (thumb) return thumb; + thumb_man=thumb_man->Succ(); + } + + if (GlobalThumbnailManager) { + ThumbnailClass* thumb=GlobalThumbnailManager->Peek_Thumbnail_Instance(filename); + if (thumb) return thumb; + } + +// If thumbnail is not found, see if we can find a texture. It is possible that the texture is outside of +// a mix file and didn't get included in any thumbnail database based on a mixfile. If so, we'll add it to +// our global thumbnail database. + if (Is_Thumbnail_Created_If_Not_Found()) { + if (GlobalThumbnailManager) { + ThumbnailClass* thumb=new ThumbnailClass(GlobalThumbnailManager,filename); + if (!thumb->Peek_Bitmap()) { + delete thumb; + thumb=NULL; } - thumb_file->Write(&offset,sizeof(int)); - thumb_file->Write(&width,sizeof(int)); - thumb_file->Write(&height,sizeof(int)); - thumb_file->Write(&date_time,sizeof(unsigned long)); - thumb_file->Write(&name_len,sizeof(int)); - thumb_file->Write(name,name_len); - offset+=width*height*4; + return thumb; } + } - // Save bitmaps - offset=total_header_length; - for (ite.First();!ite.Is_Done();ite.Next()) { - ThumbnailClass* thumb=ite.Peek_Value(); - int width=thumb->Get_Width(); - int height=thumb->Get_Height(); - thumb_file->Write(thumb->Peek_Bitmap(),width*height*4); - } + return NULL; +} - thumb_file->Close(); -#endif - } - ite.First(); - while (!ite.Is_Done()) { - ThumbnailClass* thumb=ite.Peek_Value(); - delete thumb; - ite.First(); +void ThumbnailManagerClass::Insert_To_Hash(ThumbnailClass* thumb) +{ + Changed=true; + StringClass hash_name(0,true); + Create_Hash_Name(hash_name,thumb->Get_Name()); + ThumbnailHash.Insert(hash_name,thumb); +} + +ThumbnailClass* ThumbnailManagerClass::Get_From_Hash(const StringClass& name) +{ + StringClass hash_name(0,true); + Create_Hash_Name(hash_name,name); + return ThumbnailHash.Get(hash_name); +} + +void ThumbnailManagerClass::Remove_From_Hash(ThumbnailClass* thumb) +{ + Changed=true; + StringClass hash_name(0,true); + Create_Hash_Name(hash_name,thumb->Get_Name()); + ThumbnailHash.Remove(hash_name); +} + +void ThumbnailManagerClass::Init() +{ + WWASSERT(GlobalThumbnailManager == NULL); + GlobalThumbnailManager=new ThumbnailManagerClass(GLOBAL_THUMBNAIL_MANAGER_FILENAME); + GlobalThumbnailManager->Enable_Per_Texture_Time_Stamp(true); +} + +void ThumbnailManagerClass::Deinit() +{ + while (ThumbnailManagerClass* man=ThumbnailManagerList.Head()) { + delete man; } - delete [] _ThumbnailMemory; - _ThumbnailMemory=NULL; + delete GlobalThumbnailManager; + GlobalThumbnailManager=NULL; } diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/texturethumbnail.h b/Generals/Code/Libraries/Source/WWVegas/WW3D2/texturethumbnail.h index b61e4271176..4d740af636e 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/texturethumbnail.h +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/texturethumbnail.h @@ -16,31 +16,107 @@ ** along with this program. If not, see . */ +// 08/07/02 KM Texture class redesign (revisited) + #pragma once #include "always.h" #include "wwstring.h" +#include "hashtemplate.h" +#include "dllist.h" +#include "ww3dformat.h" + +#define GLOBAL_THUMBNAIL_MANAGER_FILENAME "global.th6" + +class ThumbnailManagerClass; // ---------------------------------------------------------------------------- class ThumbnailClass { + friend ThumbnailManagerClass; + StringClass Name; unsigned char* Bitmap; unsigned Width; unsigned Height; + unsigned OriginalTextureWidth; + unsigned OriginalTextureHeight; + unsigned OriginalTextureMipLevelCount; + WW3DFormat OriginalTextureFormat; + unsigned long DateTime; bool Allocated; // if true, destructor will free the memory -public: - ThumbnailClass(const char* name, unsigned char* bitmap, unsigned w, unsigned h, bool allocated); - ThumbnailClass(const StringClass& filename); + ThumbnailManagerClass* Manager; + + ThumbnailClass( + ThumbnailManagerClass* manager, + const char* name, + unsigned char* bitmap, + unsigned w, + unsigned h, + unsigned original_w, + unsigned original_h, + unsigned original_mip_level_count, + WW3DFormat original_format, + bool allocated, + unsigned long date_time); + ThumbnailClass( + ThumbnailManagerClass* manager, + const StringClass& filename); ~ThumbnailClass(); +public: unsigned char* Peek_Bitmap() { return Bitmap; } + WW3DFormat Get_Format() { return WW3D_FORMAT_A4R4G4B4; } unsigned Get_Width() const { return Width; } unsigned Get_Height() const { return Height; } + unsigned Get_Original_Texture_Width() const { return OriginalTextureWidth; } + unsigned Get_Original_Texture_Height() const { return OriginalTextureHeight; } + unsigned Get_Original_Texture_Mip_Level_Count() const { return OriginalTextureMipLevelCount; } + WW3DFormat Get_Original_Texture_Format() const { return OriginalTextureFormat; } + unsigned long Get_Date_Time() const { return DateTime; } const StringClass& Get_Name() const { return Name; } - static ThumbnailClass* Peek_Instance(const StringClass& name); +}; + +// ---------------------------------------------------------------------------- + +class ThumbnailManagerClass : public DLNodeClass +{ + W3DMPO_GLUE(ThumbnailManagerClass); + + friend ThumbnailClass; + + static bool CreateThumbnailIfNotFound; + bool PerTextureTimeStampUsed; + StringClass ThumbnailFileName; + HashTemplateClass ThumbnailHash; + unsigned char* ThumbnailMemory; + bool Changed; + unsigned long DateTime; + + ThumbnailManagerClass(const char* thumbnail_filename); + ~ThumbnailManagerClass(); + + void Remove_From_Hash(ThumbnailClass* thumb); + void Insert_To_Hash(ThumbnailClass* thumb); + ThumbnailClass* Get_From_Hash(const StringClass& name); + +public: + ThumbnailClass* Peek_Thumbnail_Instance(const StringClass& name); + + static void Add_Thumbnail_Manager(const char* thumbnail_filename); + static void Remove_Thumbnail_Manager(const char* thumbnail_filename); + static ThumbnailManagerClass* Peek_Thumbnail_Manager(const char* thumbnail_filename); + + static ThumbnailClass* Peek_Thumbnail_Instance_From_Any_Manager(const StringClass& name); + + static bool Is_Thumbnail_Created_If_Not_Found() { return CreateThumbnailIfNotFound; } + static void Create_Thumbnail_If_Not_Found(bool create) { CreateThumbnailIfNotFound=create; } + + bool Is_Per_Texture_Time_Stamp_Used() const { return PerTextureTimeStampUsed; } + void Enable_Per_Texture_Time_Stamp(bool enable) { PerTextureTimeStampUsed=enable; } + static void Init(); static void Deinit(); }; diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp index dac6fcc1ae4..38d966e5130 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp @@ -248,14 +248,6 @@ void WW3D::Set_NPatches_Level(unsigned level) NPatchesLevel = level; } -void WW3D::Set_Thumbnail_Enabled (bool b) -{ - if (ThumbnailEnabled!=b) { - ThumbnailEnabled = b; - _Invalidate_Textures(); - } -} - /*********************************************************************************************** * WW3D::Init -- Initialize the WW3D Library * * * @@ -775,7 +767,7 @@ void WW3D::Set_Texture_Filter(int texture_filter) if (texture_filter<0) texture_filter=0; if (texture_filter>TextureFilterClass::TEXTURE_FILTER_ANISOTROPIC) texture_filter=TextureFilterClass::TEXTURE_FILTER_ANISOTROPIC; TextureFilter=texture_filter; - TextureFilterClass::_Init_Filters(); + TextureFilterClass::_Init_Filters((TextureFilterClass::TextureFilterMode)TextureFilter); } @@ -826,7 +818,7 @@ WW3DErrorType WW3D::Begin_Render(bool clear,bool clearz,const Vector3 & color, f LastFrameMemoryFrees=WWMemoryLogClass::Get_Free_Count(); WWMemoryLogClass::Reset_Counters(); - TextureLoader::Update(); + TextureLoader::Update(network_callback); // TextureClass::_Reset_Time_Stamp(); DynamicVBAccessClass::_Reset(true); DynamicIBAccessClass::_Reset(true); diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h b/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h index 1e0c158cec8..f169690b695 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h @@ -228,7 +228,7 @@ class WW3D static void _Invalidate_Mesh_Cache(); static void _Invalidate_Textures(); - static void Set_Thumbnail_Enabled(bool b);// { ThumbnailEnabled=b; } + static void Set_Thumbnail_Enabled(bool b) { ThumbnailEnabled=b; } static bool Get_Thumbnail_Enabled() { return ThumbnailEnabled; } static void Enable_Sorting(bool onoff); diff --git a/Generals/Code/Tools/WorldBuilder/src/ObjectPreview.cpp b/Generals/Code/Tools/WorldBuilder/src/ObjectPreview.cpp index 7be46780dd7..0e3cc1618fe 100644 --- a/Generals/Code/Tools/WorldBuilder/src/ObjectPreview.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/ObjectPreview.cpp @@ -218,7 +218,7 @@ static UnsignedByte * generatePreview( const ThingTemplate *tt ) } // Set the render target - DX8Wrapper::Set_Render_Target(objectTexture); + DX8Wrapper::Set_Render_Target_With_Z(objectTexture); // create the camera Bool orthoCamera = false; diff --git a/Generals/Code/Tools/WorldBuilder/src/WorldBuilder.cpp b/Generals/Code/Tools/WorldBuilder/src/WorldBuilder.cpp index 07591396655..9603cd1ec85 100644 --- a/Generals/Code/Tools/WorldBuilder/src/WorldBuilder.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/WorldBuilder.cpp @@ -637,7 +637,6 @@ int CWorldBuilderApp::ExitInstance() delete TheFileSystem; TheFileSystem = NULL; - TextureLoadTaskClass::shutdown(); delete TheW3DFileSystem; TheW3DFileSystem = NULL; diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWater.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWater.cpp index f3189e931e9..2addc0e8ba6 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWater.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWater.cpp @@ -619,8 +619,8 @@ HRESULT WaterRenderObjClass::generateVertexBuffer( Int sizeX, Int sizeY, Int ver { m_numVertices=sizeX*sizeY; //Assuming dynamic vertex buffer, allocate maximum multiple of required size to allow rendering from - //different parts of the buffer. 5-15-03: Disabled this since we use DISCARD mode instead to avoid Nvidia Runtime bug. -MW - //m_numVertices=(65536 / (sizeX*sizeY))*sizeX*sizeY; + //different parts of the buffer. 5-15-03: Disabled this since we use DISCARD mode instead to avoid Nvidia Runtime bug. -MW + //m_numVertices=(65536 / (sizeX*sizeY))*sizeX*sizeY; SEA_PATCH_VERTEX* pVertices; @@ -2229,9 +2229,9 @@ void WaterRenderObjClass::renderWaterMesh(void) if (!m_doWaterGrid) return; //the water grid is disabled. - //According to Nvidia there's a D3D bug that happens if you don't start with a - //new dynamic VB each frame - so we force a DISCARD by overflowing the counter. - m_vertexBufferD3DOffset = 0xffff; + //According to Nvidia there's a D3D bug that happens if you don't start with a + //new dynamic VB each frame - so we force a DISCARD by overflowing the counter. + m_vertexBufferD3DOffset = 0xffff; Setting *setting=&m_settings[m_tod]; diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWaterTracks.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWaterTracks.cpp index 964eb896ac3..afc6ed90131 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWaterTracks.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWaterTracks.cpp @@ -867,9 +867,9 @@ Try improving the fit to vertical surfaces like cliffs. if (!m_usedModules || ShaderClass::Is_Backface_Culling_Inverted()) return; //don't render track marks in reflections. - //According to Nvidia there's a D3D bug that happens if you don't start with a - //new dynamic VB each frame - so we force a DISCARD by overflowing the counter. - m_batchStart = 0xffff; + //According to Nvidia there's a D3D bug that happens if you don't start with a + //new dynamic VB each frame - so we force a DISCARD by overflowing the counter. + m_batchStart = 0xffff; // adjust shading for time of day. Real shadeR, shadeG, shadeB; From 96d463e23f66fc5492da9434432058367262577e Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Sun, 14 Dec 2025 11:46:18 +0100 Subject: [PATCH 2/2] unify(texture): Move W3DWater, W3DLaserDraw and WW3D2 texture related files to Core (#1989) --- Core/GameEngine/CMakeLists.txt | 4 +- .../GameEngine/Include/GameClient/Water.h | 0 .../GameEngine/Source/GameClient/Water.cpp | 0 Core/GameEngineDevice/CMakeLists.txt | 12 +- .../GameClient/Module/W3DLaserDraw.h | 0 .../Include/W3DDevice/GameClient/W3DWater.h | 0 .../W3DDevice/GameClient/W3DWaterTracks.h | 0 .../GameClient/Drawable/Draw/W3DLaserDraw.cpp | 0 .../W3DDevice/GameClient/Water/W3DWater.cpp | 0 .../GameClient/Water/W3DWaterTracks.cpp | 0 .../W3DDevice/GameClient/Water/wave.nvp | 0 .../W3DDevice/GameClient/Water/wave.nvv | 0 .../Source/WWVegas/WW3D2/CMakeLists.txt | 32 +- .../Libraries/Source/WWVegas/WW3D2/bmp2d.cpp | 0 .../Libraries/Source/WWVegas/WW3D2/bmp2d.h | 0 .../Source/WWVegas/WW3D2/dx8texman.cpp | 0 .../Source/WWVegas/WW3D2/dx8texman.h | 0 .../Source/WWVegas/WW3D2/matpass.cpp | 0 .../Libraries/Source/WWVegas/WW3D2/matpass.h | 0 .../Source/WWVegas/WW3D2/texproject.cpp | 0 .../Source/WWVegas/WW3D2/texproject.h | 0 .../Source/WWVegas/WW3D2/texture.cpp | 0 .../Libraries/Source/WWVegas/WW3D2/texture.h | 0 .../Source/WWVegas/WW3D2/texturefilter.cpp | 0 .../Source/WWVegas/WW3D2/texturefilter.h | 0 .../Source/WWVegas/WW3D2/textureloader.cpp | 0 .../Source/WWVegas/WW3D2/textureloader.h | 0 .../Source/WWVegas/WW3D2/texturethumbnail.cpp | 0 .../Source/WWVegas/WW3D2/texturethumbnail.h | 0 Generals/Code/GameEngine/CMakeLists.txt | 4 +- .../GameEngine/Include/GameClient/Water.h | 124 - .../GameEngine/Source/GameClient/Water.cpp | 134 - Generals/Code/GameEngineDevice/CMakeLists.txt | 16 +- .../GameClient/Module/W3DLaserDraw.h | 98 - .../Include/W3DDevice/GameClient/W3DWater.h | 290 -- .../W3DDevice/GameClient/W3DWaterTracks.h | 140 - .../GameClient/Drawable/Draw/W3DLaserDraw.cpp | 468 --- .../W3DDevice/GameClient/Water/W3DWater.cpp | 3489 ----------------- .../GameClient/Water/W3DWaterTracks.cpp | 1309 ------- .../W3DDevice/GameClient/Water/wave.nvp | 54 - .../W3DDevice/GameClient/Water/wave.nvv | 72 - .../Source/WWVegas/WW3D2/CMakeLists.txt | 32 +- .../Libraries/Source/WWVegas/WW3D2/bmp2d.cpp | 299 -- .../Libraries/Source/WWVegas/WW3D2/bmp2d.h | 52 - .../Source/WWVegas/WW3D2/dx8texman.cpp | 198 - .../Source/WWVegas/WW3D2/dx8texman.h | 171 - .../Source/WWVegas/WW3D2/matpass.cpp | 234 -- .../Libraries/Source/WWVegas/WW3D2/matpass.h | 114 - .../Source/WWVegas/WW3D2/texproject.cpp | 1389 ------- .../Source/WWVegas/WW3D2/texproject.h | 239 -- .../Source/WWVegas/WW3D2/texture.cpp | 1908 --------- .../Libraries/Source/WWVegas/WW3D2/texture.h | 475 --- .../Source/WWVegas/WW3D2/texturefilter.cpp | 251 -- .../Source/WWVegas/WW3D2/texturefilter.h | 130 - .../Source/WWVegas/WW3D2/textureloader.cpp | 2819 ------------- .../Source/WWVegas/WW3D2/textureloader.h | 326 -- .../Source/WWVegas/WW3D2/texturethumbnail.cpp | 410 -- .../Source/WWVegas/WW3D2/texturethumbnail.h | 124 - GeneralsMD/Code/GameEngine/CMakeLists.txt | 4 +- .../Code/GameEngineDevice/CMakeLists.txt | 12 +- .../Source/WWVegas/WW3D2/CMakeLists.txt | 32 +- scripts/cpp/unify_move_files.py | 28 + 62 files changed, 102 insertions(+), 15391 deletions(-) rename {GeneralsMD/Code => Core}/GameEngine/Include/GameClient/Water.h (100%) rename {GeneralsMD/Code => Core}/GameEngine/Source/GameClient/Water.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DLaserDraw.h (100%) rename {GeneralsMD/Code => Core}/GameEngineDevice/Include/W3DDevice/GameClient/W3DWater.h (100%) rename {GeneralsMD/Code => Core}/GameEngineDevice/Include/W3DDevice/GameClient/W3DWaterTracks.h (100%) rename {GeneralsMD/Code => Core}/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DLaserDraw.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWater.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWaterTracks.cpp (100%) rename {GeneralsMD/Code => Core}/GameEngineDevice/Source/W3DDevice/GameClient/Water/wave.nvp (100%) rename {GeneralsMD/Code => Core}/GameEngineDevice/Source/W3DDevice/GameClient/Water/wave.nvv (100%) rename {GeneralsMD/Code => Core}/Libraries/Source/WWVegas/WW3D2/bmp2d.cpp (100%) rename {GeneralsMD/Code => Core}/Libraries/Source/WWVegas/WW3D2/bmp2d.h (100%) rename {GeneralsMD/Code => Core}/Libraries/Source/WWVegas/WW3D2/dx8texman.cpp (100%) rename {GeneralsMD/Code => Core}/Libraries/Source/WWVegas/WW3D2/dx8texman.h (100%) rename {GeneralsMD/Code => Core}/Libraries/Source/WWVegas/WW3D2/matpass.cpp (100%) rename {GeneralsMD/Code => Core}/Libraries/Source/WWVegas/WW3D2/matpass.h (100%) rename {GeneralsMD/Code => Core}/Libraries/Source/WWVegas/WW3D2/texproject.cpp (100%) rename {GeneralsMD/Code => Core}/Libraries/Source/WWVegas/WW3D2/texproject.h (100%) rename {GeneralsMD/Code => Core}/Libraries/Source/WWVegas/WW3D2/texture.cpp (100%) rename {GeneralsMD/Code => Core}/Libraries/Source/WWVegas/WW3D2/texture.h (100%) rename {GeneralsMD/Code => Core}/Libraries/Source/WWVegas/WW3D2/texturefilter.cpp (100%) rename {GeneralsMD/Code => Core}/Libraries/Source/WWVegas/WW3D2/texturefilter.h (100%) rename {GeneralsMD/Code => Core}/Libraries/Source/WWVegas/WW3D2/textureloader.cpp (100%) rename {GeneralsMD/Code => Core}/Libraries/Source/WWVegas/WW3D2/textureloader.h (100%) rename {GeneralsMD/Code => Core}/Libraries/Source/WWVegas/WW3D2/texturethumbnail.cpp (100%) rename {GeneralsMD/Code => Core}/Libraries/Source/WWVegas/WW3D2/texturethumbnail.h (100%) delete mode 100644 Generals/Code/GameEngine/Include/GameClient/Water.h delete mode 100644 Generals/Code/GameEngine/Source/GameClient/Water.cpp delete mode 100644 Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DLaserDraw.h delete mode 100644 Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DWater.h delete mode 100644 Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DWaterTracks.h delete mode 100644 Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DLaserDraw.cpp delete mode 100644 Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWater.cpp delete mode 100644 Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWaterTracks.cpp delete mode 100644 Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/wave.nvp delete mode 100644 Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/wave.nvv delete mode 100644 Generals/Code/Libraries/Source/WWVegas/WW3D2/bmp2d.cpp delete mode 100644 Generals/Code/Libraries/Source/WWVegas/WW3D2/bmp2d.h delete mode 100644 Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8texman.cpp delete mode 100644 Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8texman.h delete mode 100644 Generals/Code/Libraries/Source/WWVegas/WW3D2/matpass.cpp delete mode 100644 Generals/Code/Libraries/Source/WWVegas/WW3D2/matpass.h delete mode 100644 Generals/Code/Libraries/Source/WWVegas/WW3D2/texproject.cpp delete mode 100644 Generals/Code/Libraries/Source/WWVegas/WW3D2/texproject.h delete mode 100644 Generals/Code/Libraries/Source/WWVegas/WW3D2/texture.cpp delete mode 100644 Generals/Code/Libraries/Source/WWVegas/WW3D2/texture.h delete mode 100644 Generals/Code/Libraries/Source/WWVegas/WW3D2/texturefilter.cpp delete mode 100644 Generals/Code/Libraries/Source/WWVegas/WW3D2/texturefilter.h delete mode 100644 Generals/Code/Libraries/Source/WWVegas/WW3D2/textureloader.cpp delete mode 100644 Generals/Code/Libraries/Source/WWVegas/WW3D2/textureloader.h delete mode 100644 Generals/Code/Libraries/Source/WWVegas/WW3D2/texturethumbnail.cpp delete mode 100644 Generals/Code/Libraries/Source/WWVegas/WW3D2/texturethumbnail.h diff --git a/Core/GameEngine/CMakeLists.txt b/Core/GameEngine/CMakeLists.txt index 8c720b62385..e486efe32e7 100644 --- a/Core/GameEngine/CMakeLists.txt +++ b/Core/GameEngine/CMakeLists.txt @@ -230,7 +230,7 @@ set(GAMEENGINE_SRC # Include/GameClient/TerrainVisual.h Include/GameClient/VideoPlayer.h Include/GameClient/View.h -# Include/GameClient/Water.h + Include/GameClient/Water.h # Include/GameClient/WindowLayout.h Include/GameClient/WindowVideoManager.h # Include/GameClient/WindowXlat.h @@ -835,7 +835,7 @@ set(GAMEENGINE_SRC Source/GameClient/VideoPlayer.cpp Source/GameClient/VideoStream.cpp Source/GameClient/View.cpp -# Source/GameClient/Water.cpp + Source/GameClient/Water.cpp # Source/GameLogic/AI/AI.cpp # Source/GameLogic/AI/AIDock.cpp # Source/GameLogic/AI/AIGroup.cpp diff --git a/GeneralsMD/Code/GameEngine/Include/GameClient/Water.h b/Core/GameEngine/Include/GameClient/Water.h similarity index 100% rename from GeneralsMD/Code/GameEngine/Include/GameClient/Water.h rename to Core/GameEngine/Include/GameClient/Water.h diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/Water.cpp b/Core/GameEngine/Source/GameClient/Water.cpp similarity index 100% rename from GeneralsMD/Code/GameEngine/Source/GameClient/Water.cpp rename to Core/GameEngine/Source/GameClient/Water.cpp diff --git a/Core/GameEngineDevice/CMakeLists.txt b/Core/GameEngineDevice/CMakeLists.txt index c53c29220fb..66dff03ecc0 100644 --- a/Core/GameEngineDevice/CMakeLists.txt +++ b/Core/GameEngineDevice/CMakeLists.txt @@ -13,7 +13,7 @@ set(GAMEENGINEDEVICE_SRC # Include/W3DDevice/GameClient/Module/W3DDebrisDraw.h # Include/W3DDevice/GameClient/Module/W3DDefaultDraw.h # Include/W3DDevice/GameClient/Module/W3DDependencyModelDraw.h -# Include/W3DDevice/GameClient/Module/W3DLaserDraw.h + Include/W3DDevice/GameClient/Module/W3DLaserDraw.h # Include/W3DDevice/GameClient/Module/W3DModelDraw.h # Include/W3DDevice/GameClient/Module/W3DOverlordAircraftDraw.h # Include/W3DDevice/GameClient/Module/W3DOverlordTankDraw.h @@ -73,8 +73,8 @@ set(GAMEENGINEDEVICE_SRC Include/W3DDevice/GameClient/W3DVideoBuffer.h Include/W3DDevice/GameClient/W3DView.h # Include/W3DDevice/GameClient/W3DVolumetricShadow.h -# Include/W3DDevice/GameClient/W3DWater.h -# Include/W3DDevice/GameClient/W3DWaterTracks.h + Include/W3DDevice/GameClient/W3DWater.h + Include/W3DDevice/GameClient/W3DWaterTracks.h # Include/W3DDevice/GameClient/W3DWaypointBuffer.h # Include/W3DDevice/GameClient/W3DWebBrowser.h # Include/W3DDevice/GameClient/WorldHeightMap.h @@ -102,7 +102,7 @@ set(GAMEENGINEDEVICE_SRC # Source/W3DDevice/GameClient/Drawable/Draw/W3DDebrisDraw.cpp # Source/W3DDevice/GameClient/Drawable/Draw/W3DDefaultDraw.cpp # Source/W3DDevice/GameClient/Drawable/Draw/W3DDependencyModelDraw.cpp -# Source/W3DDevice/GameClient/Drawable/Draw/W3DLaserDraw.cpp + Source/W3DDevice/GameClient/Drawable/Draw/W3DLaserDraw.cpp # Source/W3DDevice/GameClient/Drawable/Draw/W3DModelDraw.cpp # Source/W3DDevice/GameClient/Drawable/Draw/W3DOverlordAircraftDraw.cpp # Source/W3DDevice/GameClient/Drawable/Draw/W3DOverlordTankDraw.cpp @@ -176,8 +176,8 @@ set(GAMEENGINEDEVICE_SRC Source/W3DDevice/GameClient/W3DView.cpp # Source/W3DDevice/GameClient/W3dWaypointBuffer.cpp # Source/W3DDevice/GameClient/W3DWebBrowser.cpp -# Source/W3DDevice/GameClient/Water/W3DWater.cpp -# Source/W3DDevice/GameClient/Water/W3DWaterTracks.cpp + Source/W3DDevice/GameClient/Water/W3DWater.cpp + Source/W3DDevice/GameClient/Water/W3DWaterTracks.cpp # Source/W3DDevice/GameClient/WorldHeightMap.cpp # Source/W3DDevice/GameLogic/W3DGameLogic.cpp # Source/W3DDevice/GameLogic/W3DGhostObject.cpp diff --git a/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DLaserDraw.h b/Core/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DLaserDraw.h similarity index 100% rename from GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DLaserDraw.h rename to Core/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DLaserDraw.h diff --git a/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DWater.h b/Core/GameEngineDevice/Include/W3DDevice/GameClient/W3DWater.h similarity index 100% rename from GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DWater.h rename to Core/GameEngineDevice/Include/W3DDevice/GameClient/W3DWater.h diff --git a/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DWaterTracks.h b/Core/GameEngineDevice/Include/W3DDevice/GameClient/W3DWaterTracks.h similarity index 100% rename from GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DWaterTracks.h rename to Core/GameEngineDevice/Include/W3DDevice/GameClient/W3DWaterTracks.h diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DLaserDraw.cpp b/Core/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DLaserDraw.cpp similarity index 100% rename from GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DLaserDraw.cpp rename to Core/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DLaserDraw.cpp diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWater.cpp b/Core/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWater.cpp similarity index 100% rename from GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWater.cpp rename to Core/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWater.cpp diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWaterTracks.cpp b/Core/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWaterTracks.cpp similarity index 100% rename from GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWaterTracks.cpp rename to Core/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWaterTracks.cpp diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/wave.nvp b/Core/GameEngineDevice/Source/W3DDevice/GameClient/Water/wave.nvp similarity index 100% rename from GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/wave.nvp rename to Core/GameEngineDevice/Source/W3DDevice/GameClient/Water/wave.nvp diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/wave.nvv b/Core/GameEngineDevice/Source/W3DDevice/GameClient/Water/wave.nvv similarity index 100% rename from GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/wave.nvv rename to Core/GameEngineDevice/Source/W3DDevice/GameClient/Water/wave.nvv diff --git a/Core/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt b/Core/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt index 29a8f9a3bad..35c7ff4bd6e 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt +++ b/Core/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt @@ -15,8 +15,8 @@ set(WW3D2_SRC assetstatus.h bitmaphandler.cpp bitmaphandler.h - #bmp2d.cpp - #bmp2d.h + bmp2d.cpp + bmp2d.h #boxrobj.cpp #boxrobj.h bwrender.cpp @@ -56,8 +56,8 @@ set(WW3D2_SRC #dx8renderer.h #dx8rendererdebugger.cpp #dx8rendererdebugger.h - #dx8texman.cpp - #dx8texman.h + dx8texman.cpp + dx8texman.h #dx8vertexbuffer.cpp #dx8vertexbuffer.h dx8webbrowser.cpp @@ -108,8 +108,8 @@ set(WW3D2_SRC #mapper.h matinfo.cpp matinfo.h - #matpass.cpp - #matpass.h + matpass.cpp + matpass.h #matrixmapper.cpp #matrixmapper.h #mesh.cpp @@ -200,18 +200,18 @@ set(WW3D2_SRC stripoptimizer.h surfaceclass.cpp surfaceclass.h - #texproject.cpp - #texproject.h + texproject.cpp + texproject.h #textdraw.cpp # unused textdraw.h - #texture.cpp - #texture.h - #texturefilter.cpp - #texturefilter.h - #textureloader.cpp - #textureloader.h - #texturethumbnail.cpp - #texturethumbnail.h + texture.cpp + texture.h + texturefilter.cpp + texturefilter.h + textureloader.cpp + textureloader.h + texturethumbnail.cpp + texturethumbnail.h #vertmaterial.cpp #vertmaterial.h visrasterizer.cpp diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/bmp2d.cpp b/Core/Libraries/Source/WWVegas/WW3D2/bmp2d.cpp similarity index 100% rename from GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/bmp2d.cpp rename to Core/Libraries/Source/WWVegas/WW3D2/bmp2d.cpp diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/bmp2d.h b/Core/Libraries/Source/WWVegas/WW3D2/bmp2d.h similarity index 100% rename from GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/bmp2d.h rename to Core/Libraries/Source/WWVegas/WW3D2/bmp2d.h diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8texman.cpp b/Core/Libraries/Source/WWVegas/WW3D2/dx8texman.cpp similarity index 100% rename from GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8texman.cpp rename to Core/Libraries/Source/WWVegas/WW3D2/dx8texman.cpp diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8texman.h b/Core/Libraries/Source/WWVegas/WW3D2/dx8texman.h similarity index 100% rename from GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8texman.h rename to Core/Libraries/Source/WWVegas/WW3D2/dx8texman.h diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/matpass.cpp b/Core/Libraries/Source/WWVegas/WW3D2/matpass.cpp similarity index 100% rename from GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/matpass.cpp rename to Core/Libraries/Source/WWVegas/WW3D2/matpass.cpp diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/matpass.h b/Core/Libraries/Source/WWVegas/WW3D2/matpass.h similarity index 100% rename from GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/matpass.h rename to Core/Libraries/Source/WWVegas/WW3D2/matpass.h diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/texproject.cpp b/Core/Libraries/Source/WWVegas/WW3D2/texproject.cpp similarity index 100% rename from GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/texproject.cpp rename to Core/Libraries/Source/WWVegas/WW3D2/texproject.cpp diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/texproject.h b/Core/Libraries/Source/WWVegas/WW3D2/texproject.h similarity index 100% rename from GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/texproject.h rename to Core/Libraries/Source/WWVegas/WW3D2/texproject.h diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/texture.cpp b/Core/Libraries/Source/WWVegas/WW3D2/texture.cpp similarity index 100% rename from GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/texture.cpp rename to Core/Libraries/Source/WWVegas/WW3D2/texture.cpp diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/texture.h b/Core/Libraries/Source/WWVegas/WW3D2/texture.h similarity index 100% rename from GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/texture.h rename to Core/Libraries/Source/WWVegas/WW3D2/texture.h diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/texturefilter.cpp b/Core/Libraries/Source/WWVegas/WW3D2/texturefilter.cpp similarity index 100% rename from GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/texturefilter.cpp rename to Core/Libraries/Source/WWVegas/WW3D2/texturefilter.cpp diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/texturefilter.h b/Core/Libraries/Source/WWVegas/WW3D2/texturefilter.h similarity index 100% rename from GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/texturefilter.h rename to Core/Libraries/Source/WWVegas/WW3D2/texturefilter.h diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/textureloader.cpp b/Core/Libraries/Source/WWVegas/WW3D2/textureloader.cpp similarity index 100% rename from GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/textureloader.cpp rename to Core/Libraries/Source/WWVegas/WW3D2/textureloader.cpp diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/textureloader.h b/Core/Libraries/Source/WWVegas/WW3D2/textureloader.h similarity index 100% rename from GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/textureloader.h rename to Core/Libraries/Source/WWVegas/WW3D2/textureloader.h diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/texturethumbnail.cpp b/Core/Libraries/Source/WWVegas/WW3D2/texturethumbnail.cpp similarity index 100% rename from GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/texturethumbnail.cpp rename to Core/Libraries/Source/WWVegas/WW3D2/texturethumbnail.cpp diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/texturethumbnail.h b/Core/Libraries/Source/WWVegas/WW3D2/texturethumbnail.h similarity index 100% rename from GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/texturethumbnail.h rename to Core/Libraries/Source/WWVegas/WW3D2/texturethumbnail.h diff --git a/Generals/Code/GameEngine/CMakeLists.txt b/Generals/Code/GameEngine/CMakeLists.txt index 730e1ec6be8..357a3a48b61 100644 --- a/Generals/Code/GameEngine/CMakeLists.txt +++ b/Generals/Code/GameEngine/CMakeLists.txt @@ -215,7 +215,7 @@ set(GAMEENGINE_SRC Include/GameClient/TerrainVisual.h # Include/GameClient/VideoPlayer.h # Include/GameClient/View.h - Include/GameClient/Water.h +# Include/GameClient/Water.h Include/GameClient/WindowLayout.h # Include/GameClient/WindowVideoManager.h Include/GameClient/WindowXlat.h @@ -777,7 +777,7 @@ set(GAMEENGINE_SRC Source/GameClient/Terrain/TerrainVisual.cpp # Source/GameClient/VideoPlayer.cpp # Source/GameClient/View.cpp - Source/GameClient/Water.cpp +# Source/GameClient/Water.cpp Source/GameLogic/AI/AI.cpp Source/GameLogic/AI/AIDock.cpp Source/GameLogic/AI/AIGroup.cpp diff --git a/Generals/Code/GameEngine/Include/GameClient/Water.h b/Generals/Code/GameEngine/Include/GameClient/Water.h deleted file mode 100644 index 7814c543bd0..00000000000 --- a/Generals/Code/GameEngine/Include/GameClient/Water.h +++ /dev/null @@ -1,124 +0,0 @@ -/* -** 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 . -*/ - -//////////////////////////////////////////////////////////////////////////////// -// // -// (c) 2001-2003 Electronic Arts Inc. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: Water.h ////////////////////////////////////////////////////////////////////////////////// -// Author: Colin Day, December 2001 -// Desc: Water settings -/////////////////////////////////////////////////////////////////////////////////////////////////// - -#pragma once - -// INLCLUDES ////////////////////////////////////////////////////////////////////////////////////// -#include "Common/GameType.h" -#include "Common/Overridable.h" -#include "Common/Override.h" - -//------------------------------------------------------------------------------------------------- -struct FieldParse; - -//------------------------------------------------------------------------------------------------- -/** This structures keeps the settings for how our water will look */ -//------------------------------------------------------------------------------------------------- -class WaterSetting -{ - -public: - - WaterSetting( void ); - virtual ~WaterSetting( void ); - - /// Get the INI parsing table for loading - const FieldParse *getFieldParse( void ) { return m_waterSettingFieldParseTable; } - - static const FieldParse m_waterSettingFieldParseTable[]; ///< the parse table for INI definition - AsciiString m_skyTextureFile; - AsciiString m_waterTextureFile; - Int m_waterRepeatCount; - Real m_skyTexelsPerUnit; //texel density of sky plane (higher value repeats texture more). - RGBAColorInt m_vertex00Diffuse; - RGBAColorInt m_vertex10Diffuse; - RGBAColorInt m_vertex11Diffuse; - RGBAColorInt m_vertex01Diffuse; - RGBAColorInt m_waterDiffuseColor; - RGBAColorInt m_transparentWaterDiffuse; - Real m_uScrollPerMs; - Real m_vScrollPerMs; - -}; - -//------------------------------------------------------------------------------------------------- -/** This structure keeps the transparency and vertex settings, which are the same regardless of the - time of day. They can be overridden on a per-map basis. */ -//------------------------------------------------------------------------------------------------- -class WaterTransparencySetting : public Overridable -{ - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE( WaterTransparencySetting, "WaterTransparencySetting" ) - - public: - Real m_transparentWaterDepth; - Real m_minWaterOpacity; - RGBColor m_standingWaterColor; - RGBColor m_radarColor; - Bool m_additiveBlend; - AsciiString m_standingWaterTexture; - - AsciiString m_skyboxTextureN; - AsciiString m_skyboxTextureE; - AsciiString m_skyboxTextureS; - AsciiString m_skyboxTextureW; - AsciiString m_skyboxTextureT; - - public: - WaterTransparencySetting() - { - m_transparentWaterDepth = 3.0f; - m_minWaterOpacity = 1.0f; - m_standingWaterColor.red = 1.0f; - m_standingWaterColor.green = 1.0f; - m_standingWaterColor.blue = 1.0f; - m_radarColor.red = 0.55f; - m_radarColor.green = 0.55f; - m_radarColor.blue = 1.0f; - m_standingWaterTexture = "TWWater01.tga"; - m_additiveBlend = FALSE; - - m_skyboxTextureN = "TSMorningN.tga"; - m_skyboxTextureE = "TSMorningE.tga"; - m_skyboxTextureS = "TSMorningS.tga"; - m_skyboxTextureW = "TSMorningW.tga"; - m_skyboxTextureT = "TSMorningT.tga"; - } - - static const FieldParse m_waterTransparencySettingFieldParseTable[]; ///< the parse table for INI definition - - /// Get the INI parsing table for loading - const FieldParse *getFieldParse( void ) const { return m_waterTransparencySettingFieldParseTable; } -}; - -EMPTY_DTOR(WaterTransparencySetting) - -// EXTERNAL /////////////////////////////////////////////////////////////////////////////////////// -extern WaterSetting WaterSettings[ TIME_OF_DAY_COUNT ]; - -extern OVERRIDE TheWaterTransparency; diff --git a/Generals/Code/GameEngine/Source/GameClient/Water.cpp b/Generals/Code/GameEngine/Source/GameClient/Water.cpp deleted file mode 100644 index f59a942086f..00000000000 --- a/Generals/Code/GameEngine/Source/GameClient/Water.cpp +++ /dev/null @@ -1,134 +0,0 @@ -/* -** 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 . -*/ - -//////////////////////////////////////////////////////////////////////////////// -// // -// (c) 2001-2003 Electronic Arts Inc. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: Water.cpp //////////////////////////////////////////////////////////////////////////////// -// Author: Colin Day, December 2001 -// Desc: Map water settings -/////////////////////////////////////////////////////////////////////////////////////////////////// - -// INCLUDES /////////////////////////////////////////////////////////////////////////////////////// -#include "PreRTS.h" // This must go first in EVERY cpp file in the GameEngine - -#include "GameClient/Water.h" -#include "Common/INI.h" - -// GLOBALS //////////////////////////////////////////////////////////////////////////////////////// -WaterSetting WaterSettings[ TIME_OF_DAY_COUNT ]; -OVERRIDE TheWaterTransparency = NULL; - -// PRIVATE DATA /////////////////////////////////////////////////////////////////////////////////// -const FieldParse WaterSetting::m_waterSettingFieldParseTable[] = -{ - - { "SkyTexture", INI::parseAsciiString, NULL, offsetof( WaterSetting, m_skyTextureFile ) }, - { "WaterTexture", INI::parseAsciiString, NULL, offsetof( WaterSetting, m_waterTextureFile ) }, - { "Vertex00Color", INI::parseRGBAColorInt, NULL, offsetof( WaterSetting, m_vertex00Diffuse ) }, - { "Vertex10Color", INI::parseRGBAColorInt, NULL, offsetof( WaterSetting, m_vertex10Diffuse ) }, - { "Vertex01Color", INI::parseRGBAColorInt, NULL, offsetof( WaterSetting, m_vertex01Diffuse ) }, - { "Vertex11Color", INI::parseRGBAColorInt, NULL, offsetof( WaterSetting, m_vertex11Diffuse ) }, - { "DiffuseColor", INI::parseRGBAColorInt, NULL, offsetof( WaterSetting, m_waterDiffuseColor ) }, - { "TransparentDiffuseColor", INI::parseRGBAColorInt, NULL, offsetof( WaterSetting, m_transparentWaterDiffuse ) }, - { "UScrollPerMS", INI::parseReal, NULL, offsetof( WaterSetting, m_uScrollPerMs ) }, - { "VScrollPerMS", INI::parseReal, NULL, offsetof( WaterSetting, m_vScrollPerMs ) }, - { "SkyTexelsPerUnit", INI::parseReal, NULL, offsetof( WaterSetting, m_skyTexelsPerUnit ) }, - { "WaterRepeatCount", INI::parseInt, NULL, offsetof( WaterSetting, m_waterRepeatCount ) }, - - { NULL, NULL, NULL, 0 }, - -}; - -// PRIVATE DATA /////////////////////////////////////////////////////////////////////////////////// -const FieldParse WaterTransparencySetting::m_waterTransparencySettingFieldParseTable[] = -{ - - { "TransparentWaterDepth", INI::parseReal, NULL, offsetof( WaterTransparencySetting, m_transparentWaterDepth ) }, - { "TransparentWaterMinOpacity", INI::parseReal, NULL, offsetof( WaterTransparencySetting, m_minWaterOpacity ) }, - { "StandingWaterColor", INI::parseRGBColor, NULL, offsetof( WaterTransparencySetting, m_standingWaterColor ) }, - { "StandingWaterTexture",INI::parseAsciiString, NULL, offsetof( WaterTransparencySetting, m_standingWaterTexture ) }, - { "AdditiveBlending", INI::parseBool, NULL, offsetof( WaterTransparencySetting, m_additiveBlend) }, - { "RadarWaterColor", INI::parseRGBColor, NULL, offsetof( WaterTransparencySetting, m_radarColor) }, - { "SkyboxTextureN", INI::parseAsciiString,NULL, offsetof( WaterTransparencySetting, m_skyboxTextureN ) }, - { "SkyboxTextureE", INI::parseAsciiString,NULL, offsetof( WaterTransparencySetting, m_skyboxTextureE ) }, - { "SkyboxTextureS", INI::parseAsciiString,NULL, offsetof( WaterTransparencySetting, m_skyboxTextureS ) }, - { "SkyboxTextureW", INI::parseAsciiString,NULL, offsetof( WaterTransparencySetting, m_skyboxTextureW ) }, - { "SkyboxTextureT", INI::parseAsciiString,NULL, offsetof( WaterTransparencySetting, m_skyboxTextureT ) }, - - - { 0, 0, 0, 0 }, -}; - - -//------------------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------------------- -WaterSetting::WaterSetting( void ) -{ - - m_skyTextureFile.clear(); - m_waterTextureFile.clear(); - m_waterRepeatCount = 0; - m_skyTexelsPerUnit = 0.0f; - - m_vertex00Diffuse.red = 0; - m_vertex00Diffuse.green = 0; - m_vertex00Diffuse.blue = 0; - m_vertex00Diffuse.alpha = 0; - - m_vertex01Diffuse.red = 0; - m_vertex01Diffuse.green = 0; - m_vertex01Diffuse.blue = 0; - m_vertex01Diffuse.alpha = 0; - - m_vertex10Diffuse.red = 0; - m_vertex10Diffuse.green = 0; - m_vertex10Diffuse.blue = 0; - m_vertex10Diffuse.alpha = 0; - - m_vertex11Diffuse.red = 0; - m_vertex11Diffuse.green = 0; - m_vertex11Diffuse.blue = 0; - m_vertex11Diffuse.alpha = 0; - - m_waterDiffuseColor.red = 0; - m_waterDiffuseColor.green = 0; - m_waterDiffuseColor.blue = 0; - m_waterDiffuseColor.alpha = 0; - - m_transparentWaterDiffuse.red = 0; - m_transparentWaterDiffuse.green = 0; - m_transparentWaterDiffuse.blue = 0; - m_transparentWaterDiffuse.alpha = 0; - - m_uScrollPerMs = 0.0f; - m_vScrollPerMs = 0.0f; - -} - -//------------------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------------------- -WaterSetting::~WaterSetting( void ) -{ - -} - - diff --git a/Generals/Code/GameEngineDevice/CMakeLists.txt b/Generals/Code/GameEngineDevice/CMakeLists.txt index de6e7bd69a9..37a9ed23340 100644 --- a/Generals/Code/GameEngineDevice/CMakeLists.txt +++ b/Generals/Code/GameEngineDevice/CMakeLists.txt @@ -10,7 +10,7 @@ set(GAMEENGINEDEVICE_SRC Include/W3DDevice/GameClient/Module/W3DDebrisDraw.h Include/W3DDevice/GameClient/Module/W3DDefaultDraw.h Include/W3DDevice/GameClient/Module/W3DDependencyModelDraw.h - Include/W3DDevice/GameClient/Module/W3DLaserDraw.h +# Include/W3DDevice/GameClient/Module/W3DLaserDraw.h Include/W3DDevice/GameClient/Module/W3DModelDraw.h Include/W3DDevice/GameClient/Module/W3DOverlordTankDraw.h Include/W3DDevice/GameClient/Module/W3DPoliceCarDraw.h @@ -62,8 +62,8 @@ set(GAMEENGINEDEVICE_SRC # Include/W3DDevice/GameClient/W3DVideoBuffer.h # Include/W3DDevice/GameClient/W3DView.h Include/W3DDevice/GameClient/W3DVolumetricShadow.h - Include/W3DDevice/GameClient/W3DWater.h - Include/W3DDevice/GameClient/W3DWaterTracks.h +# Include/W3DDevice/GameClient/W3DWater.h +# Include/W3DDevice/GameClient/W3DWaterTracks.h Include/W3DDevice/GameClient/W3DWaypointBuffer.h Include/W3DDevice/GameClient/W3DWebBrowser.h Include/W3DDevice/GameClient/WorldHeightMap.h @@ -88,7 +88,7 @@ set(GAMEENGINEDEVICE_SRC Source/W3DDevice/GameClient/Drawable/Draw/W3DDebrisDraw.cpp Source/W3DDevice/GameClient/Drawable/Draw/W3DDefaultDraw.cpp Source/W3DDevice/GameClient/Drawable/Draw/W3DDependencyModelDraw.cpp - Source/W3DDevice/GameClient/Drawable/Draw/W3DLaserDraw.cpp +# Source/W3DDevice/GameClient/Drawable/Draw/W3DLaserDraw.cpp Source/W3DDevice/GameClient/Drawable/Draw/W3DModelDraw.cpp Source/W3DDevice/GameClient/Drawable/Draw/W3DOverlordTankDraw.cpp Source/W3DDevice/GameClient/Drawable/Draw/W3DPoliceCarDraw.cpp @@ -161,10 +161,10 @@ set(GAMEENGINEDEVICE_SRC # Source/W3DDevice/GameClient/W3DView.cpp Source/W3DDevice/GameClient/W3dWaypointBuffer.cpp Source/W3DDevice/GameClient/W3DWebBrowser.cpp - Source/W3DDevice/GameClient/Water/W3DWater.cpp - Source/W3DDevice/GameClient/Water/W3DWaterTracks.cpp - Source/W3DDevice/GameClient/Water/wave.nvp - Source/W3DDevice/GameClient/Water/wave.nvv +# Source/W3DDevice/GameClient/Water/W3DWater.cpp +# Source/W3DDevice/GameClient/Water/W3DWaterTracks.cpp +# Source/W3DDevice/GameClient/Water/wave.nvp +# Source/W3DDevice/GameClient/Water/wave.nvv Source/W3DDevice/GameClient/WorldHeightMap.cpp Source/W3DDevice/GameLogic/W3DGameLogic.cpp Source/W3DDevice/GameLogic/W3DGhostObject.cpp diff --git a/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DLaserDraw.h b/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DLaserDraw.h deleted file mode 100644 index 122af0b5aab..00000000000 --- a/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DLaserDraw.h +++ /dev/null @@ -1,98 +0,0 @@ -/* -** 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 . -*/ - -//////////////////////////////////////////////////////////////////////////////// -// // -// (c) 2001-2003 Electronic Arts Inc. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: W3DLaserDraw.h /////////////////////////////////////////////////////////////////////////// -// Author: -// Desc: -/////////////////////////////////////////////////////////////////////////////////////////////////// - -#pragma once - -// INCLUDES /////////////////////////////////////////////////////////////////////////////////////// -#include "Common/DrawModule.h" -//#include "WW3D2/Line3D.h" -#include "GameClient/Color.h" - -class SegmentedLineClass; -class TextureClass; - -class W3DLaserDrawModuleData : public ModuleData -{ -public: - - Color m_innerColor; - Color m_outerColor; - Real m_innerBeamWidth; - Real m_outerBeamWidth; - Real m_scrollRate; - Bool m_tile; - UnsignedInt m_numBeams; - UnsignedInt m_maxIntensityFrames; - UnsignedInt m_fadeFrames; - AsciiString m_textureName; - UnsignedInt m_segments; - Real m_arcHeight; - Real m_segmentOverlapRatio; - Real m_tilingScalar; - - W3DLaserDrawModuleData(); - ~W3DLaserDrawModuleData(); - static void buildFieldParse(MultiIniFieldParse& p); -}; - -//------------------------------------------------------------------------------------------------- -/** W3D laser draw */ -//------------------------------------------------------------------------------------------------- -class W3DLaserDraw : public DrawModule, public LaserDrawInterface -{ - - MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE( W3DLaserDraw, "W3DLaserDraw" ) - MAKE_STANDARD_MODULE_MACRO_WITH_MODULE_DATA( W3DLaserDraw, W3DLaserDrawModuleData ) - -public: - - W3DLaserDraw( Thing *thing, const ModuleData* moduleData ); - // virtual destructor prototype provided by memory pool declaration - - virtual void doDrawModule(const Matrix3D* transformMtx); - virtual void releaseShadows(void) {}; ///< we don't care about preserving temporary shadows. - virtual void allocateShadows(void) {}; ///< we don't care about preserving temporary shadows. - virtual void setShadowsEnabled(Bool enable) { } - virtual void setFullyObscuredByShroud(Bool fullyObscured) { }; - virtual void reactToTransformChange(const Matrix3D* oldMtx, const Coord3D* oldPos, Real oldAngle) { } - virtual void reactToGeometryChange() { } - virtual Bool isLaser() const { return true; } - Real getLaserTemplateWidth() const; - - virtual LaserDrawInterface* getLaserDrawInterface() { return this; } - virtual const LaserDrawInterface* getLaserDrawInterface() const { return this; } - -protected: - - SegmentedLineClass **m_line3D; ///< line 3D for effect - TextureClass *m_texture; - Real m_textureAspectRatio; ///< aspect ratio of texture - Bool m_selfDirty; // not saved - -}; diff --git a/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DWater.h b/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DWater.h deleted file mode 100644 index 42e71a3fbc4..00000000000 --- a/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DWater.h +++ /dev/null @@ -1,290 +0,0 @@ -/* -** 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 . -*/ - -//////////////////////////////////////////////////////////////////////////////// -// // -// (c) 2001-2003 Electronic Arts Inc. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: W3DWater.h /////////////////////////////////////////////////// - -#pragma once - -#include "always.h" -#include "rendobj.h" -#include "w3d_file.h" -#include "dx8vertexbuffer.h" -#include "dx8indexbuffer.h" -#include "shader.h" -#include "vertmaterial.h" -#include "light.h" -#include "Lib/BaseType.h" -#include "Common/GameType.h" -#include "Common/Snapshot.h" - -#define INVALID_WATER_HEIGHT 0.0f ///water height guaranteed to be below all terrain. - -#define NUM_BUMP_FRAMES 32 ///number of animation frames in bump map -//Offsets in constant register file to Vertex shader constants -#define CV_ZERO 0 -#define CV_ONE 1 -#define CV_WORLDVIEWPROJ_0 2 -#define CV_TEXPROJ_0 6 -#define CV_PATCH_SCALE_OFFSET 10 - -class PolygonTrigger; -class WaterTracksRenderSystem; -class Xfer; -/// Custom render object that draws mirrors, water, and skies. -/** -This render object handles drawing reflected W3D scenes. It will only work -with rectangular planar surfaces and was tuned with an emphasis on water. -Since skies are only visible in reflections, this code will also -render clouds and sky bodies. -*/ -class WaterRenderObjClass : public Snapshot, - public RenderObjClass -{ - -public: - - enum WaterType - { - WATER_TYPE_0_TRANSLUCENT = 0, //translucent water, no reflection - WATER_TYPE_1_FB_REFLECTION, //legacy frame buffer reflection (non translucent) - WATER_TYPE_2_PVSHADER, //pixel/vertex shader, texture reflection - WATER_TYPE_3_GRIDMESH, //3D Mesh based water - }; - - WaterRenderObjClass(void); - ~WaterRenderObjClass(void); - - ///////////////////////////////////////////////////////////////////////////// - // Render Object Interface (W3D methods) - ///////////////////////////////////////////////////////////////////////////// - virtual RenderObjClass * Clone(void) const; - virtual int Class_ID(void) const; - virtual void Render(RenderInfoClass & rinfo); -/// @todo: Add methods for collision detection with water surface -// virtual Bool Cast_Ray(RayCollisionTestClass & raytest); -// virtual Bool Cast_AABox(AABoxCollisionTestClass & boxtest); -// virtual Bool Cast_OBBox(OBBoxCollisionTestClass & boxtest); -// virtual Bool Intersect_AABox(AABoxIntersectionTestClass & boxtest); -// virtual Bool Intersect_OBBox(OBBoxIntersectionTestClass & boxtest); - - virtual void Get_Obj_Space_Bounding_Sphere(SphereClass & sphere) const; - virtual void Get_Obj_Space_Bounding_Box(AABoxClass & aabox) const; - // Get and set static sort level - virtual int Get_Sort_Level(void) const { return m_sortLevel; } - virtual void Set_Sort_Level(int level) { m_sortLevel = level;} - - ///allocate W3D resources needed to render water - void renderWater(void); /// m_gridCellsX-1 ) - return FALSE; - if (gridY < 0) - return FALSE; - if (gridY > m_gridCellsY-1 ) - return FALSE; - - return TRUE; -} - -extern WaterRenderObjClass *TheWaterRenderObj; ///. -*/ - -//////////////////////////////////////////////////////////////////////////////// -// // -// (c) 2001-2003 Electronic Arts Inc. // -// // -//////////////////////////////////////////////////////////////////////////////// - -#pragma once - -enum waveType CPP_11(: Int); //forward reference - -/// Custom render object that draws animated tracks/waves on the water. -/** - This is an object which draws a small breaking wave or splash animation. These objects are - to be managed/accessed only by the WaterTracksRenderObjClassSystem -*/ -class WaterTracksObj -{ - friend class WaterTracksRenderSystem; - -public: - - WaterTracksObj(void); - ~WaterTracksObj(void); - - virtual void Render(void) {}; ///. -*/ - -//////////////////////////////////////////////////////////////////////////////// -// // -// (c) 2001-2003 Electronic Arts Inc. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: W3DLaserDraw.cpp ///////////////////////////////////////////////////////////////////////// -// Author: Colin Day, May 2001 -// Desc: W3DLaserDraw -// Updated: Kris Morness July 2002 -- made it data driven and added new features to make it flexible. -/////////////////////////////////////////////////////////////////////////////////////////////////// - -// INCLUDES /////////////////////////////////////////////////////////////////////////////////////// -#include - -#include "Common/Thing.h" -#include "Common/ThingTemplate.h" -#include "Common/Xfer.h" -#include "GameClient/Color.h" -#include "GameClient/Drawable.h" -#include "GameClient/GameClient.h" -#include "GameClient/RayEffect.h" -#include "GameLogic/GameLogic.h" -#include "GameLogic/Object.h" -#include "GameLogic/TerrainLogic.h" -#include "GameLogic/Module/LaserUpdate.h" -#include "W3DDevice/GameClient/Module/W3DLaserDraw.h" -#include "W3DDevice/GameClient/W3DDisplay.h" -#include "W3DDevice/GameClient/W3DScene.h" -#include "WW3D2/rinfo.h" -#include "WW3D2/camera.h" -#include "WW3D2/segline.h" -#include "WWMath/vector3.h" -#include "WW3D2/assetmgr.h" - - - -// PUBLIC FUNCTIONS /////////////////////////////////////////////////////////////////////////////// - -//------------------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------------------- -W3DLaserDrawModuleData::W3DLaserDrawModuleData() -{ - m_innerBeamWidth = 0.0f; //The total width of beam - m_outerBeamWidth = 1.0f; //The total width of beam - m_numBeams = 1; //Number of overlapping cylinders that make the beam. 1 beam will just use inner data. - m_maxIntensityFrames = 0; //Laser stays at max intensity for specified time in ms. - m_fadeFrames = 0; //Laser will fade and delete. - m_scrollRate = 0.0f; - m_tile = false; - m_segments = 1; - m_arcHeight = 0.0f; - m_segmentOverlapRatio = 0.0f; - m_tilingScalar = 1.0f; -} - -//------------------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------------------- -W3DLaserDrawModuleData::~W3DLaserDrawModuleData() -{ -} - -//------------------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------------------- -void W3DLaserDrawModuleData::buildFieldParse(MultiIniFieldParse& p) -{ - ModuleData::buildFieldParse(p); - - static const FieldParse dataFieldParse[] = - { - { "NumBeams", INI::parseUnsignedInt, NULL, offsetof( W3DLaserDrawModuleData, m_numBeams ) }, - { "InnerBeamWidth", INI::parseReal, NULL, offsetof( W3DLaserDrawModuleData, m_innerBeamWidth ) }, - { "OuterBeamWidth", INI::parseReal, NULL, offsetof( W3DLaserDrawModuleData, m_outerBeamWidth ) }, - { "InnerColor", INI::parseColorInt, NULL, offsetof( W3DLaserDrawModuleData, m_innerColor ) }, - { "OuterColor", INI::parseColorInt, NULL, offsetof( W3DLaserDrawModuleData, m_outerColor ) }, - { "MaxIntensityLifetime", INI::parseDurationUnsignedInt, NULL, offsetof( W3DLaserDrawModuleData, m_maxIntensityFrames ) }, - { "FadeLifetime", INI::parseDurationUnsignedInt, NULL, offsetof( W3DLaserDrawModuleData, m_fadeFrames ) }, - { "Texture", INI::parseAsciiString, NULL, offsetof( W3DLaserDrawModuleData, m_textureName ) }, - { "ScrollRate", INI::parseReal, NULL, offsetof( W3DLaserDrawModuleData, m_scrollRate ) }, - { "Tile", INI::parseBool, NULL, offsetof( W3DLaserDrawModuleData, m_tile ) }, - { "Segments", INI::parseUnsignedInt, NULL, offsetof( W3DLaserDrawModuleData, m_segments ) }, - { "ArcHeight", INI::parseReal, NULL, offsetof( W3DLaserDrawModuleData, m_arcHeight ) }, - { "SegmentOverlapRatio", INI::parseReal, NULL, offsetof( W3DLaserDrawModuleData, m_segmentOverlapRatio ) }, - { "TilingScalar", INI::parseReal, NULL, offsetof( W3DLaserDrawModuleData, m_tilingScalar ) }, - { 0, 0, 0, 0 } - }; - p.add(dataFieldParse); -} - - -//------------------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------------------- -W3DLaserDraw::W3DLaserDraw( Thing *thing, const ModuleData* moduleData ) : - DrawModule( thing, moduleData ), - m_line3D(NULL), - m_texture(NULL), - m_textureAspectRatio(1.0f), - m_selfDirty(TRUE) -{ - Vector3 dummyPos1( 0.0f, 0.0f, 0.0f ); - Vector3 dummyPos2( 1.0f, 1.0f, 1.0f ); - Int i; - - const W3DLaserDrawModuleData *data = getW3DLaserDrawModuleData(); - - m_texture = WW3DAssetManager::Get_Instance()->Get_Texture( data->m_textureName.str() ); - if (m_texture) - { - if (!m_texture->Is_Initialized()) - m_texture->Init(); //make sure texture is actually loaded before accessing surface. - - SurfaceClass::SurfaceDescription surfaceDesc; - m_texture->Get_Level_Description(surfaceDesc); - m_textureAspectRatio = (Real)surfaceDesc.Width/(Real)surfaceDesc.Height; - } - - //Get the color components for calculation purposes. - Real innerRed, innerGreen, innerBlue, innerAlpha, outerRed, outerGreen, outerBlue, outerAlpha; - GameGetColorComponentsReal( data->m_innerColor, &innerRed, &innerGreen, &innerBlue, &innerAlpha ); - GameGetColorComponentsReal( data->m_outerColor, &outerRed, &outerGreen, &outerBlue, &outerAlpha ); - - //Make sure our beams range between 1 and the maximum cap. -#ifdef I_WANT_TO_BE_FIRED -// srj sez: this data is const for a reason. casting away the constness because we don't like the values -// isn't an acceptable solution. if you need to constrain the values, do so at parsing time, when -// it's still legal to modify these values. (In point of fact, there's not even really any reason to limit -// the numBeams or segments anymore.) - data->m_numBeams = __min( __max( 1, data->m_numBeams ), MAX_LASER_LINES ); - data->m_segments = __min( __max( 1, data->m_segments ), MAX_SEGMENTS ); - data->m_tilingScalar = __max( 0.01f, data->m_tilingScalar ); -#endif - - //Allocate an array of lines equal to the number of beams * segments - m_line3D = NEW SegmentedLineClass *[ data->m_numBeams * data->m_segments ]; - - for( UnsignedInt segment = 0; segment < data->m_segments; segment++ ) - { - //We don't care about segment positioning yet until we actually set the position - - // create all the lines we need at the right transparency level - for( i = data->m_numBeams - 1; i >= 0; i-- ) - { - int index = segment * data->m_numBeams + i; - - Real red, green, blue, alpha, width; - - if( data->m_numBeams == 1 ) - { - width = data->m_innerBeamWidth; - alpha = innerAlpha; - red = innerRed * innerAlpha; - green = innerGreen * innerAlpha; - blue = innerBlue * innerAlpha; - } - else - { - //Calculate the scale between min and max values - //0 means use min value, 1 means use max value - //0.2 means min value + 20% of the diff between min and max - Real scale = i / ( data->m_numBeams - 1.0f); - - width = data->m_innerBeamWidth + scale * (data->m_outerBeamWidth - data->m_innerBeamWidth); - alpha = innerAlpha + scale * (outerAlpha - innerAlpha); - red = innerRed + scale * (outerRed - innerRed) * innerAlpha; - green = innerGreen + scale * (outerGreen - innerGreen) * innerAlpha; - blue = innerBlue + scale * (outerBlue - innerBlue) * innerAlpha; - } - - m_line3D[ index ] = NEW SegmentedLineClass; - - SegmentedLineClass *line = m_line3D[ index ]; - if( line ) - { - line->Set_Texture( m_texture ); - line->Set_Shader( ShaderClass::_PresetAdditiveShader ); //pick the alpha blending mode you want - see shader.h for others. - line->Set_Width( width ); - line->Set_Color( Vector3( red, green, blue ) ); - line->Set_UV_Offset_Rate( Vector2(0.0f, data->m_scrollRate) ); //amount to scroll texture on each draw - if( m_texture ) - { - line->Set_Texture_Mapping_Mode(SegLineRendererClass::TILED_TEXTURE_MAP); //this tiles the texture across the line - } - - // add to scene - if (W3DDisplay::m_3DScene != NULL) - W3DDisplay::m_3DScene->Add_Render_Object( line ); //add it to our scene so it gets rendered with other objects. - - // hide the render object until the first time we come to draw it and - // set the correct position - line->Set_Visible( 0 ); - } - - - } - - } - -} - -//------------------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------------------- -W3DLaserDraw::~W3DLaserDraw( void ) -{ - const W3DLaserDrawModuleData *data = getW3DLaserDrawModuleData(); - - for( UnsignedInt i = 0; i < data->m_numBeams * data->m_segments; i++ ) - { - - // remove line from scene - if (W3DDisplay::m_3DScene != NULL) - W3DDisplay::m_3DScene->Remove_Render_Object( m_line3D[ i ] ); - - // delete line - REF_PTR_RELEASE( m_line3D[ i ] ); - - } - - delete [] m_line3D; - // TheSuperHackers @fix Mauller 11/03/2025 Free reference counted material - REF_PTR_RELEASE(m_texture); -} - -//------------------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------------------- -Real W3DLaserDraw::getLaserTemplateWidth() const -{ - const W3DLaserDrawModuleData *data = getW3DLaserDrawModuleData(); - return data->m_outerBeamWidth * 0.5f; -} - -//------------------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------------------- -void W3DLaserDraw::doDrawModule(const Matrix3D* transformMtx) -{ - //UnsignedInt currentFrame = TheGameClient->getFrame(); - const W3DLaserDrawModuleData *data = getW3DLaserDrawModuleData(); - - //Get the updatemodule that drives it... - Drawable *draw = getDrawable(); - static NameKeyType key_LaserUpdate = NAMEKEY( "LaserUpdate" ); - LaserUpdate *update = (LaserUpdate*)draw->findClientUpdateModule( key_LaserUpdate ); - if( !update ) - { - DEBUG_ASSERTCRASH( 0, ("W3DLaserDraw::doDrawModule() expects its owner drawable %s to have a ClientUpdate = LaserUpdate module.", draw->getTemplate()->getName().str() )); - return; - } - - //If the update has moved the laser, it requires a reset of the laser. - if (update->isDirty() || m_selfDirty) - { - update->setDirty(false); - m_selfDirty = false; - - Vector3 laserPoints[ 2 ]; - - for( UnsignedInt segment = 0; segment < data->m_segments; segment++ ) - { - if( data->m_arcHeight > 0.0f && data->m_segments > 1 ) - { - //CALCULATE A CURVED LINE BASED ON TOTAL LENGTH AND DESIRED HEIGHT INCREASE - //To do this we will use a portion of the cos wave ranging between -0.25PI - //and +0.25PI. 0PI is 1.0 and 0.25PI is 0.70 -- resulting in a somewhat - //gentle curve depending on the line height and length. We also have to make - //the line *level* for this phase of the calculations. - - //Get the desired direct line - Coord3D lineStart, lineEnd, lineVector; - lineStart.set( update->getStartPos() ); - lineEnd.set( update->getEndPos() ); - //This is critical -- in the case we have sloped lines (at the end, we'll fix it) -// lineEnd.z = lineStart.z; - - //Get the length of the line - lineVector.set( &lineEnd ); - lineVector.sub( &lineStart ); - Real lineLength = lineVector.length(); - - //Get the middle point (we'll use this to determine how far we are from - //that to calculate our height -- middle point is the highest). - Coord3D lineMiddle; - lineMiddle.set( &lineStart ); - lineMiddle.add( &lineEnd ); - lineMiddle.scale( 0.5 ); - - //The half length is used to scale with the distance from middle to - //get our cos( 0 to 0.25 PI) cos value - Real halfLength = lineLength * 0.5f; - - //Now calculate which segment we will use. - Real startSegmentRatio = segment / ((Real)data->m_segments); - Real endSegmentRatio = (segment + 1.0f) / ((Real)data->m_segments); - - //Offset the segment ever-so-slightly to minimize overlap -- only apply - //to segments that are not the start/end point - if( segment > 0 ) - { - startSegmentRatio -= data->m_segmentOverlapRatio; - } - if( segment < data->m_segments - 1 ) - { - endSegmentRatio += data->m_segmentOverlapRatio; - } - - //Calculate our start segment position on the *ground*. - Coord3D segmentStart, segmentEnd, vector; - vector.set( &lineVector ); - vector.scale( startSegmentRatio ); - segmentStart.set( &lineStart ); - segmentStart.add( &vector ); - - //Calculate our end segment position on the *ground*. - vector.set( &lineVector ); - vector.scale( endSegmentRatio ); - segmentEnd.set( &lineStart ); - segmentEnd.add( &vector ); - - //-------------------------------------------------------------------------------- - //Now at this point, we have our segment line in the level positions that we want. - //Calculate the raised height for the start/end segment positions using cosine. - //-------------------------------------------------------------------------------- - - //Calculate the distance from midpoint for the start positions. - vector.set( &lineMiddle ); - vector.sub( &segmentStart ); - Real dist = vector.length(); - Real scaledRadians = dist / halfLength * PI * 0.5f; - Real height = cos( scaledRadians ); - height *= data->m_arcHeight; - segmentStart.z += height; - - //Now do the same thing for the end position. - vector.set( &lineMiddle ); - vector.sub( &segmentEnd ); - dist = vector.length(); - scaledRadians = dist / halfLength * PI * 0.5f; - height = cos( scaledRadians ); - height *= data->m_arcHeight; - segmentEnd.z += height; - - //This makes the laser skim the ground rather than penetrate it! - laserPoints[ 0 ].Set( segmentStart.x, segmentStart.y, - MAX( segmentStart.z, 2.0f + TheTerrainLogic->getGroundHeight(segmentStart.x, segmentStart.y) ) ); - laserPoints[ 1 ].Set( segmentEnd.x, segmentEnd.y, - MAX( segmentEnd.z, 2.0f + TheTerrainLogic->getGroundHeight(segmentEnd.x, segmentEnd.y) ) ); - - } - else - { - //No arc -- way simpler! - laserPoints[ 0 ].Set( update->getStartPos()->x, update->getStartPos()->y, update->getStartPos()->z ); - laserPoints[ 1 ].Set( update->getEndPos()->x, update->getEndPos()->y, update->getEndPos()->z ); - } - - //Get the color components for calculation purposes. - Real innerRed, innerGreen, innerBlue, innerAlpha, outerRed, outerGreen, outerBlue, outerAlpha; - GameGetColorComponentsReal( data->m_innerColor, &innerRed, &innerGreen, &innerBlue, &innerAlpha ); - GameGetColorComponentsReal( data->m_outerColor, &outerRed, &outerGreen, &outerBlue, &outerAlpha ); - - for( Int i = data->m_numBeams - 1; i >= 0; i-- ) - { - - Real alpha, width; - int index = segment * data->m_numBeams + i; - - if( data->m_numBeams == 1 ) - { - width = data->m_innerBeamWidth * update->getWidthScale(); - alpha = innerAlpha; - } - else - { - //Calculate the scale between min and max values - //0 means use min value, 1 means use max value - //0.2 means min value + 20% of the diff between min and max - Real scale = i / ( data->m_numBeams - 1.0f); - Real ultimateScale = update->getWidthScale(); - width = (data->m_innerBeamWidth + scale * (data->m_outerBeamWidth - data->m_innerBeamWidth)); - width *= ultimateScale; - alpha = innerAlpha + scale * (outerAlpha - innerAlpha); - } - - - //Calculate the number of times to tile the line based on the height of the texture used. - if( m_texture && data->m_tile ) - { - //Calculate the length of the line. - Vector3 lineVector; - Vector3::Subtract( laserPoints[1], laserPoints[0], &lineVector ); - Real length = lineVector.Length(); - - //Adjust tile factor so texture is NOT stretched but tiled equally in both width and length. - Real tileFactor = length/width*m_textureAspectRatio*data->m_tilingScalar; - - //Set the tile factor - m_line3D[ index ]->Set_Texture_Tile_Factor( tileFactor ); //number of times to tile texture across each segment - } - - m_line3D[ index ]->Set_Width( width ); - m_line3D[ index ]->Set_Points( 2, &laserPoints[0] ); - } - } - } - - return; -} - -// ------------------------------------------------------------------------------------------------ -/** CRC */ -// ------------------------------------------------------------------------------------------------ -void W3DLaserDraw::crc( Xfer *xfer ) -{ - - // extend base class - DrawModule::crc( xfer ); - -} - -// ------------------------------------------------------------------------------------------------ -/** Xfer method - * Version Info: - * 1: Initial version */ -// ------------------------------------------------------------------------------------------------ -void W3DLaserDraw::xfer( Xfer *xfer ) -{ - - // version - const XferVersion currentVersion = 1; - XferVersion version = currentVersion; - xfer->xferVersion( &version, currentVersion ); - - // extend base class - DrawModule::xfer( xfer ); - - // Kris says there is no data to save for these, go ask him. - // m_selfDirty is not saved, is runtime only - -} - -// ------------------------------------------------------------------------------------------------ -/** Load post process */ -// ------------------------------------------------------------------------------------------------ -void W3DLaserDraw::loadPostProcess( void ) -{ - - // extend base class - DrawModule::loadPostProcess(); - - m_selfDirty = true; // so we update the first time after reload - -} diff --git a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWater.cpp b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWater.cpp deleted file mode 100644 index 3b15a0667ef..00000000000 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWater.cpp +++ /dev/null @@ -1,3489 +0,0 @@ -/* -** 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 . -*/ - -//////////////////////////////////////////////////////////////////////////////// -// // -// (c) 2001-2003 Electronic Arts Inc. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: W3DWater.cpp ///////////////////////////////////////////////////////////////////////////// -// Created: Mark Wilczynski, June 2001 -// Desc: Draw reflective water surface. Also handles drawing of waves/ripples -// on the surface. -/////////////////////////////////////////////////////////////////////////////////////////////////// - -#define SCROLL_UV - -// INCLUDES /////////////////////////////////////////////////////////////////////////////////////// -#include "W3DDevice/GameClient/W3DWater.h" -#include "W3DDevice/GameClient/HeightMap.h" -#include "W3DDevice/GameClient/W3DShroud.h" -#include "W3DDevice/GameClient/W3DWaterTracks.h" -#include "W3DDevice/GameClient/W3DAssetManager.h" -#include "texture.h" -#include "assetmgr.h" -#include "rinfo.h" -#include "camera.h" -#include "scene.h" -#include "dx8wrapper.h" -#include "light.h" -#include "d3dx8math.h" -#include "simplevec.h" -#include "mesh.h" -#include "matinfo.h" - -#include "Common/FramePacer.h" -#include "Common/GameState.h" -#include "Common/GlobalData.h" -#include "Common/PerfTimer.h" -#include "Common/Xfer.h" -#include "Common/GameLOD.h" - -#include "GameClient/Water.h" -#include "GameLogic/GameLogic.h" -#include "GameLogic/PolygonTrigger.h" -#include "GameLogic/ScriptEngine.h" -#include "W3DDevice/GameClient/W3DShaderManager.h" -#include "W3DDevice/GameClient/W3DDisplay.h" -#include "W3DDevice/GameClient/W3DPoly.h" -#include "W3DDevice/GameClient/W3DScene.h" -#include "W3DDevice/GameClient/W3DCustomScene.h" - - - -#define MIPMAP_BUMP_TEXTURE - -// DEFINES //////////////////////////////////////////////////////////////////////////////////////// -#define SKYPLANE_SIZE (384.0f*MAP_XY_FACTOR) -#define SKYPLANE_HEIGHT (30.0f) - -#define SKYBODY_TEXTURE "TSMoonLarg.tga" -#define SKYBODY_SIZE 45.0f //extent or radius of sky body - -#define SKYBODY_X 150.0f //location of skybody -#define SKYBODY_Y 550.0f //location of skybody - -/* in the bay -#define SKYBODY_X 120.0f //location of skybody -#define SKYBODY_Y 75.0f //location of skybody -*/ - -#define SKYBODY_HEIGHT SKYPLANE_HEIGHT //altitude of sky body (z-buffer disabled, so can equal sky height). - -//GeForce3 water system defines -#define PATCH_SIZE 15 //number of vertices on patch edge. Large patches may waste vertices off edge of screen. -#define PATCH_UV_TILES 42 //number of times the bump map texture is tiled across patch (must be integer!). -#define PATCH_SCALE (4.0f * MAP_XY_FACTOR) //horizontal scale factor. Adjust this and size to get desired vertex density. -#define SEA_REFLECTION_SIZE 256 //dimensions of reflection texture - -#define SEA_BUMP_SCALE (0.06f) //scales the du/dv offsets stored in bump map (~ amount to perturb) -#define BUMP_SIZE (50.f) -#define REFLECTION_FACTOR 0.1f - -#define PATCH_WIDTH (PATCH_SIZE-1) //internal defines -#define PATCH_UV_SCALE ((Real)PATCH_UV_TILES/(Real)PATCH_WIDTH) - -//3D Grid Mesh Water defines. -#define WATER_MESH_OPACITY 0.5f -#define WATER_MESH_X_VERTICES 128 -#define WATER_MESH_Y_VERTICES 128 -#define WATER_MESH_SPACING MAP_XY_FACTOR //same as terrain - -#ifdef USE_MESH_NORMALS -#define WATER_MESH_FVF DX8_FVF_XYZNDUV2 -typedef VertexFormatXYZNDUV2 MaterMeshVertexFormat; -#else -#define WATER_MESH_FVF DX8_FVF_XYZDUV2 -typedef VertexFormatXYZDUV2 MaterMeshVertexFormat; -#endif - -// Converts a FLOAT to a DWORD for use in SetRenderState() calls -static inline DWORD F2DW( FLOAT f ) { return *((DWORD*)&f); } - -#define DRAW_WATER_WAKES -/// @todo: Fix clipping of objects that intersect the mirror surface -//#define CLIP_GEOMETRY_TO_PLANE // this enables clipping of objects that intersect the mirror surfaces - -// Some shader combinations that can be useful in rendering water: - -// Modulate stage0 with stage1 texture. Also modulate stage 0 with vertex color. -#define SC_DETAIL_BLEND ( SHADE_CNST(ShaderClass::PASS_LEQUAL, ShaderClass::DEPTH_WRITE_ENABLE, ShaderClass::COLOR_WRITE_ENABLE,\ - ShaderClass::SRCBLEND_SRC_ALPHA,ShaderClass::DSTBLEND_ONE_MINUS_SRC_ALPHA, ShaderClass::FOG_DISABLE, ShaderClass::GRADIENT_MODULATE, ShaderClass::SECONDARY_GRADIENT_DISABLE, \ - ShaderClass::TEXTURING_ENABLE, ShaderClass::ALPHATEST_DISABLE, ShaderClass::CULL_MODE_ENABLE, ShaderClass::DETAILCOLOR_DETAILBLEND, ShaderClass::DETAILALPHA_DISABLE) ) - -// Just a z-buffer fill, nothing is written to the color buffer. -#define SC_ZFILL_BLEND ( SHADE_CNST(ShaderClass::PASS_LEQUAL, ShaderClass::DEPTH_WRITE_ENABLE, ShaderClass::COLOR_WRITE_DISABLE, ShaderClass::SRCBLEND_ZERO, \ - ShaderClass::DSTBLEND_ONE, ShaderClass::FOG_DISABLE, ShaderClass::GRADIENT_MODULATE, ShaderClass::SECONDARY_GRADIENT_DISABLE, ShaderClass::TEXTURING_ENABLE, \ - ShaderClass::DETAILCOLOR_SCALE, ShaderClass::DETAILALPHA_DISABLE, ShaderClass::ALPHATEST_DISABLE, ShaderClass::CULL_MODE_ENABLE, \ - ShaderClass::DETAILCOLOR_SCALE, ShaderClass::DETAILALPHA_DISABLE) ) - -// No texturing, just vertex color with vertex alpha -#define SC_ZFILL_BLENDx ( SHADE_CNST(ShaderClass::PASS_LEQUAL, ShaderClass::DEPTH_WRITE_ENABLE, ShaderClass::COLOR_WRITE_ENABLE, \ - ShaderClass::SRCBLEND_ZERO, ShaderClass::DSTBLEND_SRC_COLOR, ShaderClass::FOG_DISABLE, ShaderClass::GRADIENT_MODULATE, ShaderClass::SECONDARY_GRADIENT_DISABLE, \ - ShaderClass::TEXTURING_DISABLE, ShaderClass::DETAILCOLOR_DISABLE, ShaderClass::DETAILALPHA_DISABLE, ShaderClass::ALPHATEST_DISABLE, ShaderClass::CULL_MODE_ENABLE, \ - ShaderClass::DETAILCOLOR_DISABLE, ShaderClass::DETAILALPHA_DISABLE) ) - -// Modulate blended with vertex alpha modulation -#define SC_ZFILL_MODULATE_TEX ( SHADE_CNST(ShaderClass::PASS_LEQUAL, ShaderClass::DEPTH_WRITE_ENABLE, ShaderClass::COLOR_WRITE_ENABLE,\ - ShaderClass::SRCBLEND_ZERO, ShaderClass::DSTBLEND_SRC_COLOR, ShaderClass::FOG_DISABLE, ShaderClass::GRADIENT_MODULATE, ShaderClass::SECONDARY_GRADIENT_DISABLE, \ - ShaderClass::TEXTURING_ENABLE, ShaderClass::ALPHATEST_DISABLE, ShaderClass::CULL_MODE_DISABLE, ShaderClass::DETAILCOLOR_DISABLE, ShaderClass::DETAILALPHA_DISABLE) ) - -// Alpha blended with vertex alpha modulation -#define SC_ZFILL_ALPHA_TEX ( SHADE_CNST(ShaderClass::PASS_LEQUAL, ShaderClass::DEPTH_WRITE_ENABLE, ShaderClass::COLOR_WRITE_ENABLE,\ - ShaderClass::SRCBLEND_SRC_ALPHA, ShaderClass::DSTBLEND_ONE_MINUS_SRC_ALPHA, ShaderClass::FOG_DISABLE, ShaderClass::GRADIENT_DISABLE, ShaderClass::SECONDARY_GRADIENT_DISABLE, \ - ShaderClass::TEXTURING_ENABLE, ShaderClass::ALPHATEST_DISABLE, ShaderClass::CULL_MODE_DISABLE, ShaderClass::DETAILCOLOR_DISABLE, ShaderClass::DETAILALPHA_DISABLE) ) - -// Alpha blended with vertex alpha modulation -#define SC_OPAQUE_TEXONLY ( SHADE_CNST(ShaderClass::PASS_LEQUAL, ShaderClass::DEPTH_WRITE_ENABLE, ShaderClass::COLOR_WRITE_ENABLE,\ - ShaderClass::SRCBLEND_ONE, ShaderClass::DSTBLEND_ZERO, ShaderClass::FOG_DISABLE, ShaderClass::GRADIENT_DISABLE, ShaderClass::SECONDARY_GRADIENT_DISABLE, \ - ShaderClass::TEXTURING_ENABLE, ShaderClass::ALPHATEST_DISABLE, ShaderClass::CULL_MODE_DISABLE, ShaderClass::DETAILCOLOR_DISABLE, ShaderClass::DETAILALPHA_DISABLE) ) - -// Alpha blended with vertex alpha modulation -#define SC_ZFILL_BLEND3 ( SHADE_CNST(ShaderClass::PASS_LEQUAL, ShaderClass::DEPTH_WRITE_ENABLE, ShaderClass::COLOR_WRITE_ENABLE,\ - ShaderClass::SRCBLEND_SRC_ALPHA, ShaderClass::DSTBLEND_ONE_MINUS_SRC_ALPHA, ShaderClass::FOG_DISABLE, ShaderClass::GRADIENT_MODULATE, ShaderClass::SECONDARY_GRADIENT_DISABLE, \ - ShaderClass::TEXTURING_ENABLE, ShaderClass::ALPHATEST_DISABLE, ShaderClass::CULL_MODE_DISABLE, ShaderClass::DETAILCOLOR_DISABLE, ShaderClass::DETAILALPHA_DISABLE) ) - -static ShaderClass zFillAlphaShader(SC_ZFILL_BLEND3); -static ShaderClass blendStagesShader(SC_DETAIL_BLEND); - -WaterRenderObjClass *TheWaterRenderObj=NULL; ///Release(); (p)=NULL; } } - -void doSkyBoxSet(Bool startDraw) -{ - if (TheWritableGlobalData) - TheWritableGlobalData->m_drawSkyBox = startDraw; -} - - -#define DONUT_SIDES 90 -#define INNER_RADIUS 200.0f -#define OUTER_RADIUS 250.0f -#define TEXTURE_REPEAT_COUNT 16 -#define DONUT_HEIGHT 15.0f -//#define DO_FLAT_DONUT -#define AMP_SCALE (30.0f/120.0f) -#define WAVE_FREQ 0.3f -#define AMP_SCALE2 (10.0f/120.0f) -#define NOISE_FREQ (2.0f*PI/WAVE_FREQ) - -#define NOISE_REPEAT_FACTOR ((float)(1.0f/(16.0f))) - - -static Bool wireframeForDebug = 0; - -void WaterRenderObjClass::setupJbaWaterShader(void) -{ - if (!TheWaterTransparency->m_additiveBlend) - DX8Wrapper::Set_Shader(ShaderClass::_PresetAlphaShader); - else - DX8Wrapper::Set_Shader(ShaderClass::_PresetAdditiveShader); - - VertexMaterialClass *vmat=VertexMaterialClass::Get_Preset(VertexMaterialClass::PRELIT_DIFFUSE); - DX8Wrapper::Set_Material(vmat); - REF_PTR_RELEASE(vmat); - m_riverTexture->Get_Filter().Set_Mag_Filter(TextureFilterClass::FILTER_TYPE_BEST); - m_riverTexture->Get_Filter().Set_Min_Filter(TextureFilterClass::FILTER_TYPE_BEST); - m_riverTexture->Get_Filter().Set_Mip_Mapping(TextureFilterClass::FILTER_TYPE_BEST); - - -// Setting *setting=&m_settings[m_tod]; - - - DX8Wrapper::Apply_Render_State_Changes(); //force update of view and projection matrices - DX8Wrapper::Set_DX8_Texture_Stage_State( 0, D3DTSS_ALPHAOP, D3DTOP_ADD ); - if (!m_riverAlphaEdge->Is_Initialized()) - m_riverAlphaEdge->Init(); - DX8Wrapper::_Get_D3D_Device8()->SetTexture(3,m_riverAlphaEdge->Peek_D3D_Texture()); - DX8Wrapper::Set_DX8_Texture_Stage_State(3, D3DTSS_ADDRESSU, D3DTADDRESS_WRAP); - DX8Wrapper::Set_DX8_Texture_Stage_State(3, D3DTSS_ADDRESSV, D3DTADDRESS_WRAP); - DX8Wrapper::Set_DX8_Texture_Stage_State(0, D3DTSS_TEXCOORDINDEX, 0); - DX8Wrapper::Set_DX8_Texture_Stage_State(1, D3DTSS_TEXCOORDINDEX, 0); - DX8Wrapper::Set_DX8_Texture_Stage_State(3, D3DTSS_TEXCOORDINDEX, 1); - - Bool doSparkles = true; - - if (m_riverWaterPixelShader && doSparkles) { - if (!m_waterSparklesTexture->Is_Initialized()) - m_waterSparklesTexture->Init(); - DX8Wrapper::_Get_D3D_Device8()->SetTexture(1,m_waterSparklesTexture->Peek_D3D_Texture()); - - if (!m_waterNoiseTexture->Is_Initialized()) - m_waterNoiseTexture->Init(); - DX8Wrapper::_Get_D3D_Device8()->SetTexture(2,m_waterNoiseTexture->Peek_D3D_Texture()); - - DX8Wrapper::Set_DX8_Texture_Stage_State(1, D3DTSS_ADDRESSU, D3DTADDRESS_WRAP); - DX8Wrapper::Set_DX8_Texture_Stage_State(1, D3DTSS_ADDRESSV, D3DTADDRESS_WRAP); - - DX8Wrapper::Set_DX8_Texture_Stage_State(2, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEPOSITION); - // Two output coordinates are used. - DX8Wrapper::Set_DX8_Texture_Stage_State(2, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2); - DX8Wrapper::Set_DX8_Texture_Stage_State(2, D3DTSS_ADDRESSU, D3DTADDRESS_WRAP); - DX8Wrapper::Set_DX8_Texture_Stage_State(2, D3DTSS_ADDRESSV, D3DTADDRESS_WRAP); - D3DXMATRIX inv; - float det; - - Matrix4x4 curView; - DX8Wrapper::_Get_DX8_Transform(D3DTS_VIEW, curView); - D3DXMatrixInverse(&inv, &det, (D3DXMATRIX*)&curView); - D3DXMATRIX scale; - - D3DXMatrixScaling(&scale, NOISE_REPEAT_FACTOR, NOISE_REPEAT_FACTOR,1); - D3DXMATRIX destMatrix = inv * scale; - D3DXMatrixTranslation(&scale, m_riverVOrigin, m_riverVOrigin,0); - destMatrix = destMatrix*scale; - DX8Wrapper::_Set_DX8_Transform(D3DTS_TEXTURE2, *(Matrix4x4*)&destMatrix); - - } - m_pDev->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR ); - m_pDev->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR ); - m_pDev->SetTextureStageState( 1, D3DTSS_MINFILTER, D3DTEXF_LINEAR ); - m_pDev->SetTextureStageState( 1, D3DTSS_MAGFILTER, D3DTEXF_LINEAR ); - m_pDev->SetTextureStageState( 2, D3DTSS_MINFILTER, D3DTEXF_LINEAR ); - m_pDev->SetTextureStageState( 2, D3DTSS_MAGFILTER, D3DTEXF_LINEAR ); - m_pDev->SetTextureStageState( 3, D3DTSS_MINFILTER, D3DTEXF_LINEAR ); - m_pDev->SetTextureStageState( 3, D3DTSS_MAGFILTER, D3DTEXF_LINEAR ); - if (m_riverWaterPixelShader){ - DX8Wrapper::_Get_D3D_Device8()->SetPixelShaderConstant(0, D3DXVECTOR4(REFLECTION_FACTOR, REFLECTION_FACTOR, REFLECTION_FACTOR, 1.0f), 1); - DX8Wrapper::_Get_D3D_Device8()->SetPixelShader(m_riverWaterPixelShader); - } -} - - - - -//------------------------------------------------------------------------------------------------- -/** Destructor. Releases w3d assets. */ -//------------------------------------------------------------------------------------------------- -WaterRenderObjClass::~WaterRenderObjClass(void) -{ - REF_PTR_RELEASE(m_meshVertexMaterialClass); - REF_PTR_RELEASE(m_vertexMaterialClass); - REF_PTR_RELEASE(m_meshLight); - REF_PTR_RELEASE(m_alphaClippingTexture); - REF_PTR_RELEASE (m_skyBox); - - REF_PTR_RELEASE (m_riverTexture); - REF_PTR_RELEASE (m_whiteTexture); - REF_PTR_RELEASE (m_waterNoiseTexture); - REF_PTR_RELEASE (m_riverAlphaEdge); - REF_PTR_RELEASE (m_waterSparklesTexture); - - Int i; - - for(i=0; iGet_Level_Description(d3dsd); - - if (Get_Bytes_Per_Pixel(d3dsd.Format) != 4) - { - // LORENZEN WAS BUGGED BY THIS, - // DEBUG_CRASH(("WaterRenderObjClass::Invalid BumpMap format - Was it compressed?") ); - return S_OK; - } - - if (pBumpSource->Peek_D3D_Texture()) - { - numLevels=pBumpSource->Peek_D3D_Texture()->GetLevelCount(); - } - else - return S_OK; - - pTex[0]=DX8Wrapper::_Create_DX8_Texture(d3dsd.Width,d3dsd.Height,WW3D_FORMAT_U8V8,MIP_LEVELS_ALL,D3DPOOL_MANAGED,false); - - for (Int level=0; level < numLevels; level++) - { - surf=pBumpSource->Get_Surface_Level(level); - surf->Get_Description(d3dsd); - pSrc=(unsigned char *)surf->Lock((int *)&dwSrcPitch); - - pTex[0]->LockRect( level, &d3dlr, 0, 0 ); - DWORD dwDstPitch = (DWORD)d3dlr.Pitch; - BYTE* pDst = (BYTE*)d3dlr.pBits; - - for( DWORD y=0; y1 ) ? 63 : 127; - - switch( D3DFMT_V8U8)//m_BumpMapFormat ) - { - case D3DFMT_V8U8: - *pDstT++ = (BYTE)iDu; - *pDstT++ = (BYTE)iDv; - break; - - case D3DFMT_L6V5U5: - *(WORD*)pDstT = (WORD)( ( (iDu>>3) & 0x1f ) << 0 ); - *(WORD*)pDstT |= (WORD)( ( (iDv>>3) & 0x1f ) << 5 ); - *(WORD*)pDstT |= (WORD)( ( ( uL>>2) & 0x3f ) << 10 ); - pDstT += 2; - break; - - case D3DFMT_X8L8V8U8: - *pDstT++ = (BYTE)iDu; - *pDstT++ = (BYTE)iDv; - *pDstT++ = (BYTE)uL; - *pDstT++ = (BYTE)0L; - break; - } - - // Move one pixel to the left (src is 32-bpp) - pSrcB0+=4; pSrcB1+=4; pSrcB2+=4; - } - - // Move to the next line - pSrc += dwSrcPitch; pDst += dwDstPitch; - } - - pTex[0]->UnlockRect(level); - surf->Unlock(); - REF_PTR_RELEASE (surf); - } - -#else - surf=pBumpSource->Get_Surface_Level(); - surf->Get_Description(d3dsd); - pSrc=(unsigned char *)surf->Lock((int *)&dwSrcPitch); - - // Create the bumpmap's surface and texture objects - m_pBumpTexture[i]=DX8Wrapper::_Create_DX8_Texture(d3dsd.Width,d3dsd.Height,WW3D_FORMAT_U8V8,TextureClass::MIP_LEVELS_1,D3DPOOL_MANAGED,false); - - // Fill the bits of the new texture surface with bits from - // a private format. - - m_pBumpTexture[i]->LockRect( 0, &d3dlr, 0, 0 ); - DWORD dwDstPitch = (DWORD)d3dlr.Pitch; - BYTE* pDst = (BYTE*)d3dlr.pBits; - - for( DWORD y=0; y1 ) ? 63 : 127; - - switch( D3DFMT_V8U8)//m_BumpMapFormat ) - { - case D3DFMT_V8U8: - *pDstT++ = (BYTE)iDu; - *pDstT++ = (BYTE)iDv; - break; - - case D3DFMT_L6V5U5: - *(WORD*)pDstT = (WORD)( ( (iDu>>3) & 0x1f ) << 0 ); - *(WORD*)pDstT |= (WORD)( ( (iDv>>3) & 0x1f ) << 5 ); - *(WORD*)pDstT |= (WORD)( ( ( uL>>2) & 0x3f ) << 10 ); - pDstT += 2; - break; - - case D3DFMT_X8L8V8U8: - *pDstT++ = (BYTE)iDu; - *pDstT++ = (BYTE)iDv; - *pDstT++ = (BYTE)uL; - *pDstT++ = (BYTE)0L; - break; - } - - // Move one pixel to the left (src is 32-bpp) - pSrcB0+=4; pSrcB1+=4; pSrcB2+=4; - } - - // Move to the next line - pSrc += dwSrcPitch; pDst += dwDstPitch; - } - - m_pBumpTexture[i]->UnlockRect(0); - surf->Unlock(); -#endif - - return S_OK; -} - -//------------------------------------------------------------------------------------------------- -/** Create and fill a D3D vertex buffer with water surface vertices */ -//------------------------------------------------------------------------------------------------- -HRESULT WaterRenderObjClass::generateVertexBuffer( Int sizeX, Int sizeY, Int vertexSize, Bool doStatic) -{ - m_numVertices=sizeX*sizeY; - //Assuming dynamic vertex buffer, allocate maximum multiple of required size to allow rendering from - //different parts of the buffer. 5-15-03: Disabled this since we use DISCARD mode instead to avoid Nvidia Runtime bug. -MW - //m_numVertices=(65536 / (sizeX*sizeY))*sizeX*sizeY; - - SEA_PATCH_VERTEX* pVertices; - - Setting *setting=&m_settings[m_tod]; - - HRESULT hr; - - //default setting for a dynamic vertex buffer - D3DPOOL pool = D3DPOOL_DEFAULT; - DWORD usage = D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC; - DWORD fvf = WATER_MESH_FVF; - - if (doStatic) - { //change settings for a static vertex buffer - pool = D3DPOOL_MANAGED; - usage = D3DUSAGE_WRITEONLY; - fvf=0;// DX8 Docs confusing on this. Say no FVF for vertex shaders. Else DX8_FVF_XYZDUV1; - m_numVertices=sizeX*sizeY; - } - - if (m_vertexBufferD3D == NULL) - { // Create vertex buffer - - if (FAILED(hr=m_pDev->CreateVertexBuffer - ( - m_numVertices*vertexSize, - usage, - fvf, - pool, - &m_vertexBufferD3D - ))) - return hr; - } - - m_vertexBufferD3DOffset=0; - - if (!doStatic) - return S_OK; //only create the buffer, other code will fill it. - - // load results into buffer - if (FAILED(hr=m_vertexBufferD3D->Lock - ( - 0, - m_numVertices*sizeof(SEA_PATCH_VERTEX), - (BYTE**)&pVertices, - 0//D3DLOCK_DISCARD - ))) - return hr; - - Int x,z; - for (z=0; zx=(float)x; - pVertices->y=m_level; - pVertices->z=(float)z; - - pVertices->tu=(float)x*PATCH_UV_SCALE; - pVertices->tv=(float)z*PATCH_UV_SCALE; - pVertices->c=setting->transparentWaterDiffuse; //vertex alpha/color - pVertices++; - } - } - - if (FAILED(hr=m_vertexBufferD3D->Unlock())) return hr; - - return S_OK; -} - -//------------------------------------------------------------------------------------------------- -/** Create and fill a D3D index buffer with water surface strip indices */ -//------------------------------------------------------------------------------------------------- -HRESULT WaterRenderObjClass::generateIndexBuffer(Int sizeX, Int sizeY) -{ - HRESULT hr; - - //Will need SizeY-1 strips, each of length SizeX*2 (2 indices per strip segment). - //Will also need 2 extra indices to connect each strip to next one (except last strip) - //Total index buffer size = (SizeY-1)*(SizeX*2+2) - 2 (drop the extra 2 indices from last strip) - - m_numIndices=(sizeY-1)*(sizeX*2+2) - 2; - - //old way - - // Create index buffer - WORD* pIndices; - - if (FAILED(hr=m_pDev->CreateIndexBuffer - ( - (m_numIndices+2)*sizeof(WORD), - D3DUSAGE_WRITEONLY, - D3DFMT_INDEX16, - D3DPOOL_MANAGED, - &m_indexBufferD3D - ))) - return hr; - - if (FAILED(hr=m_indexBufferD3D->Lock - ( - 0, - m_numIndices*sizeof(WORD), - (BYTE**)&pIndices, - 0 - ))) - return hr; - - Int i,j,k; - - for (i=0,j=0,k=0; i0; x-=step) - { - *pIndices++=(WORD)((z-step)*size+(x-step)); - *pIndices++=(WORD)((z-0)*size+(x-step)); - } - // insert additional degenerate to start next row - *pIndices++=pIndices[-1]; - *pIndices++=pIndices[-1]; - } - - s_toggle=!s_toggle; - } -*/ - if (FAILED(hr=m_indexBufferD3D->Unlock())) return hr; - - return S_OK; -} - -//------------------------------------------------------------------------------------------------- -/** Releases all w3d assets, to prepare for Reset device call. */ -//------------------------------------------------------------------------------------------------- -void WaterRenderObjClass::ReleaseResources(void) -{ - - REF_PTR_RELEASE(m_indexBuffer); - - REF_PTR_RELEASE(m_pReflectionTexture); - SAFE_RELEASE(m_vertexBufferD3D); - SAFE_RELEASE(m_indexBufferD3D); - - if (m_waterTrackSystem) - m_waterTrackSystem->ReleaseResources(); - - if (m_dwWavePixelShader) - m_pDev->DeletePixelShader(m_dwWavePixelShader); - - if (m_dwWaveVertexShader) - m_pDev->DeleteVertexShader(m_dwWaveVertexShader); - - if (m_waterPixelShader) - m_pDev->DeletePixelShader(m_waterPixelShader); - - if (m_trapezoidWaterPixelShader) - m_pDev->DeletePixelShader(m_trapezoidWaterPixelShader); - - if (m_riverWaterPixelShader) - m_pDev->DeletePixelShader(m_riverWaterPixelShader); - - m_dwWavePixelShader=0; - m_dwWaveVertexShader=0; - m_waterPixelShader = 0; - m_trapezoidWaterPixelShader=0; - m_riverWaterPixelShader=0; -} - -//------------------------------------------------------------------------------------------------- -/** (Re)allocates all W3D assets after a reset.. */ -//------------------------------------------------------------------------------------------------- -void WaterRenderObjClass::ReAcquireResources(void) -{ - HRESULT hr; - - m_indexBuffer=NEW_REF(DX8IndexBufferClass,(6)); - // Fill up the IB - { - DX8IndexBufferClass::WriteLockClass lockIdxBuffer(m_indexBuffer); - UnsignedShort *ib=lockIdxBuffer.Get_Index_Array(); - //quad of 2 triangles: - // 3-----2 - // | /| - // | / | - // |/ | - // 0-----1 - ib[0]=3; - ib[1]=0; - ib[2]=2; - ib[3]=2; - ib[4]=0; - ib[5]=1; - } - - m_pDev=DX8Wrapper::_Get_D3D_Device8(); - - //We're using the same grid for either 3D Water Mesh or Pixel/Vertex shader. Just - //allocate the right size depending on usage - if (m_meshData) - { - //Create new grid data - if (FAILED(generateIndexBuffer(m_gridCellsX+1,m_gridCellsY+1))) - return; - if (FAILED(generateVertexBuffer(m_gridCellsX+1,m_gridCellsY+1,sizeof(MaterMeshVertexFormat),false))) - return; - } - else - if (m_waterType == WATER_TYPE_2_PVSHADER) - { //pixel/vertex shader based water assets. - if (FAILED(hr=generateIndexBuffer(PATCH_SIZE,PATCH_SIZE))) - return; - - if (FAILED(hr=generateVertexBuffer(PATCH_SIZE,PATCH_SIZE,sizeof(SEA_PATCH_VERTEX),true))) - return; - - //shader decleration - DWORD Declaration[]= - { - (D3DVSD_STREAM(0)), - (D3DVSD_REG(0, D3DVSDT_FLOAT3)), // Position - (D3DVSD_REG(1, D3DVSDT_D3DCOLOR)), // Diffuse - (D3DVSD_REG(2, D3DVSDT_FLOAT2)), // Bump map texture - (D3DVSD_END()) - }; - - hr = W3DShaderManager::LoadAndCreateD3DShader("shaders\\wave.pso", &Declaration[0], 0, false, &m_dwWavePixelShader); - if (FAILED(hr)) - return; - - hr = W3DShaderManager::LoadAndCreateD3DShader("shaders\\wave.vso", &Declaration[0], 0, true, &m_dwWaveVertexShader); - if (FAILED(hr)) - return; - - // Create reflection texture - m_pReflectionTexture = DX8Wrapper::Create_Render_Target (SEA_REFLECTION_SIZE, SEA_REFLECTION_SIZE); - } - - if (m_waterTrackSystem) - m_waterTrackSystem->ReAcquireResources(); - - if (W3DShaderManager::getChipset() >= DC_GENERIC_PIXEL_SHADER_1_1) - { - ID3DXBuffer *compiledShader; - const char *shader = - "ps.1.1\n \ - tex t0 \n\ - tex t1 \n\ - tex t2 \n\ - tex t3\n\ - mul r0,v0,t0 ; blend vertex color into t0. \n\ - mul r1, t1, t2 ; mul\n\ - add r0.rgb, r0, t3\n\ - +mul r0.a, r0, t3\n\ - add r0.rgb, r0, r1\n"; - hr = D3DXAssembleShader( shader, strlen(shader), 0, NULL, &compiledShader, NULL); - if (hr==0) { - hr = DX8Wrapper::_Get_D3D_Device8()->CreatePixelShader((DWORD*)compiledShader->GetBufferPointer(), &m_riverWaterPixelShader); - compiledShader->Release(); - } - shader = - "ps.1.1\n \ - tex t0 \n\ - tex t1 \n\ - texbem t2, t1 ; use t1 as env map adjustment on t2.\n\ - mul r0,v0,t0 ; blend vertex color into t0. \n\ - mul r1.rgb,t2,c0 ; reduce t2 (environment mapped reflection) by constant\n\ - add r0.rgb, r0, r1"; - hr = D3DXAssembleShader( shader, strlen(shader), 0, NULL, &compiledShader, NULL); - if (hr==0) { - hr = DX8Wrapper::_Get_D3D_Device8()->CreatePixelShader((DWORD*)compiledShader->GetBufferPointer(), &m_waterPixelShader); - compiledShader->Release(); - } - shader = - "ps.1.1\n \ - tex t0 ;get water texture\n\ - tex t1 ;get white highlights on black background\n\ - tex t2 ;get white highlights with more tiling\n\ - tex t3 ; get black shroud \n\ - mul r0,v0,t0 ; blend vertex color and alpha into base texture. \n\ - mad r0.rgb, t1, t2, r0 ; blend sparkles and noise \n\ - mul r0.rgb, r0, t3 ; blend in black shroud \n\ - ;\n"; - hr = D3DXAssembleShader( shader, strlen(shader), 0, NULL, &compiledShader, NULL); - if (hr==0) { - hr = DX8Wrapper::_Get_D3D_Device8()->CreatePixelShader((DWORD*)compiledShader->GetBufferPointer(), &m_trapezoidWaterPixelShader); - compiledShader->Release(); - } - } - - //W3D Invalidate textures after losing the device and since we peek at the textures directly, it won't - //know to reinit them for us. Do it here manually: - if (m_riverTexture && !m_riverTexture->Is_Initialized()) - m_riverTexture->Init(); - if (m_waterNoiseTexture && !m_waterNoiseTexture->Is_Initialized()) - m_waterNoiseTexture->Init(); - if (m_riverAlphaEdge && !m_riverAlphaEdge->Is_Initialized()) - m_riverAlphaEdge->Init(); - if (m_waterSparklesTexture && !m_waterSparklesTexture->Is_Initialized()) - m_waterSparklesTexture->Init(); - if (m_whiteTexture && !m_whiteTexture->Is_Initialized()) - { m_whiteTexture->Init(); - SurfaceClass *surface=m_whiteTexture->Get_Surface_Level(); - surface->DrawPixel(0,0,0xffffffff); - REF_PTR_RELEASE(surface); - } -} - -void WaterRenderObjClass::load(void) -{ - if (m_waterTrackSystem) - m_waterTrackSystem->loadTracks(); -} - -//------------------------------------------------------------------------------------------------- -/** Initializes water with dimensions and parent scene. - * During rendering, we will render a water surface of given dimensions - * and reflect the parent scene in its surface. For now, waters are - * forced to be rectangles. */ -//------------------------------------------------------------------------------------------------- -Int WaterRenderObjClass::init(Real waterLevel, Real dx, Real dy, SceneClass *parentScene, WaterType type) -{ - - m_fBumpFrame=0; - m_fBumpScale=SEA_BUMP_SCALE; - - m_dx=dx; - m_dy=dy; - m_level=waterLevel; - - m_LastUpdateTime=timeGetTime(); - m_uScrollPerMs=0.001f; - m_vScrollPerMs=0.001f; - m_uOffset=0; - m_vOffset=0; - - m_parentScene=parentScene; - m_waterType = type; - - /// Hack for now - //m_waterType = WATER_TYPE_0_TRANSLUCENT; - - ///@todo: calculate a real normal/distance for arbitrary planes. - m_planeNormal=Vector3(0,0,1); //water plane normal - m_planeDistance=m_level; //water plane distance(always at zero for now) - - m_meshLight=NEW_REF(LightClass,(LightClass::DIRECTIONAL)); - m_meshLight->Set_Ambient(Vector3(0.1f,0.1f,0.1f)); - m_meshLight->Set_Diffuse(Vector3(1.0f,1.0f,1.0f)); - m_meshLight->Set_Specular(Vector3(1.0f,1.0f,1.0f)); - m_meshLight->Set_Position(Vector3(1000,1000,1000)); - //testLight->Set_Spot_Direction(Vector3(TheGlobalData->m_terrainLightX,TheGlobalData->m_terrainLightY,TheGlobalData->m_terrainLightZ)); - m_meshLight->Set_Spot_Direction(Vector3(-0.57f,-0.57f,-0.57f)); - - //Setup material for 3D Mesh water. - m_meshVertexMaterialClass=NEW_REF(VertexMaterialClass,()); - m_meshVertexMaterialClass->Set_Shininess(20.0); - m_meshVertexMaterialClass->Set_Ambient(1.0f,1.0f,1.0f); - m_meshVertexMaterialClass->Set_Diffuse(1.0f,1.0f,1.0f); - m_meshVertexMaterialClass->Set_Specular(0.5,0.5,0.5); - m_meshVertexMaterialClass->Set_Opacity(WATER_MESH_OPACITY); - m_meshVertexMaterialClass->Set_Lighting(true); - - // - // assign the data from the WaterSettings[] global to the data for this - // render object (we at present only have one water plane) - // - loadSetting( &m_settings[ TIME_OF_DAY_MORNING ], TIME_OF_DAY_MORNING ); - loadSetting( &m_settings[ TIME_OF_DAY_AFTERNOON ], TIME_OF_DAY_AFTERNOON ); - loadSetting( &m_settings[ TIME_OF_DAY_EVENING ], TIME_OF_DAY_EVENING ); - loadSetting( &m_settings[ TIME_OF_DAY_NIGHT ], TIME_OF_DAY_NIGHT ); - - Set_Sort_Level(2); //force water to be drawn after all other non translucent objects in scene. - Set_Force_Visible(TRUE); //water is always visible since it's a composite object made of multiple planes all over the map. - - ReAcquireResources(); -#if 0 //MD does not support the old bump-mapped water at all so no point loading textures. -MW 8-11-03 - if (type == WATER_TYPE_2_PVSHADER || (W3DShaderManager::getChipset() >= DC_GENERIC_PIXEL_SHADER_1_1)) - { //geforce3 specific water requires some extra D3D assets - m_pDev=DX8Wrapper::_Get_D3D_Device8(); - //save previous thumbnail mode - bool thumbnails_enabled = WW3D::Get_Thumbnail_Enabled(); - WW3D::Set_Thumbnail_Enabled(false); - - //load bump map textures off disk - TextureClass *pBumpSource; //temporary textures in a format W3D understands - TextureClass *pBumpSource2; //temporary textures in a format W3D understands - Int i; - i=NUM_BUMP_FRAMES; - while (i--) - { - char bump_name[128]; - - sprintf(bump_name,"caust%.2d.tga",i); - pBumpSource=WW3DAssetManager::Get_Instance()->Get_Texture(bump_name); - sprintf(bump_name,"caustS%.2d.tga",i); - pBumpSource2=WW3DAssetManager::Get_Instance()->Get_Texture(bump_name); - initBumpMap(m_pBumpTexture+i, pBumpSource); - initBumpMap(m_pBumpTexture2+i, pBumpSource2); - WW3DAssetManager::Get_Instance()->Release_Texture(pBumpSource); - WW3DAssetManager::Get_Instance()->Release_Texture(pBumpSource2); - REF_PTR_RELEASE(pBumpSource); - REF_PTR_RELEASE(pBumpSource2); - } - //restore previous thumpnail mode - WW3D::Set_Thumbnail_Enabled(thumbnails_enabled); - } -#endif - - //Setup material for regular water - m_vertexMaterialClass=VertexMaterialClass::Get_Preset(VertexMaterialClass::PRELIT_DIFFUSE); - - - - m_shaderClass = zFillAlphaShader;//ShaderClass::_PresetAlphaShader;ShaderClass::_PresetOpaqueShader;//detailOpaqueShader; - m_shaderClass.Set_Cull_Mode(ShaderClass::CULL_MODE_DISABLE); //water should be visible from both sides - - //Assets used for all types of water - m_alphaClippingTexture=WW3DAssetManager::Get_Instance()->Get_Texture(SKYBODY_TEXTURE); - -#ifdef CLIP_GEOMETRY_TO_PLANE - m_alphaClippingTexture=WW3DAssetManager::Get_Instance()->Get_Texture("alphaclip.tga"); -#endif - - m_skyBox = ((W3DAssetManager*)W3DAssetManager::Get_Instance())->Create_Render_Obj( "new_skybox", TheGlobalData->m_skyBoxScale, 0); - - //Enable clamping on all textures used by the skybox (to reduce corner seams). - if (m_skyBox && m_skyBox->Class_ID() == RenderObjClass::CLASSID_MESH) - { - MeshClass *mesh=(MeshClass*) m_skyBox; - MaterialInfoClass *material = mesh->Get_Material_Info(); - - for (Int i=0; iTexture_Count(); i++) - { - if (material->Peek_Texture(i)) - { - material->Peek_Texture(i)->Get_Filter().Set_U_Addr_Mode(TextureFilterClass::TEXTURE_ADDRESS_CLAMP); - material->Peek_Texture(i)->Get_Filter().Set_V_Addr_Mode(TextureFilterClass::TEXTURE_ADDRESS_CLAMP); - } - } - - REF_PTR_RELEASE(material); - } - - m_riverTexture=WW3DAssetManager::Get_Instance()->Get_Texture(TheWaterTransparency->m_standingWaterTexture.str()); - - //For some reason setting a NULL texture does not result in 0xffffffff for pixel shaders so using explicit "white" texture. - m_whiteTexture=MSGNEW("TextureClass") TextureClass(1,1,WW3D_FORMAT_A4R4G4B4,MIP_LEVELS_1); - SurfaceClass *surface=m_whiteTexture->Get_Surface_Level(); - surface->DrawPixel(0,0,0xffffffff); - REF_PTR_RELEASE(surface); - - m_waterNoiseTexture=WW3DAssetManager::Get_Instance()->Get_Texture("Noise0000.tga"); - m_riverAlphaEdge=WW3DAssetManager::Get_Instance()->Get_Texture("TWAlphaEdge.tga"); - m_waterSparklesTexture=WW3DAssetManager::Get_Instance()->Get_Texture("WaterSurfaceBubbles.tga"); -#ifdef DRAW_WATER_WAKES - m_waterTrackSystem = NEW WaterTracksRenderSystem; - m_waterTrackSystem->init(); -#endif - - return 0; -} - -void WaterRenderObjClass::updateMapOverrides(void) -{ - if (m_riverTexture && TheWaterTransparency->m_standingWaterTexture.compareNoCase(m_riverTexture->Get_Texture_Name()) != 0) - { - REF_PTR_RELEASE(m_riverTexture); - m_riverTexture = WW3DAssetManager::Get_Instance()->Get_Texture(TheWaterTransparency->m_standingWaterTexture.str()); - } -} - -// ------------------------------------------------------------------------------------------------ -// ------------------------------------------------------------------------------------------------ -void WaterRenderObjClass::reset( void ) -{ - - // for vertex animated water mesh reset the values - if( m_meshData) - { - Int i, j; - WaterMeshData *pData; - Int mx = m_gridCellsX + 1; - Int my = m_gridCellsY + 1; - - // go through each mesh point and adjust the height according to the velocity - for( j = 0, pData = m_meshData; j < (my + 2); j++ ) - { - - for( i = 0; i < (mx + 2); i++ ) - { - - // areset grid values for this cell - pData->velocity = 0.0f; - pData->height = 0.0f; - pData->preferredHeight = 0.0f; - pData->status = WaterRenderObjClass::AT_REST; - - // on to the next one - pData++; - - } - - } - - // mesh data is no longer in motion - m_meshInMotion = FALSE; - - } - - if (m_waterTrackSystem) - m_waterTrackSystem->reset(); -} - -void WaterRenderObjClass::enableWaterGrid(Bool state) -{ - m_doWaterGrid = state; - - m_drawingRiver = false; - m_disableRiver = false; - - if (state && m_meshData == NULL) - { //water type has changed, must allocate necessary assets for new water. - //contains the current deformed water surface z(height) values. With 1 vertex invisible border - //around surface to speed up normal calculations. - m_meshDataSize = (m_gridCellsX+1+2)*(m_gridCellsY+1+2); - m_meshData=NEW WaterMeshData[ m_meshDataSize ]; - memset(m_meshData,0,sizeof(WaterMeshData)*(m_gridCellsX+1+2)*(m_gridCellsY+1+2)); - reset(); - - //Release existing grid data - SAFE_RELEASE(m_vertexBufferD3D); - SAFE_RELEASE(m_indexBufferD3D); - - //Create new grid data - if (FAILED(generateIndexBuffer(m_gridCellsX+1,m_gridCellsY+1))) - return; - if (FAILED(generateVertexBuffer(m_gridCellsX+1,m_gridCellsY+1,sizeof(MaterMeshVertexFormat),false))) - return; - } -} - -// ------------------------------------------------------------------------------------------------ -/** Update phase for water if we need it. */ -// ------------------------------------------------------------------------------------------------ -void WaterRenderObjClass::update( void ) -{ - // TheSuperHackers @tweak The water movement time step is now decoupled from the render update. - const Real timeScale = TheFramePacer->getActualLogicTimeScaleOverFpsRatio(); - - { - constexpr const Real MagicOffset = 0.0125f * 33 / 5000; ///< the work of top Munkees; do not question it - - m_riverVOrigin += 0.002f * timeScale; - m_riverXOffset += (Real)(MagicOffset * timeScale); - m_riverYOffset += (Real)(2 * MagicOffset * timeScale); - - // This moves offsets towards zero when smaller -1.0 or larger 1.0 - m_riverXOffset -= (Int)m_riverXOffset; - m_riverYOffset -= (Int)m_riverYOffset; - - m_fBumpFrame += timeScale; - if (m_fBumpFrame >= NUM_BUMP_FRAMES) - m_fBumpFrame = 0.0f; - - // for vertex animated water we need to update the vector field - if( m_doWaterGrid && m_meshInMotion == TRUE ) - { - const Real PREFERRED_HEIGHT_FUDGE = 1.0f; ///< this is close enough to at rest - const Real AT_REST_VELOCITY_FUDGE = 1.0f; ///< when we're close enough to at rest height and velocity we will stop - const Real WATER_DAMPENING = 0.93f; ///< use with up force of 15.0 - Int i, j; - Int mx = m_gridCellsX+1; - Int my = m_gridCellsY+1; - WaterMeshData *pData; - - // - // we will mark the mesh as clean now ... if any of the fields are still in motion - // they will continue to mark the mesh as dirty so processing continues next frame - // - m_meshInMotion = FALSE; - - // go through each mesh point and adjust the height according to the velocity - for( j = 0, pData = m_meshData; j < (my + 2); j++ ) - { - - for( i = 0; i < (mx + 2); i++ ) - { - - // only pay attention to mesh points that are in motion - if( BitIsSet( pData->status, WaterRenderObjClass::IN_MOTION ) ) - { - - // DAMPENING to slow the changes down - pData->velocity *= WATER_DAMPENING; - - // if the height here is below our preferred height, we want to add upward force to counteract it - if( pData->height < pData->preferredHeight ) - pData->velocity -= TheGlobalData->m_gravity * 3.0f; - else - pData->velocity += TheGlobalData->m_gravity * 3.0f; - - // adjust the height at this grid location according to the current velocity - pData->height = pData->height + pData->velocity; - - // - // if we are close enough to our preferred height and our velocity is small enough - // this will be our resting location - // - if( fabs( pData->height - pData->preferredHeight ) < PREFERRED_HEIGHT_FUDGE && - fabs( pData->velocity ) < AT_REST_VELOCITY_FUDGE ) - { - - BitClear( pData->status, WaterRenderObjClass::IN_MOTION ); - pData->height = pData->preferredHeight; - pData->velocity = 0.0f; - - } - else - { - - // there is still motion in the mesh, we need to process next frame - m_meshInMotion = TRUE; - - } - - } - - // on to the next one - pData++; - - } - - } - - } - - } - -} - - -//------------------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------------------- -void WaterRenderObjClass::replaceSkyboxTexture(const AsciiString& oldTexName, const AsciiString& newTextName) -{ - W3DAssetManager* assetManager = ((W3DAssetManager*)W3DAssetManager::Get_Instance()); - - assetManager->replacePrototypeTexture(m_skyBox, oldTexName.str(), newTextName.str()); - - //Enable clamping on all textures used by the skybox (to reduce corner seams). - if (m_skyBox && m_skyBox->Class_ID() == RenderObjClass::CLASSID_MESH) - { - MeshClass *mesh=(MeshClass*) m_skyBox; - MaterialInfoClass *material = mesh->Get_Material_Info(); - - for (Int i=0; iTexture_Count(); i++) - { - if (material->Peek_Texture(i)) - { - material->Peek_Texture(i)->Get_Filter().Set_U_Addr_Mode(TextureFilterClass::TEXTURE_ADDRESS_CLAMP); - material->Peek_Texture(i)->Get_Filter().Set_V_Addr_Mode(TextureFilterClass::TEXTURE_ADDRESS_CLAMP); - } - } - } - -} - -//------------------------------------------------------------------------------------------------- -/** Adjusts various water/sky rendering settings that depend on time of day. */ -//------------------------------------------------------------------------------------------------- -void WaterRenderObjClass::setTimeOfDay(TimeOfDay tod) -{ - m_tod=tod; - if (m_waterType == WATER_TYPE_2_PVSHADER) - generateVertexBuffer(PATCH_SIZE,PATCH_SIZE,sizeof(SEA_PATCH_VERTEX),true); //update the water mesh with new lighting/alpha -} - -//------------------------------------------------------------------------------------------------- -/**Copies GDF settings dealing with a particular time of day into our own - * structures. Also allocates any required W3D assets (textures). */ -//------------------------------------------------------------------------------------------------- -void WaterRenderObjClass::loadSetting( Setting *setting, TimeOfDay timeOfDay ) -{ - SurfaceClass::SurfaceDescription surfaceDesc; - - // sanity - DEBUG_ASSERTCRASH( setting, ("WaterRenderObjClass::loadSetting, NULL setting") ); - - // textures - setting->skyTexture = WW3DAssetManager::Get_Instance()->Get_Texture( WaterSettings[ timeOfDay ].m_skyTextureFile.str() ); - setting->waterTexture = WW3DAssetManager::Get_Instance()->Get_Texture( WaterSettings[ timeOfDay ].m_waterTextureFile.str() ); - - // texelss per unit - setting->skyTexelsPerUnit = WaterSettings[ timeOfDay ].m_skyTexelsPerUnit; - setting->waterTexture->Get_Level_Description( surfaceDesc, 0 ); - setting->skyTexelsPerUnit /= (Real)surfaceDesc.Width; - - // water repeat - setting->waterRepeatCount = WaterSettings[ timeOfDay ].m_waterRepeatCount; - - // U and V scroll per ms - setting->uScrollPerMs = WaterSettings[ timeOfDay ].m_uScrollPerMs; - setting->vScrollPerMs = WaterSettings[ timeOfDay ].m_vScrollPerMs; - - // - // vertex colors - // - // bottom left - setting->vertex00Diffuse = (WaterSettings[ timeOfDay ].m_vertex00Diffuse.red << 16) | - (WaterSettings[ timeOfDay ].m_vertex00Diffuse.green << 8) | - WaterSettings[ timeOfDay ].m_vertex00Diffuse.blue; - // top left - setting->vertex01Diffuse = (WaterSettings[ timeOfDay ].m_vertex01Diffuse.red << 16) | - (WaterSettings[ timeOfDay ].m_vertex01Diffuse.green << 8) | - WaterSettings[ timeOfDay ].m_vertex01Diffuse.blue; - // bottom right - setting->vertex10Diffuse = (WaterSettings[ timeOfDay ].m_vertex10Diffuse.red << 16) | - (WaterSettings[ timeOfDay ].m_vertex10Diffuse.green << 8) | - WaterSettings[ timeOfDay ].m_vertex10Diffuse.blue; - // top right - setting->vertex11Diffuse = (WaterSettings[ timeOfDay ].m_vertex11Diffuse.red << 16) | - (WaterSettings[ timeOfDay ].m_vertex11Diffuse.green << 8) | - WaterSettings[ timeOfDay ].m_vertex11Diffuse.blue; - - // diffuse water color - setting->waterDiffuse = (WaterSettings[ timeOfDay ].m_waterDiffuseColor.alpha << 24) | - (WaterSettings[ timeOfDay ].m_waterDiffuseColor.red << 16) | - (WaterSettings[ timeOfDay ].m_waterDiffuseColor.green << 8) | - WaterSettings[ timeOfDay ].m_waterDiffuseColor.blue; - - // transparent water color - setting->transparentWaterDiffuse = (WaterSettings[ timeOfDay ].m_transparentWaterDiffuse.alpha << 24) | - (WaterSettings[ timeOfDay ].m_transparentWaterDiffuse.red << 16) | - (WaterSettings[ timeOfDay ].m_transparentWaterDiffuse.green << 8) | - WaterSettings[ timeOfDay ].m_transparentWaterDiffuse.blue; - -} - -//------------------------------------------------------------------------------------------------- -/** Our water may use effects that require run-time rendered textures. These - * textures need to be updated before we start rendering to the main screen - * render target because D3D doesn't multiple render targets. */ -//------------------------------------------------------------------------------------------------- -void WaterRenderObjClass::updateRenderTargetTextures(CameraClass *cam) -{ - if (m_waterType == WATER_TYPE_2_PVSHADER && getClippedWaterPlane(cam, NULL) && - TheTerrainRenderObject && TheTerrainRenderObject->getMap()) - renderMirror(cam); //generate texture containing reflected scene -} - -//------------------------------------------------------------------------------------------------- -/** Renders the reflected scene into an offscreen texture. */ -//------------------------------------------------------------------------------------------------- -void WaterRenderObjClass::renderMirror(CameraClass *cam) -{ -#ifdef EXTENDED_STATS - if (DX8Wrapper::stats.m_disableWater) { - return; - } -#endif - Matrix3D OldCameraMatrix=cam->Get_Transform(); - Matrix4x4 FullMatrix4(cam->Get_Transform()); //copy 3x4 matrix into a 4x4 - Vector3 WaterNormal(0,0,1); //normal of plane used for reflection - Vector4 WaterPlane(WaterNormal.X,WaterNormal.Y,WaterNormal.Z,m_level); - Vector3 rRight,rUp,rN,rPos; //orientation and translation vectors of camera - - Matrix4x4 FullMatrix(FullMatrix4.Transpose()); //swap rows/columns - - //reflect camera right vector - Real axis_distance=Vector3::Dot_Product((Vector3&)FullMatrix[0],WaterNormal); - rRight = (Vector3&)FullMatrix[0] - (2.0f*axis_distance*WaterNormal); - - //reflect camera up vector - axis_distance=Vector3::Dot_Product((Vector3&)FullMatrix[1],WaterNormal); - rUp = (Vector3&)FullMatrix[1] - (2.0f*axis_distance*WaterNormal); - - //reflect camera n vector - axis_distance=Vector3::Dot_Product((Vector3&)FullMatrix[2],WaterNormal); - rN = (Vector3&)FullMatrix[2] - (2.0f*axis_distance*WaterNormal); - - //reflect camera position - axis_distance=Vector3::Dot_Product((Vector3&)FullMatrix[3],WaterNormal); //distance cam to origin - axis_distance -= WaterPlane.W; // subtract mirror plane distance to get distance camera to plane - rPos = (Vector3&)FullMatrix[3] - (2.0f*axis_distance*WaterNormal); - - //generate a new camera matrix from reflected vectors - Matrix3D reflectedTransform(rRight,rUp,rN,rPos); - - - DX8Wrapper::Set_Render_Target_With_Z((TextureClass*)m_pReflectionTexture); - - // Clear the backbuffer - WW3D::Begin_Render(false,true,Vector3(0.0f,0.0f,0.0f)); //clearing only z-buffer since background always filled with clouds - - cam->Set_Transform( reflectedTransform ); - - //Force reflected image to be drawn into full texture size - not a viewport inside texture. - Vector2 vMin,vMax,vOldMax,vOldMin; - cam->Get_Viewport(vOldMin,vOldMax); - vMax.X=vMax.Y=1.0f; - vMin.X=vMin.Y=0.0f; - cam->Set_Viewport(vMin,vMax); - - cam->Apply(); //force an update of all the camera dependent parameters like frustum clip planes - - //flip the winding order of polygons to draw the reflected back sides. - ShaderClass::Invert_Backface_Culling(true); - - // Render the scene - renderSky(); - if (m_tod == TIME_OF_DAY_NIGHT) - renderSkyBody(&reflectedTransform); - - WW3D::Render(m_parentScene,cam); - - cam->Set_Transform(OldCameraMatrix); //restore original non-reflected matrix - cam->Set_Viewport(vOldMin,vOldMax); - - cam->Apply(); //force an update of all the camera dependent parameters like frustum clip planes - - ShaderClass::Invert_Backface_Culling(false); - - WW3D::End_Render(false); - - // Change the rendertarget back to the main backbuffer - DX8Wrapper::Set_Render_Target((IDirect3DSurface8 *)NULL); -} - -//------------------------------------------------------------------------------------------------- -/** Renders (draws) the water. - * Algorithm: - * Draw reflected scene. - * Draw reflected sky layer(s) and bodies. - * Clear Zbuffer - * Fill Zbuffer by drawing water surface (allows proper sorting into regular scene). - * Draw non-reflected scene (done in regular app render loop). - * - * This algorithm doesn't apply to translucent water, which is rendered into a - * texture and rendered at end of scene. */ -//------------------------------------------------------------------------------------------------- -//DECLARE_PERF_TIMER(Water) -void WaterRenderObjClass::Render(RenderInfoClass & rinfo) -{ - //USE_PERF_TIMER(Water) - if (TheTerrainRenderObject && !TheTerrainRenderObject->getMap()) - return; //no map has been loaded yet. - - if (((RTS3DScene *)rinfo.Camera.Get_User_Data())->getCustomPassMode() == SCENE_PASS_ALPHA_MASK || - ((SceneClass *)rinfo.Camera.Get_User_Data())->Get_Extra_Pass_Polygon_Mode() == SceneClass::EXTRA_PASS_CLEAR_LINE) - return; //water is not drawn in wireframe or custom scene passes - -#ifdef EXTENDED_STATS - if (DX8Wrapper::stats.m_disableWater) { - return; - } -#endif - if (ShaderClass::Is_Backface_Culling_Inverted()) - return; //the water object will not reflect in itself, so don't do anything if rendering a mirror. - - //this water type needs to rendered after the rest of scene, so buffer it up for later - - // If static sort lists are enabled and this mesh has a sort level, put it on the list instead - // of rendering it. - unsigned int sort_level = (unsigned int)Get_Sort_Level(); - - if (WW3D::Are_Static_Sort_Lists_Enabled() && sort_level != SORT_LEVEL_NONE) - { - WW3D::Add_To_Static_Sort_List(this, sort_level); - return; - } - - switch(m_waterType) - { - case WATER_TYPE_0_TRANSLUCENT: - case WATER_TYPE_3_GRIDMESH: - //Draw the water surface as a bunch of alpha blended tiles covering areas where water is visible - renderWater(); - if (!m_drawingRiver || m_disableRiver) { - renderWaterMesh(); //Draw water surface as 3D deforming mesh if it's enabled on this map. - } - break; - - case WATER_TYPE_2_PVSHADER: - //Pixel/Vertex Shader based water which uses an off-screen rendered reflection texture - drawSea(rinfo); //draw water surface - break; - - case WATER_TYPE_1_FB_REFLECTION: - { - //Normal frame buffer reflection water type. Non translucent. Legacy code we're not using anymore. - Matrix3D OldCameraMatrix=rinfo.Camera.Get_Transform(); - Matrix4x4 FullMatrix4(rinfo.Camera.Get_Transform()); //copy 3x4 matrix into a 4x4 - Vector3 WaterNormal(0,0,1); //normal of plane used for reflection - Vector4 WaterPlane(WaterNormal.X,WaterNormal.Y,WaterNormal.Z,m_level); //assume distance to origin 0 - Vector3 rRight,rUp,rN,rPos; //orientation and translation vectors of camera - - Matrix4x4 FullMatrix(FullMatrix4.Transpose()); //swap rows/columns - - //reflect camera right vector - Real axis_distance=Vector3::Dot_Product((Vector3&)FullMatrix[0],WaterNormal); - rRight = (Vector3&)FullMatrix[0] - (2.0f*axis_distance*WaterNormal); - - //reflect camera up vector - axis_distance=Vector3::Dot_Product((Vector3&)FullMatrix[1],WaterNormal); - rUp = (Vector3&)FullMatrix[1] - (2.0f*axis_distance*WaterNormal); - - //reflect camera n vector - axis_distance=Vector3::Dot_Product((Vector3&)FullMatrix[2],WaterNormal); - rN = (Vector3&)FullMatrix[2] - (2.0f*axis_distance*WaterNormal); - - //reflect camera position - axis_distance=Vector3::Dot_Product((Vector3&)FullMatrix[3],WaterNormal); //distance cam to origin - axis_distance -= WaterPlane.W; // subtract mirror plane distance to get distance camera to plane - rPos = (Vector3&)FullMatrix[3] - (2.0f*axis_distance*WaterNormal); - - //generate a new camera matrix from reflected vectors - Matrix3D reflectedTransform(rRight,rUp,rN,rPos); - - //flip the winding order of polygons to draw the reflected back sides. - ShaderClass::Invert_Backface_Culling(true); - - #ifdef CLIP_GEOMETRY_TO_PLANE - // Set a clip plane, so that only objects above the water are reflected - WaterPlane.W *= -1.0f; //flip sign of plane distance for D3D use. - - // DX8Wrapper::Set_DX8_Clip_Plane( 0, &WaterPlane.X ); - // DX8Wrapper::Set_DX8_Render_State(D3DRS_CLIPPLANEENABLE, D3DCLIPPLANE0 ); //turn on first clip plane - - // Alternate Clipping Method using alpha testing hack! - /**************************************************************************************/ - - D3DXMATRIX inv; - D3DXMATRIX clipMatrix; - Real det; - Matrix4x4 curView; - - //get current view matrix - DX8Wrapper::_Get_DX8_Transform(D3DTS_VIEW, curView); - - //get inverse of view matrix(= view to world matrix) - D3DXMatrixInverse(&inv, &det, (D3DXMATRIX*)&curView); - - //create clipping matrix by inserting our plane equation into the 1st column - D3DXMatrixIdentity(&clipMatrix); - clipMatrix(0,0)=WaterNormal.X; - clipMatrix(1,0)=WaterNormal.Y; - clipMatrix(2,0)=WaterNormal.Z; - clipMatrix(3,0)=WaterPlane.W+0.5f; - inv *=clipMatrix; - - // Change texture wrapping mode to 'clamp' for texture stage 1 - DX8Wrapper::Set_DX8_Texture_Stage_State( 1, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP); - DX8Wrapper::Set_DX8_Texture_Stage_State( 1, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP); - - // Use CameraSpace vertices as input to matrix and use texture wrap mode from stage 1 - DX8Wrapper::Set_DX8_Texture_Stage_State(1, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEPOSITION|1); - // Two output coordinates are used. - DX8Wrapper::Set_DX8_Texture_Stage_State(1, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2); - - // Set texture generation matrix for stage 1 - DX8Wrapper::_Set_DX8_Transform(D3DTS_TEXTURE1, *((Matrix4*)&inv)); - - // Disable bilinear filtering - DX8Wrapper::Set_DX8_Texture_Stage_State(1, D3DTSS_MINFILTER, D3DTEXF_POINT); - DX8Wrapper::Set_DX8_Texture_Stage_State(1, D3DTSS_MAGFILTER, D3DTEXF_POINT); - - // Pass stage 0 texture data untouched(by modulating with white) - DX8Wrapper::Set_DX8_Texture_Stage_State( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE ); //stage 1 texture - DX8Wrapper::Set_DX8_Texture_Stage_State( 1, D3DTSS_COLORARG2, D3DTA_CURRENT ); //previous stage texture - DX8Wrapper::Set_DX8_Texture_Stage_State( 1, D3DTSS_COLOROP, D3DTOP_MODULATE ); //module with white => does nothing - - DX8Wrapper::Set_DX8_Texture_Stage_State( 1, D3DTSS_ALPHAARG1, D3DTA_TEXTURE ); //stage 1 texture - DX8Wrapper::Set_DX8_Texture_Stage_State( 1, D3DTSS_ALPHAARG2, D3DTA_CURRENT ); //previous stage texture - DX8Wrapper::Set_DX8_Texture_Stage_State( 1, D3DTSS_ALPHAOP, D3DTOP_MODULATE ); //modulate with clipping texture - - DX8Wrapper::Set_DX8_Render_State(D3DRS_ALPHAREF,0x00); - DX8Wrapper::Set_DX8_Render_State(D3DRS_ALPHAFUNC,D3DCMP_NOTEQUAL); //pass pixels who's alpha is not zero - DX8Wrapper::Set_DX8_Render_State(D3DRS_ALPHATESTENABLE, true); //test pixels if transparent(clipped) before rendering. - - // Set clipping texture - m_alphaClippingTexture->Set_U_Addr_Mode(TextureClass::TEXTURE_ADDRESS_CLAMP); - m_alphaClippingTexture->Set_V_Addr_Mode(TextureClass::TEXTURE_ADDRESS_CLAMP); - m_alphaClippingTexture->Set_Min_Filter(TextureClass::FILTER_TYPE_NONE); - m_alphaClippingTexture->Set_Mag_Filter(TextureClass::FILTER_TYPE_NONE); - m_alphaClippingTexture->Set_Mip_Mapping(TextureClass::FILTER_TYPE_NONE); - - DX8Wrapper::Set_Texture(0,m_alphaClippingTexture); - - //TODO: Will have to make sure that the shader system is not resetting my stage 1 setup - //while rendering the scene - - /*************************************************************************************/ - #endif - - #if 0 // No longer do simple rendering. - if (TheGlobalData->m_useWaterPlane) - { - //@todo : Would it be better to create a new camera or change the transform of the - //existing one? - rinfo.Camera.Set_Transform( reflectedTransform ); - rinfo.Camera.Apply(); //force an update of all the camera dependent parameters like frustum clip planes - - if(m_useCloudLayer) - { - if (TheGlobalData && TheGlobalData->m_drawEntireTerrain) - m_skyBox->Render(rinfo); - else - { - renderSky(); - if (m_tod == TIME_OF_DAY_NIGHT) - renderSkyBody(&reflectedTransform); - } - } - - WW3D::Render(m_parentScene,&rinfo.Camera); - - rinfo.Camera.Set_Transform(OldCameraMatrix); //restore original non-reflected matrix - rinfo.Camera.Apply(); //force an update of all the camera dependent parameters like frustum clip planes - - //clear the z-buffer to remove changes made by objects inside mirror - DX8Wrapper::Clear(false,true,Vector3(0.1f,0.1f,0.1f)); - } - #endif - - #ifdef CLIP_GEOMETRY_TO_PLANE - //restore default culling mode - // DX8Wrapper::Set_DX8_Render_State(D3DRS_CLIPPLANEENABLE, 0 ); //turn off first clip plane - - //disable texture coordinate generation - DX8Wrapper::Set_DX8_Texture_Stage_State(1, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE); - DX8Wrapper::Set_DX8_Render_State(D3DRS_ALPHATESTENABLE, false); //disable alpha testing - #endif - - ShaderClass::Invert_Backface_Culling(false); //return culling back to normal - - ShaderClass::Invalidate(); //reset shading system so it forces full state set. - - renderWater(); - } - break; - - default: - break; - } - - if (TheGlobalData && TheGlobalData->m_drawSkyBox) - { //center skybox around camera - Vector3 pos=rinfo.Camera.Get_Position(); - pos.Z = TheGlobalData->m_skyBoxPositionZ; - m_skyBox->Set_Position(pos); - m_skyBox->Render(rinfo); - } - - //Clean up after any pixel shaders. - //Force render state apply so that the "NULL" texture gets applied to D3D, thus releasing shroud reference count. - DX8Wrapper::Apply_Render_State_Changes(); - DX8Wrapper::Invalidate_Cached_Render_States(); - - if (m_waterTrackSystem) - m_waterTrackSystem->flush(rinfo); - -// renderWaterMesh(); -// renderWaterWave(); -} - -//------------------------------------------------------------------------------------------------- -/** Clips the water plane to the current camera frustum and returns a bounding - * box enclosing the clipped plane. Returns false if water plane is not visible. */ -//------------------------------------------------------------------------------------------------- -Bool WaterRenderObjClass::getClippedWaterPlane(CameraClass *cam, AABoxClass *box) -{ - const FrustumClass & frustum = cam->Get_Frustum(); - - ClipPolyClass ClippedPoly0; - ClipPolyClass ClippedPoly1; - - ///@todo: generate proper sized polygon - ClippedPoly0.Reset(); - ClippedPoly0.Add_Vertex(Vector3(0,0,m_level)); - ClippedPoly0.Add_Vertex(Vector3(0,m_dy,m_level)); - ClippedPoly0.Add_Vertex(Vector3(m_dx,m_dy,m_level)); - ClippedPoly0.Add_Vertex(Vector3(m_dx,0,m_level)); - - //clip against all 6 frustum planes - ClippedPoly0.Clip(frustum.Planes[0],ClippedPoly1); - ClippedPoly1.Clip(frustum.Planes[1],ClippedPoly0); - ClippedPoly0.Clip(frustum.Planes[2],ClippedPoly1); - ClippedPoly1.Clip(frustum.Planes[3],ClippedPoly0); - ClippedPoly0.Clip(frustum.Planes[4],ClippedPoly1); - ClippedPoly1.Clip(frustum.Planes[5],ClippedPoly0); - - Int final_vcount = ClippedPoly0.Verts.Count(); - - //make sure the polygon is visible - if (final_vcount >= 3) - { - //find axis aligned bounding box around visible polygon - if (box) - box->Init(&(ClippedPoly0.Verts[0]),final_vcount); - return TRUE; - } - - return FALSE; //water plane is not visible -} - -//------------------------------------------------------------------------------------------------- -/** Draws the water surface using a custom D3D vertex/pixel shader and a - * reflection texture. Only tested to work on GeForce3. */ -//------------------------------------------------------------------------------------------------- -void WaterRenderObjClass::drawSea(RenderInfoClass & rinfo) -{ - AABoxClass seaBox; - - if (!getClippedWaterPlane(&rinfo.Camera,&seaBox)) - return; //the sea is not visible - - D3DXMATRIX matProj, matView, matWW3D; - - //create a transform which will flip the y and z coordinates to fit our system - memset(&matWW3D,0,sizeof(D3DMATRIX)); - matWW3D._11=1.0f; - matWW3D._32=1.0f; - matWW3D._23=1.0f; - matWW3D._44=1.0f; - - Matrix3D tm(Transform); - - DX8Wrapper::Set_Transform(D3DTS_WORLD,tm); //position the water surface - DX8Wrapper::Set_Texture(0,NULL); //we'll be setting our own textures, so reset W3D - DX8Wrapper::Set_Texture(1,NULL); //we'll be setting our own textures, so reset W3D - - - DX8Wrapper::Apply_Render_State_Changes(); //force update of view and projection matrices - - Vector3 camTran; - - rinfo.Camera.Get_Transform().Get_Translation(&camTran); - - DX8Wrapper::_Get_DX8_Transform(D3DTS_VIEW, *(Matrix4x4*)&matView); - DX8Wrapper::_Get_DX8_Transform(D3DTS_PROJECTION, *(Matrix4x4*)&matProj); - - //default setup from Kenny's demo - m_pDev->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); - m_pDev->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE ); - m_pDev->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE); - m_pDev->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_DISABLE ); - m_pDev->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0 ); - - m_pDev->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE ); - m_pDev->SetTextureStageState( 1, D3DTSS_COLORARG2, D3DTA_CURRENT ); - m_pDev->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_MODULATE); - m_pDev->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE ); - m_pDev->SetTextureStageState( 1, D3DTSS_TEXCOORDINDEX, 1 ); - - m_pDev->SetTextureStageState( 2, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE); - m_pDev->SetTextureStageState( 2, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_PASSTHRU|2); - - m_pDev->SetTextureStageState( 3, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE); - m_pDev->SetTextureStageState( 3, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_PASSTHRU|3); - -// m_pDev->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR ); -// m_pDev->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR ); -// m_pDev->SetTextureStageState( 0, D3DTSS_MIPFILTER, D3DTEXF_POINT ); - -// m_pDev->SetTextureStageState( 1, D3DTSS_MINFILTER, D3DTEXF_POINT ); -// m_pDev->SetTextureStageState( 1, D3DTSS_MAGFILTER, D3DTEXF_POINT ); -// m_pDev->SetTextureStageState( 1, D3DTSS_MIPFILTER, D3DTEXF_NONE ); - //end of default setup - - m_pDev->SetTextureStageState(0, D3DTSS_ADDRESSU, D3DTADDRESS_WRAP); - m_pDev->SetTextureStageState(0, D3DTSS_ADDRESSV, D3DTADDRESS_WRAP); - m_pDev->SetRenderState( D3DRS_WRAP0, D3DWRAP_U | D3DWRAP_V); - - m_pDev->SetTextureStageState(1, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP); - m_pDev->SetTextureStageState(1, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP); - - m_pDev->SetTexture( 0, m_pBumpTexture[(Int)m_fBumpFrame]); -#ifdef MIPMAP_BUMP_TEXTURE - m_pDev->SetTextureStageState( 0, D3DTSS_MIPFILTER, D3DTEXF_POINT ); - m_pDev->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR ); - m_pDev->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR ); -#endif - m_pDev->SetTextureStageState( 1, D3DTSS_BUMPENVMAT00, F2DW(m_fBumpScale) ); - m_pDev->SetTextureStageState( 1, D3DTSS_BUMPENVMAT01, F2DW(0.0f) ); - m_pDev->SetTextureStageState( 1, D3DTSS_BUMPENVMAT10, F2DW(0.0f) ); - m_pDev->SetTextureStageState( 1, D3DTSS_BUMPENVMAT11, F2DW(m_fBumpScale) ); - m_pDev->SetTextureStageState( 1, D3DTSS_BUMPENVLSCALE, F2DW(1.0f) ); - m_pDev->SetTextureStageState( 1, D3DTSS_BUMPENVLOFFSET, F2DW(0.0f) ); - - m_pDev->SetTextureStageState( 2, D3DTSS_COLOROP, D3DTOP_DISABLE ); - m_pDev->SetTextureStageState( 2, D3DTSS_ALPHAOP, D3DTOP_DISABLE ); - - m_pDev->SetRenderState(D3DRS_ZWRITEENABLE , FALSE); - - D3DXMATRIX mat; - memset(&mat,0,sizeof(D3DXMATRIX)); - - mat._11 = 0.5f; mat._12 = -0.5f; mat._13 = 0.5f; mat._14=0.5f; - mat._21 = 0.5f; mat._22 = 0.5f; mat._23 = 0.0f; mat._24=0.0f; - mat._31 = 0.0f; mat._32 = 0.0f; mat._33 = 0.0f; mat._34=1.0f; - mat._41 = 0.0f; mat._42 = 0.0f; mat._43 = 0.0f; mat._44=1.0f; - - m_pDev->SetVertexShaderConstant(CV_TEXPROJ_0, &mat, 4); - - // Setup constants - m_pDev->SetVertexShaderConstant(CV_ZERO, D3DXVECTOR4(0.0f, 0.0f, 0.0f, 0.0f), 1); - m_pDev->SetVertexShaderConstant(CV_ONE, D3DXVECTOR4(1.0f, 1.0f, 1.0f, 1.0f), 1); - - m_pDev->SetVertexShader(m_dwWaveVertexShader); - m_pDev->SetPixelShader(m_dwWavePixelShader); - -// Make reflection brighter to compensate for darker coloring on sea floor -// m_pDev->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE ); -// m_pDev->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_SRCCOLOR ); - - m_pDev->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA ); - m_pDev->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA ); - - m_pDev->SetRenderState(D3DRS_ALPHABLENDENABLE , TRUE); - m_pDev->SetTexture( 1, m_pReflectionTexture->Peek_D3D_Texture()); - -// m_pDev->SetRenderState(D3DRS_FILLMODE,D3DFILL_WIREFRAME);//LORENZEN - - Int patchX,patchY,startX,startY; - - D3DXMATRIX patchMatrix; - memset(&patchMatrix,0,sizeof(D3DXMATRIX)); - patchMatrix._11=PATCH_SCALE; - patchMatrix._22=1.0f; - patchMatrix._33=PATCH_SCALE; - patchMatrix._44=1.0f; - - m_pDev->SetStreamSource(0,m_vertexBufferD3D,sizeof(WaterRenderObjClass::SEA_PATCH_VERTEX)); - m_pDev->SetIndices(m_indexBufferD3D,0); - - for (startY=patchY=(seaBox.Center.Y-seaBox.Extent.Y)/(PATCH_WIDTH*PATCH_SCALE); (patchY*PATCH_WIDTH*PATCH_SCALE)<(seaBox.Center.Y+seaBox.Extent.Y); patchY++) - { - for (startX=patchX=(seaBox.Center.X-seaBox.Extent.X)/(PATCH_WIDTH*PATCH_SCALE); (patchX*PATCH_WIDTH*PATCH_SCALE)<(seaBox.Center.X+seaBox.Extent.X); patchX++) - { - D3DXMATRIX matWorldViewProj, matTemp, matTempWorld; - patchMatrix._41=(float)(patchX*PATCH_WIDTH*PATCH_SCALE ); - patchMatrix._43=(float)(patchY*PATCH_WIDTH*PATCH_SCALE ); - //convert the default D3D coordinate system into ours - D3DXMatrixMultiply(&matTempWorld, &patchMatrix, &matWW3D); - - D3DXMatrixMultiply(&matTemp, &matTempWorld, &matView); - D3DXMatrixMultiply(&matWorldViewProj, &matTemp, &matProj); - //matrices must be transposed before loading into vertex shader registers - D3DXMatrixTranspose(&matWorldViewProj, &matWorldViewProj); - m_pDev->SetVertexShaderConstant(CV_WORLDVIEWPROJ_0, &matWorldViewProj, 4); //pass transform matrix into shader - - m_pDev->DrawIndexedPrimitive(D3DPT_TRIANGLESTRIP,0,m_numVertices,0,m_numIndices); - } - } -// m_pDev->SetRenderState(D3DRS_FILLMODE,D3DFILL_SOLID); - m_pDev->SetRenderState(D3DRS_ALPHABLENDENABLE , FALSE); - m_pDev->SetTexture( 0, NULL); //release reference to bump texture - m_pDev->SetTexture( 1, NULL); //release reference to reflection texture - m_pDev->SetTexture( 2, NULL); //release reference to reflection texture - - m_pDev->SetTextureStageState( 0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE); - m_pDev->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_PASSTHRU|0); - m_pDev->SetTextureStageState( 1, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE); - m_pDev->SetTextureStageState( 1, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_PASSTHRU|1); - m_pDev->SetRenderState(D3DRS_ZWRITEENABLE , TRUE); - - m_pDev->SetTextureStageState(1, D3DTSS_ADDRESSU, D3DTADDRESS_WRAP); - m_pDev->SetTextureStageState(1, D3DTSS_ADDRESSV, D3DTADDRESS_WRAP); - - m_pDev->SetRenderState( D3DRS_WRAP0, 0); //turn off texture wrapping - - m_pDev->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_DISABLE ); - m_pDev->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_DISABLE ); - m_pDev->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE ); - m_pDev->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE ); - m_pDev->SetTextureStageState( 2, D3DTSS_COLOROP, D3DTOP_DISABLE ); - m_pDev->SetTextureStageState( 2, D3DTSS_ALPHAOP, D3DTOP_DISABLE ); - - //Restore old transforms - DX8Wrapper::_Set_DX8_Transform(D3DTS_VIEW, *(Matrix4x4*)&matView); - DX8Wrapper::_Set_DX8_Transform(D3DTS_PROJECTION, *(Matrix4x4*)&matProj); - - m_pDev->SetPixelShader(0); //turn off pixel shader - m_pDev->SetVertexShader(DX8_FVF_XYZDUV1); //turn off custom vertex shader - - DX8Wrapper::Invalidate_Cached_Render_States(); - - if (TheTerrainRenderObject->getShroud()) - { - //do second pass to apply the shroud on water plane - W3DShaderManager::setTexture(0,TheTerrainRenderObject->getShroud()->getShroudTexture()); - W3DShaderManager::setShader(W3DShaderManager::ST_SHROUD_TEXTURE, 0); - m_pDev->SetStreamSource(0,m_vertexBufferD3D,sizeof(WaterRenderObjClass::SEA_PATCH_VERTEX)); - m_pDev->SetIndices(m_indexBufferD3D,0); - for (startY=patchY=(seaBox.Center.Y-seaBox.Extent.Y)/(PATCH_WIDTH*PATCH_SCALE); (patchY*PATCH_WIDTH*PATCH_SCALE)<(seaBox.Center.Y+seaBox.Extent.Y); patchY++) - { - for (startX=patchX=(seaBox.Center.X-seaBox.Extent.X)/(PATCH_WIDTH*PATCH_SCALE); (patchX*PATCH_WIDTH*PATCH_SCALE)<(seaBox.Center.X+seaBox.Extent.X); patchX++) - { - D3DXMATRIX matTemp; - patchMatrix._41=(float)(patchX*PATCH_WIDTH*PATCH_SCALE); - patchMatrix._43=(float)(patchY*PATCH_WIDTH*PATCH_SCALE); - - D3DXMatrixMultiply(&matTemp, &patchMatrix, &matWW3D); - - DX8Wrapper::_Set_DX8_Transform(D3DTS_WORLD, *(Matrix4x4*)&matTemp); - - m_pDev->DrawIndexedPrimitive(D3DPT_TRIANGLESTRIP,0,m_numVertices,0,m_numIndices); - } - } - W3DShaderManager::resetShader(W3DShaderManager::ST_SHROUD_TEXTURE); - } - -} - - -#define FEATHER_LAYER_COUNT (5.0f) -#define FEATHER_THICKNESS (4.0f) - -//------------------------------------------------------------------------------------------------- -/** Renders (draws) the water surface.*/ -//------------------------------------------------------------------------------------------------- -void WaterRenderObjClass::renderWater(void) -{ - for (PolygonTrigger *pTrig=PolygonTrigger::getFirstPolygonTrigger(); pTrig; pTrig = pTrig->getNext()) { - if (pTrig->isWaterArea()) { - if (pTrig->getNumPoints()>2) { - if (pTrig->isRiver()) { - drawRiverWater(pTrig); - continue; - } - Int k; - for (k=1; kgetNumPoints()-1; k=k+2) { - ICoord3D pt3 = *pTrig->getPoint(0); - ICoord3D pt2 = *pTrig->getPoint(k); - ICoord3D pt1 = *pTrig->getPoint(k+1); - ICoord3D pt0 = *pTrig->getPoint(k+1); - if (k+2getNumPoints()) { - pt0 = *pTrig->getPoint(k+2); - } - Vector3 points[4]; - points[0].Set(pt0.x, pt0.y, pt0.z); - points[1].Set(pt1.x, pt1.y, pt1.z); - points[2].Set(pt2.x, pt2.y, pt2.z); - points[3].Set(pt3.x, pt3.y, pt3.z); - - if ( TheGlobalData->m_featherWater ) - { - for (int r = 0; r < TheGlobalData->m_featherWater; ++r) - { - drawTrapezoidWater(points); - points[0].Z += (FEATHER_THICKNESS/TheGlobalData->m_featherWater); - } - } - - else - drawTrapezoidWater(points); - - - } - } - } - } - -} - -//------------------------------------------------------------------------------------------------- -/** Renders (draws) the sky plane. Will apply current time-of-day settings including - * some simple UV scrolling animation. */ -//------------------------------------------------------------------------------------------------- -void WaterRenderObjClass::renderSky(void) -{ - Int timeNow,timeDiff; - Real fu,fv; - - Setting *setting=&m_settings[m_tod]; - - timeNow=timeGetTime(); - - timeDiff=timeNow-m_LastUpdateTime; - m_LastUpdateTime=timeNow; - - m_uOffset += timeDiff * setting->uScrollPerMs * setting->skyTexelsPerUnit; - m_vOffset += timeDiff * setting->vScrollPerMs * setting->skyTexelsPerUnit; - - //clamp uv coordinate into 0,1 range - m_uOffset = m_uOffset - (Real)((Int) m_uOffset); - m_vOffset = m_vOffset - (Real)((Int) m_vOffset); - - fu= m_uOffset + (SKYPLANE_SIZE * 2) * setting->skyTexelsPerUnit; - fv= m_vOffset + (SKYPLANE_SIZE * 2) * setting->skyTexelsPerUnit; - - - VertexMaterialClass *vmat=VertexMaterialClass::Get_Preset(VertexMaterialClass::PRELIT_DIFFUSE); - DX8Wrapper::Set_Material(vmat); - REF_PTR_RELEASE(vmat); - - ShaderClass m_shader2=ShaderClass::_PresetOpaqueShader; - m_shader2.Set_Cull_Mode(ShaderClass::CULL_MODE_DISABLE); - m_shader2.Set_Depth_Compare(ShaderClass::PASS_ALWAYS); //no need to check against z-buffer, sky always rendered first. - m_shader2.Set_Depth_Mask(ShaderClass::DEPTH_WRITE_DISABLE); //sky is always behind everything so no need to update z-buffer - - DX8Wrapper::Set_Shader(m_shader2); - - DX8Wrapper::Set_Texture(0,setting->skyTexture); - - //draw an infinite sky plane - DynamicVBAccessClass vb_access(BUFFER_TYPE_DYNAMIC_DX8,dynamic_fvf_type,4); - { - DynamicVBAccessClass::WriteLockClass lock(&vb_access); - VertexFormatXYZNDUV2* verts=lock.Get_Formatted_Vertex_Array(); - if(verts) - { - verts[0].x=-SKYPLANE_SIZE; - verts[0].y=SKYPLANE_SIZE; - verts[0].z=SKYPLANE_HEIGHT; - verts[0].u1=m_uOffset; - verts[0].v1=fv; - verts[0].diffuse=setting->vertex01Diffuse; - - verts[1].x=SKYPLANE_SIZE; - verts[1].y=SKYPLANE_SIZE; - verts[1].z=SKYPLANE_HEIGHT; - verts[1].u1=fu; - verts[1].v1=fv; - verts[1].diffuse=setting->vertex11Diffuse; - - verts[2].x=SKYPLANE_SIZE; - verts[2].y=-SKYPLANE_SIZE; - verts[2].z=SKYPLANE_HEIGHT; - verts[2].u1=fu; - verts[2].v1=m_vOffset; - verts[2].diffuse=setting->vertex10Diffuse; - - verts[3].x=-SKYPLANE_SIZE; - verts[3].y=-SKYPLANE_SIZE; - verts[3].z=SKYPLANE_HEIGHT; - verts[3].u1=m_uOffset; - verts[3].v1=m_vOffset; - verts[3].diffuse=setting->vertex00Diffuse; - } - } - - DX8Wrapper::Set_Index_Buffer(m_indexBuffer,0); - DX8Wrapper::Set_Vertex_Buffer(vb_access); - - Matrix3D tm(1); - tm.Set_Translation(Vector3(0,0,0)); - DX8Wrapper::Set_Transform(D3DTS_WORLD,tm); - - DX8Wrapper::Draw_Triangles( 0,2, 0, 4); //draw a quad, 2 triangles, 4 verts -} - -//------------------------------------------------------------------------------------------------- -/** Renders (draws) the sky body. Used for moon and sun. We rotate the image - * so that it always faces the camera. This removes perspective and helps hide that - * it's a flat image. */ -//------------------------------------------------------------------------------------------------- -/// @todo: Add code to render properly sorted sun sky body. -void WaterRenderObjClass::renderSkyBody(Matrix3D *mat) -{ - Vector3 cPos; - - Vector3 pView,pRight,pUp,pPos(SKYBODY_X,SKYBODY_Y,SKYBODY_HEIGHT); - - mat->Get_Translation(&cPos); - - pView=cPos-pPos; //billboard to camera - pView.Normalize(); //particle view direction - - Vector3 WorldUp(0,0,-1); ///@todo: hacked so only works for reflections across xy plane - -#ifdef ALLOW_TEMPORARIES - Vector3 rotAxis=Vector3::Cross_Product(WorldUp,pView); //get axis of rotation. - rotAxis.Normalize(); -#else - Vector3 rotAxis; - Vector3::Normalized_Cross_Product(WorldUp, pView, &rotAxis); -#endif - - Real angle=Vector3::Dot_Product(WorldUp,pView); - - angle = acos(angle); - - - Matrix3D tm(1); - tm.Set(rotAxis,angle); - tm.Adjust_Translation(Vector3(SKYBODY_X,SKYBODY_Y,SKYBODY_HEIGHT)); - - - DX8Wrapper::Set_Transform(D3DTS_WORLD,tm); - - - VertexMaterialClass *vmat=VertexMaterialClass::Get_Preset(VertexMaterialClass::PRELIT_DIFFUSE); - DX8Wrapper::Set_Material(vmat); - REF_PTR_RELEASE(vmat); - - ShaderClass m_shader2=ShaderClass::_PresetAlphaShader; - m_shader2.Set_Cull_Mode(ShaderClass::CULL_MODE_DISABLE); - m_shader2.Set_Depth_Compare(ShaderClass::PASS_ALWAYS); //no need to check against z-buffer, sky always rendered first. - m_shader2.Set_Depth_Mask(ShaderClass::DEPTH_WRITE_DISABLE); //sky is always behind everything so no need to update z-buffer - - DX8Wrapper::Set_Shader(m_shader2); - - -// DX8Wrapper::Set_Shader(ShaderClass::/*_PresetAdditiveShader*//*_PresetOpaqueShader*/_PresetAlphaShader); -// DX8Wrapper::Set_Texture(0,setting->skyBodyTexture); - - DX8Wrapper::Set_Texture(0,m_alphaClippingTexture); - - //draw an infinite sky plane - DynamicVBAccessClass vb_access(BUFFER_TYPE_DYNAMIC_DX8,dynamic_fvf_type,4); - { - DynamicVBAccessClass::WriteLockClass lock(&vb_access); - VertexFormatXYZNDUV2* verts=lock.Get_Formatted_Vertex_Array(); - if(verts) - { - verts[0].x=-SKYBODY_SIZE; - verts[0].y=SKYBODY_SIZE; - verts[0].z=0; - verts[0].u2=0; - verts[0].v2=1; - verts[0].diffuse=0xffffffff; - - verts[1].x=SKYBODY_SIZE; - verts[1].y=SKYBODY_SIZE; - verts[1].z=0; - verts[1].u2=1; - verts[1].v2=1; - verts[1].diffuse=0xffffffff; - - verts[2].x=SKYBODY_SIZE; - verts[2].y=-SKYBODY_SIZE; - verts[2].z=0; - verts[2].u2=1; - verts[2].v2=0; - verts[2].diffuse=0xffffffff; - - verts[3].x=-SKYBODY_SIZE; - verts[3].y=-SKYBODY_SIZE; - verts[3].z=0; - verts[3].u2=0; - verts[3].v2=0; - verts[3].diffuse=0xffffffff; - } - } - - DX8Wrapper::Set_Index_Buffer(m_indexBuffer,0); - DX8Wrapper::Set_Vertex_Buffer(vb_access); - - DX8Wrapper::Draw_Triangles( 0,2, 0, 4); //draw a quad, 2 triangles, 4 verts -} - -//Defines for procedural water animation. -#define WATER_FREQ (2.0*3.2831/4.0) //2pi (full cycle) cover 4 units -#define WATER_AMP (1.0f) -#define WATER_OFFSET (0.1f) - -//------------------------------------------------------------------------------------------------- -/** Renders (draws) the water surface mesh geometry. - * This is a work-in-progress! Do not use this code! */ -//------------------------------------------------------------------------------------------------- -void WaterRenderObjClass::renderWaterMesh(void) -{ - - if (!m_doWaterGrid) - return; //the water grid is disabled. - - //According to Nvidia there's a D3D bug that happens if you don't start with a - //new dynamic VB each frame - so we force a DISCARD by overflowing the counter. - m_vertexBufferD3DOffset = 0xffff; - - Setting *setting=&m_settings[m_tod]; - - WaterMeshData *pData; - Int mx=m_gridCellsX+1; - Int my=m_gridCellsY+1; - Int i,j; - - Real cellSizeX=m_gridCellSize; - Real cellSizeY=m_gridCellSize; -// Real uScale2=5.0f*setting->waterRepeatCount/(128.0f)*cellSizeX/10.0f; -// Real vScale2=5.0f*setting->waterRepeatCount/(128.0f)*cellSizeY/10.0f; - - //Old waterRepeatCount settings in INI were based on 128x128 water grid of cellsize=10 - //Scale values to correct size. - Real uScale=setting->waterRepeatCount/(128.0f)*cellSizeX/10.0f*0.2f; - Real vScale=setting->waterRepeatCount/(128.0f)*cellSizeY/10.0f*0.2f; - - Vector3 nx(cellSizeX*2.0f,0,0); - Vector3 ny(0,cellSizeY*2.0f,0); - Vector3 C; - -#ifdef DO_WATER_SIMULATION //Debug code used to create a dummy water animation - // - // Mark: If you re-enable this water simulation, you might want to consider moving - // this code to the update() method of the water render object (Colin) - // - - static Real PhasePerFrameX=0.1f; - static Real PhasePerFrameY=0.1f; - - //update the mesh heights for this frame (update buffer is 2 samples wider/taller due to border) - for (j=0,pData=m_meshData; j<(my+2); j++) - { - for (i=0; i<(mx+2); i++) - { - //*pData = WATER_AMP * sin(WATER_FREQ*(0.7f*i + 0.7f*j) - PhasePerFrame); - - pData->height=WATER_OFFSET+WATER_AMP*(sin((float)i*WATER_FREQ*0.4+PhasePerFrameX*0.5)+sin((float)i*WATER_FREQ*0.6+PhasePerFrameX*0.2)+sin((float)j*WATER_FREQ+PhasePerFrameX)+sin((float)j*WATER_FREQ*0.7+PhasePerFrameX*0.3)); -// *pData=WATER_OFFSET+WATER_AMP*(sin((float)i*WATER_FREQ*0.4+PhasePerFrameX*0.5)+sin((float)i*WATER_FREQ*0.6+PhasePerFrameX*0.2)+sin((float)j*WATER_FREQ+PhasePerFrameX)+sin((float)j*WATER_FREQ*0.7+PhasePerFrameX*0.3)); - pData++; - } - } - - PhasePerFrameX -= 0.08f; - PhasePerFrameY -= 0.1f; -#endif - - MaterMeshVertexFormat *vb; - if (m_vertexBufferD3DOffset < m_numVertices) - { //we have room in current VB, append new verts - if(m_vertexBufferD3D->Lock(m_vertexBufferD3DOffset*sizeof(MaterMeshVertexFormat),mx*my*sizeof(MaterMeshVertexFormat),(unsigned char**)&vb,D3DLOCK_NOOVERWRITE) != D3D_OK) - return; - } - else - { //ran out of room in last VB, request a substitute VB. - if(m_vertexBufferD3D->Lock(0,mx*my*sizeof(MaterMeshVertexFormat),(unsigned char**)&vb,D3DLOCK_DISCARD) != D3D_OK) - return; - m_vertexBufferD3DOffset=0; //reset start of page to first vertex - } - Int diffuse; - diffuse = setting->waterDiffuse&0x00ffffff; - Int alpha = (setting->waterDiffuse & 0xff000000)>>24; - // Reduce alpha for wave mesh - alpha -= 0x20; - diffuse |= alpha<<24; - - //I pulled some of these constants out of the loops for speed: - Real uvCosScale=0.02*cos(3*m_riverVOrigin); - Real sinOffset=25*m_riverVOrigin; - Real originScale=m_riverVOrigin/vScale; - Real bumpSizeDiv=cellSizeY/BUMP_SIZE; - Real bumpSizeDiv2=0.3f*cellSizeY/BUMP_SIZE; - - //Data has a 1 vertex padding all around it so we don't need to special-case edges. Improves performance - for (j=0,pData=m_meshData+mx+2+1; jheight - (pData-1)->height; - ny.Z=(pData+mx+2)->height - (pData-mx-2)->height; -// nx.Z=*(pData+1)-*(pData-1); -// ny.Z=*(pData+mx+2)-*(pData-mx-2); - Vector3::Cross_Product(nx,ny,&C); - C.Normalize(); - vb->nx = C.X; - vb->ny = C.X; - vb->nz = C.X; -#endif - Real x = (float)i*cellSizeX; - vb->x= x; - vb->y= y; - vb->z= pData->height;//WATER_OFFSET+WATER_AMP*(sin((float)i*WATER_FREQ+PhasePerFrame)+cos((float)j*WATER_FREQ+PhasePerFrame)); - - vb->diffuse = diffuse; -#ifdef SCROLL_UV -// vb->diffuse=0x80ffffff; - vb->u1=(float)i*uScale; - vb->v1=v1Offset; - - //old slow version - //vb->v1=m_riverVOrigin+(float)j*vScale + 0.02*cos(3*m_riverVOrigin)*sin(25*m_riverVOrigin+y*PI/(8*MAP_XY_FACTOR)); - -// vb->u2=m_initialGridU2+(float)i*uScale2; -// vb->v2=m_initialGridV2+(float)j*vScale2; -#else - vb->u1=(float)i*uScale; - vb->v1=(float)j*vScale; -#endif - vb->u2=(float)(i)*cellSizeX/BUMP_SIZE; - vb->v2=v2Offset; - //old slow code - //vb->v2=(float)(j+m_riverVOrigin/vScale )*cellSizeY/BUMP_SIZE+ 0.3f*(float)j*cellSizeY/BUMP_SIZE; - vb++; - pData++; - } - } - - m_vertexBufferD3D->Unlock(); - - Matrix3D tm(Transform); - - DX8Wrapper::Set_Transform(D3DTS_WORLD,tm); //position the water surface - DX8Wrapper::Set_Material(m_meshVertexMaterialClass); - - ShaderClass::CullModeType oldCullMode=m_shaderClass.Get_Cull_Mode(); - - ShaderClass::DepthMaskType oldDepthMask=m_shaderClass.Get_Depth_Mask(); - m_shaderClass.Set_Depth_Mask(ShaderClass::DEPTH_WRITE_DISABLE); //disable writing to z-buffer to prevent particle clipping. - - m_shaderClass.Set_Cull_Mode(ShaderClass::CULL_MODE_ENABLE); //water should be visible from both sides - - DX8Wrapper::Set_Shader(m_shaderClass); -#if 1 - setupFlatWaterShader(); -#else - //DX8Wrapper::Set_Shader(ShaderClass::_PresetOpaqueShader); - DX8Wrapper::Set_Texture(0,setting->waterTexture); - DX8Wrapper::Set_Texture(1,setting->waterTexture); - - DX8Wrapper::Set_Light(0,*m_meshLight); - DX8Wrapper::Set_Light(1,NULL); - DX8Wrapper::Set_Light(2,NULL); - DX8Wrapper::Set_Light(3,NULL); -/* - DX8Wrapper::Set_DX8_Render_State(D3DRS_AMBIENT,0); //turn off scene ambient - DX8Wrapper::Set_DX8_Render_State(D3DRS_SPECULARENABLE,TRUE); - DX8Wrapper::Set_DX8_Render_State(D3DRS_LOCALVIEWER,TRUE); -*/ - - DX8Wrapper::Apply_Render_State_Changes(); //force update of view and projection matrices -#endif - - -// m_pDev->SetRenderState(D3DRS_ZFUNC,D3DCMP_ALWAYS); //used to display grid under map. - - m_pDev->SetIndices(m_indexBufferD3D,m_vertexBufferD3DOffset); - m_pDev->SetStreamSource(0,m_vertexBufferD3D,sizeof(MaterMeshVertexFormat)); - m_pDev->SetVertexShader(WATER_MESH_FVF); - - - if (TheTerrainRenderObject->getShroud() && !m_trapezoidWaterPixelShader) - { //we have a shroud to apply and can't do it inside the pixel shader. - //so do it in stage1 - W3DShaderManager::setTexture(0,TheTerrainRenderObject->getShroud()->getShroudTexture()); - W3DShaderManager::setShader(W3DShaderManager::ST_SHROUD_TEXTURE, 1); - - //modulate with shroud texture - DX8Wrapper::Set_DX8_Texture_Stage_State( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE ); //stage 1 texture - DX8Wrapper::Set_DX8_Texture_Stage_State( 1, D3DTSS_COLORARG2, D3DTA_CURRENT ); //previous stage texture - DX8Wrapper::Set_DX8_Texture_Stage_State( 1, D3DTSS_COLOROP, D3DTOP_MODULATE ); - DX8Wrapper::Set_DX8_Texture_Stage_State( 1, D3DTSS_ALPHAOP, D3DTOP_MODULATE ); - - //Shroud shader uses z-compare of EQUAL which wouldn't work on water because it doesn't - //write to the zbuffer. Change to LESSEQUAL. - DX8Wrapper::_Get_D3D_Device8()->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL); - m_pDev->DrawIndexedPrimitive(D3DPT_TRIANGLESTRIP,0,mx*my,0,m_numIndices-2); - DX8Wrapper::_Get_D3D_Device8()->SetRenderState(D3DRS_ZFUNC, D3DCMP_EQUAL); - W3DShaderManager::resetShader(W3DShaderManager::ST_SHROUD_TEXTURE); - } - else - m_pDev->DrawIndexedPrimitive(D3DPT_TRIANGLESTRIP,0,mx*my,0,m_numIndices-2); - - Debug_Statistics::Record_DX8_Polys_And_Vertices(m_numIndices-2,mx*my,ShaderClass::_PresetOpaqueShader); - -// m_pDev->SetRenderState(D3DRS_FILLMODE,D3DFILL_SOLID); - - if (m_trapezoidWaterPixelShader) DX8Wrapper::_Get_D3D_Device8()->SetPixelShader(NULL); - - m_vertexBufferD3DOffset += mx*my; //advance past vertices already in buffer - - DX8Wrapper::Set_Texture(0,NULL); - DX8Wrapper::Set_Texture(1,NULL); - ShaderClass::Invalidate(); - m_shaderClass.Set_Cull_Mode(oldCullMode); //water should be visible from both sides - - // restore shader to old mask - m_shaderClass.Set_Depth_Mask(oldDepthMask); - - //W3DShaderManager::resetShader(W3DShaderManager::ST_SHROUD_TEXTURE); - -} - -inline void WaterRenderObjClass::setGridVertexHeight(Int x, Int y, Real value) -{ - DEBUG_ASSERTCRASH( x < (m_gridCellsX+1) && y < (m_gridCellsY+1), ("Invalid Water Mesh Coordinates") ); - - if (m_meshData) - { - m_meshData[(y+1)*(m_gridCellsX+1+2)+x+1].height = value; - } -} - -void WaterRenderObjClass::setGridHeightClamps(Real minz, Real maxz) -{ - m_minGridHeight = minz; - m_maxGridHeight = maxz; -} - -void WaterRenderObjClass::addVelocity( Real worldX, Real worldY, - Real zVelocity, Real preferredHeight ) -{ - - if( m_doWaterGrid) - { - Real gx,gy; - Real minX,maxX,minY,maxY; - Int x,y; - WaterMeshData *meshPoint; - m_disableRiver = true; - - //check if center falls within grid bounds - if (worldToGridSpace(worldX, worldY, gx, gy)) - { - - //find extents of influence - minX = floorf(gx - m_gridChangeMaxRange); - if (minX < 0 ) - minX = 0; //clamp extent to fall within box - maxX = ceilf(gx + m_gridChangeMaxRange); - if (maxX > m_gridCellsX) - maxX = m_gridCellsX; //clamp extent to fall within box - - minY = floorf(gy - m_gridChangeMaxRange); - if (minY < 0 ) - minY = 0; //clamp extent to fall within box - maxY = ceilf(gy + m_gridChangeMaxRange); - if (maxY > m_gridCellsY) - maxY = m_gridCellsY; //clamp extent to fall within box - - for (y=minY; y<=maxY; y++) - { - for (x=minX; x<=maxX; x++) - { - - // get the mesh point that we're concerned with - meshPoint = &m_meshData[ (y + 1) * (m_gridCellsX + 1 + 2) + x + 1 ]; - - // we now have a new preferred height - meshPoint->preferredHeight = preferredHeight; - - // - // set the velocity of this point based on the distance from the center of the - // "core" point for this call - // - meshPoint->velocity = meshPoint->velocity + zVelocity; - - // this point is now "in motion" - BitSet( meshPoint->status, WaterRenderObjClass::IN_MOTION ); - - } - } - - // - // the mesh data is now dirty, we need to pass through the velocity field - // during an update phase to update the positions - // - m_meshInMotion = TRUE; - - } - - } - -} - -void WaterRenderObjClass::changeGridHeight(Real wx, Real wy, Real delta) -{ - Real gx,gy; - Real *oldData; - Real newData; - Real distance; - Real minX,maxX,minY,maxY; - Int x,y; - - //check if center falls within grid bounds - if (worldToGridSpace(wx, wy, gx, gy)) - { //find extents of influence - minX = floorf(gx - m_gridChangeMaxRange); - if (minX < 0 ) - minX = 0; //clamp extent to fall within box - maxX = ceilf(gx + m_gridChangeMaxRange); - if (maxX > m_gridCellsX) - maxX = m_gridCellsX; //clamp extent to fall within box - - minY = floorf(gy - m_gridChangeMaxRange); - if (minY < 0 ) - minY = 0; //clamp extent to fall within box - maxY = ceilf(gy + m_gridChangeMaxRange); - if (maxY > m_gridCellsY) - maxY = m_gridCellsY; //clamp extent to fall within box - - for (y=minY; y<=maxY; y++) - { - for (x=minX; x<=maxX; x++) - { oldData = &m_meshData[(y+1)*(m_gridCellsX+1+2)+x+1].height; - distance = (gx - (Real)x)*(gx - (Real)x) + (gy - (Real)y)*(gy - (Real)y); - distance = sqrt(distance); - newData = *oldData + 1.0f/(m_gridChangeAtt0+m_gridChangeAtt1*distance+distance*distance*m_gridChangeAtt2)*delta; - //Clamp to min/max values - if (newData < m_minGridHeight) - newData = m_minGridHeight; - if (newData > m_maxGridHeight) - newData = m_maxGridHeight; - *oldData = newData; - } - } - } -} - -void WaterRenderObjClass::setGridChangeAttenuationFactors(Real a, Real b, Real c, Real range) -{ - m_gridChangeAtt0 = a; - m_gridChangeAtt1 = b; - m_gridChangeAtt2 = c; - m_gridChangeMaxRange = range/m_gridCellSize; //convert range to grid space -} - -void WaterRenderObjClass::setGridTransform(Real angle, Real x, Real y, Real z) -{ - m_gridDirectionX = Vector2(1.0f,0.0f); - - m_gridOrigin.X = x; - m_gridOrigin.Y = y; - - Matrix3D xform(1); - xform.Rotate_Z(angle); - - m_gridDirectionX.X = xform.Get_X_Vector().X; - m_gridDirectionX.Y = xform.Get_X_Vector().Y; - - m_gridDirectionY.X = xform.Get_Y_Vector().X; - m_gridDirectionY.Y = xform.Get_Y_Vector().Y; - - xform.Set_Translation(Vector3(x,y,z)); - Set_Transform(xform); -} - -void WaterRenderObjClass::setGridTransform(const Matrix3D *transform ) -{ - - if( transform ) - Set_Transform( *transform ); - -} - -void WaterRenderObjClass::getGridTransform(Matrix3D *transform ) -{ - - if( transform ) - *transform = Get_Transform(); - -} - -void WaterRenderObjClass::setGridResolution(Real gridCellsX, Real gridCellsY, Real cellSize) -{ - m_gridCellSize=cellSize; - - if (m_gridCellsX != gridCellsX || m_gridCellsY != gridCellsY) - { //resolution has changed - m_gridCellsX=gridCellsX; - m_gridCellsY=gridCellsY; - - if (m_meshData) - { - - delete [] m_meshData;//free previously allocated grid and allocate new size - m_meshData = NULL; // must set to NULL so that we properly re-allocate - m_meshDataSize = 0; - - Bool enable = m_doWaterGrid; - enableWaterGrid(true); // allocates buffers. - m_doWaterGrid = enable; - - } - } -} - -void WaterRenderObjClass::getGridResolution( Real *gridCellsX, Real *gridCellsY, Real *cellSize ) -{ - - if( gridCellsX ) - *gridCellsX = m_gridCellsX; - if( gridCellsY ) - *gridCellsY = m_gridCellsY; - if( cellSize ) - *cellSize = m_gridCellSize; - -} - -static Real wobble(Real baseV, Real offset, Bool wobble) -{ - if (!wobble) return 0; - offset = sin(2*PI*baseV - 3*offset); - return offset/22; -} - -/**Utility function used to query water heights in a manner that works in both RTS and WB.*/ -Real WaterRenderObjClass::getWaterHeight(Real x, Real y) -{ - const WaterHandle *waterHandle = NULL; - Real waterZ = 0.0f; - ICoord3D iLoc; - - iLoc.x = REAL_TO_INT_FLOOR( x + 0.5f ); - iLoc.y = REAL_TO_INT_FLOOR( y + 0.5f ); - iLoc.z = 0; - - for( PolygonTrigger *pTrig = PolygonTrigger::getFirstPolygonTrigger(); pTrig; pTrig = pTrig->getNext() ) - { - - if( !pTrig->isWaterArea() ) - continue; - - // See if point is in a water area - if( pTrig->pointInTrigger( iLoc ) ) - { - - if( pTrig->getPoint( 0 )->z >= waterZ ) - { - - waterZ = pTrig->getPoint( 0 )->z; - waterHandle = pTrig->getWaterHandle(); - - } - - } - - } - - if (waterHandle) - return waterHandle->m_polygon->getPoint( 0 )->z; - return INVALID_WATER_HEIGHT; //point not underwater -} - -//------------------------------------------------------------------------------------------------- -//Draw a many sided river polygon. -//------------------------------------------------------------------------------------------------- -void WaterRenderObjClass::drawRiverWater(PolygonTrigger *pTrig) -{ - DX8Wrapper::Invalidate_Cached_Render_States(); ///@todo: Figure out why rivers don't draw without reset of all states. - - Int rectangleCount = pTrig->getNumPoints()/2; - rectangleCount--; - - Real bumpFactor = 5; - static Bool doWobble = true; - - if (m_disableRiver) return; - m_drawingRiver = true; - - //allocate 2 triangles per side with 3 indices per triangle - DynamicIBAccessClass ib_access(BUFFER_TYPE_DYNAMIC_DX8,(rectangleCount+1)*2*3); - { - DynamicIBAccessClass::WriteLockClass lockib(&ib_access); - UnsignedShort *curIb = lockib.Get_Index_Array(); - for (Int i=0; im_standingWaterColor.red; - Real shadeG=TheWaterTransparency->m_standingWaterColor.green; - Real shadeB=TheWaterTransparency->m_standingWaterColor.blue; - - //If the water color is not overridden, use legacy lighting code. - if ( shadeR==1.0f && shadeG==1.0f && shadeB==1.0f) - { - shadeR = TheGlobalData->m_terrainAmbient[0].red; - shadeG = TheGlobalData->m_terrainAmbient[0].green; - shadeB = TheGlobalData->m_terrainAmbient[0].blue; - - //Add in diffuse lighting from each terrain light - for (Int lightIndex=0; lightIndex < TheGlobalData->m_numGlobalLights; lightIndex++) - { - if (-TheGlobalData->m_terrainLightPos[lightIndex].z > 0) - { shadeR += -TheGlobalData->m_terrainLightPos[lightIndex].z * TheGlobalData->m_terrainDiffuse[lightIndex].red; - shadeG += -TheGlobalData->m_terrainLightPos[lightIndex].z * TheGlobalData->m_terrainDiffuse[lightIndex].green; - shadeB += -TheGlobalData->m_terrainLightPos[lightIndex].z * TheGlobalData->m_terrainDiffuse[lightIndex].blue; - } - } - - //Get water material colors - Real waterShadeR = (m_settings[m_tod].waterDiffuse & 0xff) / 255.0f; - Real waterShadeG = ((m_settings[m_tod].waterDiffuse >> 8) & 0xff) / 255.0f; - Real waterShadeB = ((m_settings[m_tod].waterDiffuse >> 16) & 0xff) / 255.0f; - - shadeR=shadeR*waterShadeR*255.0f; - shadeG=shadeG*waterShadeG*255.0f; - shadeB=shadeB*waterShadeB*255.0f; - } - else - { - shadeR=shadeR*255.0f; - shadeG=shadeG*255.0f; - shadeB=shadeB*255.0f; - - if (shadeR == 0 && shadeG == 0 && shadeB == 0) - { //special case where we disable lighting - shadeR=255; - shadeG=255; - shadeB=255; - } - } - - Int diffuse=REAL_TO_INT(shadeB) | (REAL_TO_INT(shadeG) << 8) | (REAL_TO_INT(shadeR) << 16); - - //Keep diffuse from lighting calculations but substitute custom alpha - diffuse |= m_settings[m_tod].waterDiffuse & 0xff000000; //copy alpha/opacity from ini setting - - Int innerNdx = pTrig->getRiverStart(); - Int outerNdx = innerNdx+1; - - Real endLen=0; - Real totalLen=0; - Int i; - for (i=0; igetNumPoints()-1; i++) { - ICoord3D innerPt = *pTrig->getPoint(i); - ICoord3D outerPt = *pTrig->getPoint(i+1); - Real dx = innerPt.x-outerPt.x; - Real dy = innerPt.y-outerPt.y; - Real curLen = sqrt(dx*dx+dy*dy); - totalLen += curLen; - if ( i==innerNdx) { - endLen = curLen; - } - } - bumpFactor = endLen/BUMP_SIZE; - - Real lengthOfRiver = (totalLen/2)-endLen; - Real repeatCount = lengthOfRiver / (endLen); - - Real vScale=(Real)repeatCount/(Real)rectangleCount; - -#define HEIGHT_TO_USE (0.5f) - if (innerNdx >= pTrig->getNumPoints()-1) return; - //allocate 2 vertices per side - DynamicVBAccessClass vb_access(BUFFER_TYPE_DYNAMIC_DX8,dynamic_fvf_type,(rectangleCount+1)*2); - { - DynamicVBAccessClass::WriteLockClass lock(&vb_access); - VertexFormatXYZNDUV2* vb=lock.Get_Formatted_Vertex_Array(); - - Real constA=3*m_riverVOrigin; - - for (i=0; i<(pTrig->getNumPoints()/2); i++) - { - Real x,y; - ICoord3D innerPt = *pTrig->getPoint(outerNdx); - ICoord3D outerPt = *pTrig->getPoint(innerNdx); - outerNdx++; - innerNdx--; - if (innerNdx<0) { - innerNdx = pTrig->getNumPoints()-1; - } - if (outerNdx >= pTrig->getNumPoints()) { - outerNdx = 0; - } - x=innerPt.x; - y=innerPt.y; - - vb->x=x; - vb->y=y; - - vb->z=innerPt.z; - vb->diffuse= diffuse; - - Real wobbleConst=-m_riverVOrigin+vScale*(Real)i + WWMath::Fast_Sin(2*PI*(vScale*(Real)i) - constA)/22.0f; - //old slower version - //vb->v1=-m_riverVOrigin+vScale*(Real)i + wobble(vScale*i, m_riverVOrigin, doWobble); - vb->v1=wobbleConst; - vb->u1=HEIGHT_TO_USE ; - //old slower version - //vb->v2 = -m_riverVOrigin+vScale*(Real)i + wobble(vScale*i, m_riverVOrigin, doWobble); - vb->v2=wobbleConst; - vb->u2 = 1.0f; - vb->nx = 0; - vb->ny = 0; - vb->nz = 1.0f; - vb++; - - x=outerPt.x; - y=outerPt.y; - - vb->x=x; - vb->y=y; - vb->z=outerPt.z; - vb->diffuse= diffuse; - //old slower version - //vb->v1=-m_riverVOrigin+vScale*(Real)i + wobble(vScale*i, m_riverVOrigin, doWobble); - vb->v1=wobbleConst; - vb->u1=0; - //old slower version - //vb->v2 = -m_riverVOrigin+vScale*(Real)i + wobble(vScale*i, m_riverVOrigin, doWobble); - vb->v2 =wobbleConst; - vb->u2 = 0; - vb->nx = 0; - vb->ny = 0; - vb->nz = 1.0f; - vb++; - - } - } - - Matrix3D tm(1); - - DX8Wrapper::Set_Transform(D3DTS_WORLD,tm); //position the water surface - DX8Wrapper::Set_Index_Buffer(ib_access,0); - DX8Wrapper::Set_Vertex_Buffer(vb_access); - DX8Wrapper::Set_Texture(0,m_riverTexture); //set to blue - - setupJbaWaterShader(); - - //In additive blending we need to use the alpha at the edges of river to darken - //rgb instead. - if (TheWaterTransparency->m_additiveBlend) - DX8Wrapper::Set_DX8_Render_State(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA ); - - if (m_riverWaterPixelShader) DX8Wrapper::_Get_D3D_Device8()->SetPixelShader(m_riverWaterPixelShader); - DWORD cull; - DX8Wrapper::_Get_D3D_Device8()->GetRenderState(D3DRS_CULLMODE, &cull); - DX8Wrapper::_Get_D3D_Device8()->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); - - - - if (wireframeForDebug) { - DX8Wrapper::_Get_D3D_Device8()->SetRenderState(D3DRS_FILLMODE,D3DFILL_WIREFRAME); - } - DX8Wrapper::Draw_Triangles( 0,rectangleCount*2, 0, (rectangleCount+1)*2); - if (wireframeForDebug) { - DX8Wrapper::_Get_D3D_Device8()->SetRenderState(D3DRS_FILLMODE,D3DFILL_SOLID); - } - - if (m_riverWaterPixelShader) DX8Wrapper::_Get_D3D_Device8()->SetPixelShader(NULL); - - //restore blend mode to what W3D expects. - if (TheWaterTransparency->m_additiveBlend) - DX8Wrapper::Set_DX8_Render_State(D3DRS_SRCBLEND, D3DBLEND_ONE ); - - //do second pass to apply the shroud on water plane - if (TheTerrainRenderObject->getShroud()) - { - W3DShaderManager::setTexture(0,TheTerrainRenderObject->getShroud()->getShroudTexture()); - W3DShaderManager::setShader(W3DShaderManager::ST_SHROUD_TEXTURE, 0); - DX8Wrapper::_Get_D3D_Device8()->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); - //Shroud shader uses z-compare of EQUAL which wouldn't work on water because it doesn't - //write to the zbuffer. Change to LESSEQUAL. - DX8Wrapper::_Get_D3D_Device8()->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL); - DX8Wrapper::Draw_Triangles( 0,rectangleCount*2, 0, (rectangleCount+1)*2); - DX8Wrapper::_Get_D3D_Device8()->SetRenderState(D3DRS_ZFUNC, D3DCMP_EQUAL); - W3DShaderManager::resetShader(W3DShaderManager::ST_SHROUD_TEXTURE); - } - DX8Wrapper::_Get_D3D_Device8()->SetRenderState(D3DRS_CULLMODE, cull); - - -} - -void WaterRenderObjClass::setupFlatWaterShader(void) -{ - - DX8Wrapper::Set_Texture(0,m_riverTexture); - if (!TheWaterTransparency->m_additiveBlend) - DX8Wrapper::Set_Shader(ShaderClass::_PresetAlphaShader); - else - DX8Wrapper::Set_Shader(ShaderClass::_PresetAdditiveShader); - - VertexMaterialClass *vmat=VertexMaterialClass::Get_Preset(VertexMaterialClass::PRELIT_DIFFUSE); - DX8Wrapper::Set_Material(vmat); - REF_PTR_RELEASE(vmat); - m_riverTexture->Get_Filter().Set_Mag_Filter(TextureFilterClass::FILTER_TYPE_BEST); - m_riverTexture->Get_Filter().Set_Min_Filter(TextureFilterClass::FILTER_TYPE_BEST); - m_riverTexture->Get_Filter().Set_Mip_Mapping(TextureFilterClass::FILTER_TYPE_BEST); - - DX8Wrapper::Apply_Render_State_Changes(); //force update of view and projection matrices - - //Setup shroud to render in same pass as water - if (m_trapezoidWaterPixelShader) - { if (TheTerrainRenderObject->getShroud()) - { - W3DShaderManager::setTexture(0,TheTerrainRenderObject->getShroud()->getShroudTexture()); - //Use stage 3 to apply the shroud - W3DShaderManager::setShader(W3DShaderManager::ST_SHROUD_TEXTURE, 3); - //Shroud shader uses z-compare of EQUAL which wouldn't work on water because it doesn't - //write to the zbuffer. Change to LESSEQUAL. - DX8Wrapper::_Get_D3D_Device8()->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL); - } - else - { //Assume no shroud, so stage 3 will be "NULL" texture but using actual white because - //pixel shader on GF4 generates random colors with SetTexture(3,NULL). - if (!m_whiteTexture->Is_Initialized()) - { m_whiteTexture->Init(); - SurfaceClass *surface=m_whiteTexture->Get_Surface_Level(); - surface->DrawPixel(0,0,0xffffffff); - REF_PTR_RELEASE(surface); - } - DX8Wrapper::_Get_D3D_Device8()->SetTexture(3,m_whiteTexture->Peek_D3D_Texture()); - } - } - - DX8Wrapper::Set_DX8_Texture_Stage_State( 0, D3DTSS_ALPHAOP, D3DTOP_ADD ); - DX8Wrapper::Set_DX8_Texture_Stage_State(0, D3DTSS_TEXCOORDINDEX, 0); - DX8Wrapper::Set_DX8_Texture_Stage_State(1, D3DTSS_TEXCOORDINDEX, 0); - - Bool doSparkles = true; - - if (m_trapezoidWaterPixelShader && doSparkles) { - - if (!m_waterSparklesTexture->Is_Initialized()) - m_waterSparklesTexture->Init(); - - DX8Wrapper::_Get_D3D_Device8()->SetTexture(1,m_waterSparklesTexture->Peek_D3D_Texture()); - - if (!m_waterNoiseTexture->Is_Initialized()) - m_waterNoiseTexture->Init(); - - DX8Wrapper::_Get_D3D_Device8()->SetTexture(2,m_waterNoiseTexture->Peek_D3D_Texture()); - - DX8Wrapper::Set_DX8_Texture_Stage_State(1, D3DTSS_ADDRESSU, D3DTADDRESS_WRAP); - DX8Wrapper::Set_DX8_Texture_Stage_State(1, D3DTSS_ADDRESSV, D3DTADDRESS_WRAP); - - DX8Wrapper::Set_DX8_Texture_Stage_State(2, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEPOSITION); - // Two output coordinates are used. - DX8Wrapper::Set_DX8_Texture_Stage_State(2, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2); - DX8Wrapper::Set_DX8_Texture_Stage_State(2, D3DTSS_ADDRESSU, D3DTADDRESS_WRAP); - DX8Wrapper::Set_DX8_Texture_Stage_State(2, D3DTSS_ADDRESSV, D3DTADDRESS_WRAP); - D3DXMATRIX inv; - float det; - - Matrix4x4 curView; - DX8Wrapper::_Get_DX8_Transform(D3DTS_VIEW, curView); - D3DXMatrixInverse(&inv, &det, (D3DXMATRIX*)&curView); - D3DXMATRIX scale; - - D3DXMatrixScaling(&scale, NOISE_REPEAT_FACTOR, NOISE_REPEAT_FACTOR,1); - D3DXMATRIX destMatrix = inv * scale; - D3DXMatrixTranslation(&scale, m_riverVOrigin, m_riverVOrigin,0); - destMatrix = destMatrix*scale; - DX8Wrapper::_Set_DX8_Transform(D3DTS_TEXTURE2, *(Matrix4x4*)&destMatrix); - - } - m_pDev->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR ); - m_pDev->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR ); - m_pDev->SetTextureStageState( 1, D3DTSS_MINFILTER, D3DTEXF_LINEAR ); - m_pDev->SetTextureStageState( 1, D3DTSS_MAGFILTER, D3DTEXF_LINEAR ); - m_pDev->SetTextureStageState( 2, D3DTSS_MINFILTER, D3DTEXF_LINEAR ); - m_pDev->SetTextureStageState( 2, D3DTSS_MAGFILTER, D3DTEXF_LINEAR ); - if (m_trapezoidWaterPixelShader){ - DX8Wrapper::_Get_D3D_Device8()->SetPixelShaderConstant(0, D3DXVECTOR4(REFLECTION_FACTOR, REFLECTION_FACTOR, REFLECTION_FACTOR, 1.0f), 1); - DX8Wrapper::_Get_D3D_Device8()->SetPixelShader(m_trapezoidWaterPixelShader); - } -} - -//------------------------------------------------------------------------------------------------- -//Draw a 4 sided flat water area. -//------------------------------------------------------------------------------------------------- -void WaterRenderObjClass::drawTrapezoidWater(Vector3 points[4]) -{ - Vector3 origin(points[0]); - Vector3 uVec1(points[1]); - Vector3 vVec1(points[3]); - Vector3 uVec2(points[2]); - Vector3 vVec2(points[2]); - uVec2 -= vVec1; - vVec2 -= uVec1; - uVec1 -= origin; - vVec1 -= origin; - Int uCount = (uVec1.Length()+uVec2.Length()) / (8*MAP_XY_FACTOR); - if (uCount<1) uCount = 1; - Int vCount = (vVec1.Length()+vVec2.Length()) / (8*MAP_XY_FACTOR); - if (vCount<1) vCount = 1; - - if (uCount>50) uCount = 50; - if (vCount>50) vCount = 50; - - static Bool doWobble = true; - - Int rectangleCount = uCount*vCount; - - uCount++; - vCount++; - - Int i, j; - //allocate 2 triangles per side with 3 indices per triangle - DynamicIBAccessClass ib_access(BUFFER_TYPE_DYNAMIC_DX8,(rectangleCount+1)*2*3); - { - DynamicIBAccessClass::WriteLockClass lockib(&ib_access); - UnsignedShort *curIb = lockib.Get_Index_Array(); - for (j=0; jm_standingWaterColor.red; - Real shadeG=TheWaterTransparency->m_standingWaterColor.green; - Real shadeB=TheWaterTransparency->m_standingWaterColor.blue; - - //If the water color is not overridden, use legacy lighting code. - if ( shadeR==1.0f && shadeG==1.0f && shadeB==1.0f) - { - shadeR = TheGlobalData->m_terrainAmbient[0].red; - shadeG = TheGlobalData->m_terrainAmbient[0].green; - shadeB = TheGlobalData->m_terrainAmbient[0].blue; - - //Add in diffuse lighting from each terrain light - for (Int lightIndex=0; lightIndex < TheGlobalData->m_numGlobalLights; lightIndex++) - { - if (-TheGlobalData->m_terrainLightPos[lightIndex].z > 0) - { shadeR += -TheGlobalData->m_terrainLightPos[lightIndex].z * TheGlobalData->m_terrainDiffuse[lightIndex].red; - shadeG += -TheGlobalData->m_terrainLightPos[lightIndex].z * TheGlobalData->m_terrainDiffuse[lightIndex].green; - shadeB += -TheGlobalData->m_terrainLightPos[lightIndex].z * TheGlobalData->m_terrainDiffuse[lightIndex].blue; - } - } - - //Get water material colors - Real waterShadeR = (m_settings[m_tod].waterDiffuse & 0xff) / 255.0f; - Real waterShadeG = ((m_settings[m_tod].waterDiffuse >> 8) & 0xff) / 255.0f; - Real waterShadeB = ((m_settings[m_tod].waterDiffuse >> 16) & 0xff) / 255.0f; - - shadeR=shadeR*waterShadeR*255.0f; - shadeG=shadeG*waterShadeG*255.0f; - shadeB=shadeB*waterShadeB*255.0f; - } - else - { - shadeR=shadeR*255.0f; - shadeG=shadeG*255.0f; - shadeB=shadeB*255.0f; - - if (shadeR == 0 && shadeG == 0 && shadeB == 0) - { //special case where we disable lighting - shadeR=255; - shadeG=255; - shadeB=255; - } - } - - Int diffuse=REAL_TO_INT(shadeB) | (REAL_TO_INT(shadeG) << 8) | (REAL_TO_INT(shadeR) << 16); - - //Keep diffuse from lighting calculations but substitute custom alpha - diffuse |= m_settings[m_tod].waterDiffuse & 0xff000000; //copy alpha/opacity from ini setting - - DynamicVBAccessClass vb_access(BUFFER_TYPE_DYNAMIC_DX8,dynamic_fvf_type,(rectangleCount+1)*2); - -//#define WAVY_WATER -//#define FEATHER_LAYER_COUNT (3) //LORENZEN -//#define FEATHER_LAYER_THICKNESS (2.5f) -//#define FEATHER_WATER - -//#ifdef WAVY_WATER // the NEW WATER a'la LORENZEN - if ( TheGlobalData->m_featherWater ) - { - - DynamicVBAccessClass::WriteLockClass lock(&vb_access); - VertexFormatXYZNDUV2* vb=lock.Get_Formatted_Vertex_Array(); - - Real phase = 0; - Real mapCoeff = PI/(4*MAP_XY_FACTOR); - Real wave = 0; - Real amplitude = 0.5f; - - //The first (high order) byte is the Alpha value for this patch - // It needs to be set proportional to the number of feather layers - // this comes from TheGlobalData->m_featherWater, which is a count of layers - - - Int Alpha = 0; - if ( TheGlobalData->m_featherWater == 5) Alpha = 80; - if ( TheGlobalData->m_featherWater == 4) Alpha = 110; - if ( TheGlobalData->m_featherWater == 3) Alpha = 140; - if ( TheGlobalData->m_featherWater == 2) Alpha = 200; - if ( TheGlobalData->m_featherWater == 1) Alpha = 255; - - //Keep diffuse from lighting calculations but substitute custom alpha - Int customDiffuse = (diffuse & 0x00ffffff) | (Alpha<< 24);//(0x80 << 16)|(0x90 << 8)|0xa0; - - for (j=0; jx=vertex.X; - vb->y=vertex.Y; - - // common to all the waving effects - phase = 25 * m_riverVOrigin + vertex.X * mapCoeff; - wave = (sin(phase) - 1.0f) * amplitude; - - vb->z = (vertex.Z + wave); - vb->diffuse = customDiffuse; - vb->u1 = (vertex.X/waterFactor) + 0.02*cos(11*m_riverVOrigin)*wave; - vb->v1 = (vertex.Y/waterFactor) + 0.02*cos(5*m_riverVOrigin)*wave; - vb->u2 = vertex.X/BUMP_SIZE; - vb->v2 = vertex.Y/BUMP_SIZE + 0.3f*vertex.X/BUMP_SIZE; - vb->nx = 0; - vb->ny = 0; - vb->nz = 1.0f; - vb++; - } - } - } -//#else // STILL THE OLD FLAT WATER - else - - { - DynamicVBAccessClass::WriteLockClass lock(&vb_access); - VertexFormatXYZNDUV2* vb=lock.Get_Formatted_Vertex_Array(); - - //Pulling some constants out of the inner loops to improve performance -MW - Real constA=0.02*cos(11*m_riverVOrigin); - Real constB=0.02*cos(5*m_riverVOrigin); - Real constC=25*m_riverVOrigin; - Real ooWaterFactor = 1.0f/waterFactor; - const Real constD=PI/(4*MAP_XY_FACTOR); - Real constE=1.0f/(Real)(vCount-1); - Real constF=1.0f/(Real)(uCount-1); - - for (j=0; jx=vertex.X; - vb->y=vertex.Y; - vb->z=vertex.Z; - - vb->diffuse= diffuse; - //Old slower version - //vb->u1=(vertex.X/waterFactor) + 0.02*cos(11*m_riverVOrigin)*sin(25*m_riverVOrigin+vertex.X*PI/(4*MAP_XY_FACTOR)); - //vb->v1=(vertex.Y/waterFactor) + 0.02*cos(5*m_riverVOrigin)*sin(25*m_riverVOrigin+vertex.Y*PI/(4*MAP_XY_FACTOR)); - vb->u1=vertex.X*ooWaterFactor + constA*WWMath::Fast_Sin(constC+vertex.X*constD); - vb->v1=vertex.Y*ooWaterFactor + constB*WWMath::Fast_Sin(constC+vertex.Y*constD); - vb->u2 = vertex.X/BUMP_SIZE; - //Old slower version - //vb->v2 = vertex.Y/BUMP_SIZE + 0.3f*vertex.X/BUMP_SIZE; - vb->v2 = (vertex.Y+0.3f*vertex.X)/BUMP_SIZE; - vb->nx = 0; - vb->ny = 0; - vb->nz = 1.0f; - vb++; - } - } - } - -//#endif // OLD VS NEW WATER - - - - Matrix3D tm(1); - - DX8Wrapper::Set_Transform(D3DTS_WORLD,tm); //position the water surface - DX8Wrapper::Set_Index_Buffer(ib_access,0); - DX8Wrapper::Set_Vertex_Buffer(vb_access); - - setupFlatWaterShader();// lorenzen sez use the alpha shader - - //If video card supports it and it's enabled, feather the water edge using destination alpha - if (DX8Wrapper::getBackBufferFormat() == WW3D_FORMAT_A8R8G8B8 && TheGlobalData->m_showSoftWaterEdge && TheWaterTransparency->m_transparentWaterDepth !=0) - { DX8Wrapper::Set_DX8_Render_State(D3DRS_SRCBLEND, D3DBLEND_DESTALPHA ); - if (!TheWaterTransparency->m_additiveBlend) - DX8Wrapper::Set_DX8_Render_State(D3DRS_DESTBLEND, D3DBLEND_INVDESTALPHA ); - } - - - DWORD cull; - DX8Wrapper::_Get_D3D_Device8()->GetRenderState(D3DRS_CULLMODE, &cull); - DX8Wrapper::_Get_D3D_Device8()->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); - - - -//#ifdef FEATHER_WATER // the NEW WATER a'la LORENZEN - -// int layer = 0;//LORENZEN -// for (layer = 0; layer < FEATHER_LAYER_COUNT; ++layer)//LORENZEN -//#endif // FEATHER_WATER - { -//#ifdef WAVY_WATER // the NEW WATER a'la LORENZEN - - //increment the depth of the water's surface for every vert in the buffer -//#ifdef FEATHER_WATER -// VertexFormatXYZNDUV2 *vertBuf = vertexBufferStart; -// while (vertBuf < vertexBufferStart + vCount * uCount) -// { -// vertBuf->z *= FEATHER_LAYER_THICKNESS; -// ++vertBuf; -// } -//#endif // FEATHER_WATER -//#endif //WAVY_WATER - DX8Wrapper::Draw_Triangles( 0,rectangleCount*2, 0, (rectangleCount+1)*2);//lorenzen thinks this is where to itereate the soft shoreline effect - } - - - - - if (false) { - DX8Wrapper::_Get_D3D_Device8()->SetRenderState(D3DRS_FILLMODE,D3DFILL_WIREFRAME); - m_pDev->SetRenderState(D3DRS_ALPHABLENDENABLE , false); - DX8Wrapper::Draw_Triangles( 0,rectangleCount*2, 0, (rectangleCount+1)*2); - m_pDev->SetRenderState(D3DRS_ALPHABLENDENABLE , true); - DX8Wrapper::_Get_D3D_Device8()->SetRenderState(D3DRS_FILLMODE,D3DFILL_SOLID); - } - - if (m_riverWaterPixelShader) DX8Wrapper::_Get_D3D_Device8()->SetPixelShader(NULL); - //Restore alpha blend to default values since we may have changed them to feather edges. - if (!TheWaterTransparency->m_additiveBlend) - { DX8Wrapper::Set_DX8_Render_State(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA ); - DX8Wrapper::Set_DX8_Render_State(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA ); - } - else - { - DX8Wrapper::Set_DX8_Render_State(D3DRS_SRCBLEND, D3DBLEND_ONE ); - DX8Wrapper::Set_DX8_Render_State(D3DRS_DESTBLEND, D3DBLEND_ONE ); - } - - if (TheTerrainRenderObject->getShroud()) - { - if (m_trapezoidWaterPixelShader) - { //shroud was applied in stage3 of main pass so just need to restore state here. - W3DShaderManager::resetShader(W3DShaderManager::ST_SHROUD_TEXTURE); - DX8Wrapper::_Get_D3D_Device8()->SetTexture(3,NULL); //free possible reference to shroud texture - DX8Wrapper::_Get_D3D_Device8()->SetRenderState(D3DRS_ZFUNC, D3DCMP_EQUAL); - } - else - { //do second pass to apply the shroud on water plane for cards that can't do it in main pass. - W3DShaderManager::setTexture(0,TheTerrainRenderObject->getShroud()->getShroudTexture()); - W3DShaderManager::setShader(W3DShaderManager::ST_SHROUD_TEXTURE, 0); - DX8Wrapper::_Get_D3D_Device8()->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); - //Shroud shader uses z-compare of EQUAL which wouldn't work on water because it doesn't - //write to the zbuffer. Change to LESSEQUAL. - DX8Wrapper::_Get_D3D_Device8()->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL); - DX8Wrapper::Draw_Triangles( 0,rectangleCount*2, 0, (rectangleCount+1)*2); - DX8Wrapper::_Get_D3D_Device8()->SetRenderState(D3DRS_ZFUNC, D3DCMP_EQUAL); - W3DShaderManager::resetShader(W3DShaderManager::ST_SHROUD_TEXTURE); - } - } - DX8Wrapper::_Get_D3D_Device8()->SetRenderState(D3DRS_CULLMODE, cull); -} - - - -//------------------------------------------------------------------------------------------------- -//debug version where moon rotates with the camera (always upright on screen) -//------------------------------------------------------------------------------------------------- -#if 0 -void WaterRenderObjClass::renderSkyBody(Matrix3D *mat) -{ - Vector3 vRight,vUp,V0,V1,V2,V3; - - mat->Get_X_Vector(&vRight); - mat->Get_Y_Vector(&vUp); - - //calculate offsets from quad center to each of the 4 corners - // 0-----1 - // | /| - // | / | - // |/ | - // 3-----2 - V0=-vRight+vUp; - V2=vRight+vUp; - V2=vRight-vUp; - V3=-vRight-vUp; - - VertexMaterialClass *vmat=VertexMaterialClass::Get_Preset(VertexMaterialClass::PRELIT_DIFFUSE); - DX8Wrapper::Set_Material(vmat); - REF_PTR_RELEASE(vmat); - DX8Wrapper::Set_Shader(ShaderClass::/*_PresetAdditiveShader*//*_PresetOpaqueShader*/_PresetAlphaShader); -// DX8Wrapper::Set_Texture(0,setting->skyBodyTexture); - - DX8Wrapper::Set_Texture(0,m_alphaClippingTexture); - - //draw an infinite sky plane - DynamicVBAccessClass vb_access(BUFFER_TYPE_DYNAMIC_DX8,4); - { - DynamicVBAccessClass::WriteLockClass lock(&vb_access); - VertexFormatXYZNDUV2* verts=lock.Get_Formatted_Vertex_Array(); - if(verts) - { - verts[0].x=SKYBODY_SIZE*V0.X; - verts[0].y=SKYBODY_SIZE*V0.Y; - verts[0].z=SKYBODY_SIZE*V0.Z; - verts[0].u2=0; - verts[0].v2=1; - verts[0].diffuse=0xffffffff; - - verts[1].x=SKYBODY_SIZE*V1.X; - verts[1].y=SKYBODY_SIZE*V1.Y; - verts[1].z=SKYBODY_SIZE*V1.Z; - verts[1].u2=1; - verts[1].v2=1; - verts[1].diffuse=0xffffffff; - - verts[2].x=SKYBODY_SIZE*V2.X; - verts[2].y=SKYBODY_SIZE*V2.Y; - verts[2].z=SKYBODY_SIZE*V2.Z; - verts[2].u2=1; - verts[2].v2=0; - verts[2].diffuse=0xffffffff; - - verts[3].x=SKYBODY_SIZE*V3.X; - verts[3].y=SKYBODY_SIZE*V3.Y; - verts[3].z=SKYBODY_SIZE*V3.Z; - verts[3].u2=0; - verts[3].v2=0; - verts[3].diffuse=0xffffffff; - } - } - - DX8Wrapper::Set_Index_Buffer(m_indexBuffer,0); - DX8Wrapper::Set_Vertex_Buffer(vb_access); - - Matrix3D tm(1); - //set postion of skybody in world -// tm.Set_Translation(Vector3(40,0,0)); - DX8Wrapper::Set_Transform(D3DTS_WORLD,tm); - - DX8Wrapper::Draw_Triangles( 0,2, 0, 4); //draw a quad, 2 triangles, 4 verts -} -#endif - -// ------------------------------------------------------------------------------------------------ -/** CRC */ -// ------------------------------------------------------------------------------------------------ -void WaterRenderObjClass::crc( Xfer *xfer ) -{ - -} - -// ------------------------------------------------------------------------------------------------ -/** Xfer - * Version Info: - * 1: Initial version */ -// ------------------------------------------------------------------------------------------------ -void WaterRenderObjClass::xfer( Xfer *xfer ) -{ - - // version - XferVersion currentVersion = 1; - XferVersion version = currentVersion; - xfer->xferVersion( &version, currentVersion ); - - // grid cells x - Int cellsX = m_gridCellsX; - xfer->xferInt( &cellsX ); - if( cellsX != m_gridCellsX ) - { - - DEBUG_CRASH(( "WaterRenderObjClass::xfer - cells X mismatch" )); - throw SC_INVALID_DATA; - - } - - // grid cells Y - Int cellsY = m_gridCellsY; - xfer->xferInt( &cellsY ); - if( cellsY != m_gridCellsY ) - { - - DEBUG_CRASH(( "WaterRenderObjClass::xfer - cells Y mismatch" )); - throw SC_INVALID_DATA; - - } - - // xfer each of the mesh data points - for( UnsignedInt i = 0; i < m_meshDataSize; ++i ) - { - - // height - xfer->xferReal( &m_meshData[ i ].height ); - - // velocity - xfer->xferReal( &m_meshData[ i ].velocity ); - - // status - xfer->xferUnsignedByte( &m_meshData[ i ].status ); - - // preferred height - xfer->xferUnsignedByte( &m_meshData[ i ].preferredHeight ); - - } - -} - -// ------------------------------------------------------------------------------------------------ -/** Load post process */ -// ------------------------------------------------------------------------------------------------ -void WaterRenderObjClass::loadPostProcess( void ) -{ - -} - - diff --git a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWaterTracks.cpp b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWaterTracks.cpp deleted file mode 100644 index 5c60664aaee..00000000000 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWaterTracks.cpp +++ /dev/null @@ -1,1309 +0,0 @@ -/* -** 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 . -*/ - -//////////////////////////////////////////////////////////////////////////////// -// // -// (c) 2001-2003 Electronic Arts Inc. // -// // -//////////////////////////////////////////////////////////////////////////////// - -// FILE: W3DWaterTracks.cpp //////////////////////////////////////////////// -//----------------------------------------------------------------------------- -// -// Westwood Studios Pacific. -// -// Confidential Information -// Copyright (C) 2001 - All Rights Reserved -// -//----------------------------------------------------------------------------- -// -// Project: RTS3 -// -// File name: W3DWaterTracks.cpp -// -// Created: Mark Wilczynski, July 2001 -// -// Desc: Draw waves and splash marks on water surface. System allows for -// some simple animation : dynamic uv coordinates, scaling, scrolling, -// and alpha. -//----------------------------------------------------------------------------- - -#include "W3DDevice/GameClient/HeightMap.h" -#include "W3DDevice/GameClient/W3DWaterTracks.h" -#include "W3DDevice/GameClient/W3DShaderManager.h" -#include "W3DDevice/GameClient/W3DShroud.h" -#include "GameClient/InGameUI.h" -#include "GameClient/Water.h" -#include "GameLogic/TerrainLogic.h" -#include "Common/FramePacer.h" -#include "Common/GlobalData.h" -#include "Common/UnicodeString.h" -#include "Common/file.h" -#include "Common/FileSystem.h" -#include "texture.h" -#include "colmath.h" -#include "coltest.h" -#include "rinfo.h" -#include "camera.h" -#include "assetmgr.h" -#include "WW3D2/dx8wrapper.h" - -//number of vertex pages allocated - allows double buffering of vertex updates. -//while one is being rendered, another is being updated. Improves HW parallelism. -#define WATER_VB_PAGES 1000 -#define WATER_STRIP_X 2 //vertex resolution of each strip -#define WATER_STRIP_Y 2 -#define SYNC_WAVES //all the waves are in sync - movement resets at same time. -//#define DEFAULT_FINAL_WAVE_WIDTH 28.0f -//#define DEFAULT_FINAL_WAVE_HEIGHT 18.0f -//#define DEFAULT_SECOND_WAVE_TIME_OFFSET 6267 //should always be half of totalMs - -WaterTracksRenderSystem *TheWaterTracksRenderSystem=NULL; ///< singleton for track drawing system. - -static Bool pauseWaves=FALSE; - -enum waveType CPP_11(: Int) -{ - WaveTypeFirst, - WaveTypePond=WaveTypeFirst, - WaveTypeOcean, - WaveTypeCloseOcean, //same as above but appears much closer to beach. - WaveTypeCloseOceanDouble, //same as above but waves much sloser together. - WaveTypeRadial, - WaveTypeLast = WaveTypeRadial, - WaveTypeStationary, - WaveTypeMax, -}; - -struct waveInfo -{ - Real m_finalWidth; //final width of of wave when it reaches beach. - Real m_finalHeight; //final height of wave after it stretched out on beach. - Real m_waveDistance; //distance away from beach where wave starts. - Real m_initialVelocity; - Int m_fadeMs; //time to fade out wave after it stops on shore. - Real m_initialWidthFraction; //fraction of m_finalWidth when wave first appears. - Real m_initialHeightWidthFraction; //fraction of initial width to use as the initial height. - Int m_timeToCompress; //time for back of wave to continue moving forward after front starts retreating. - Int m_secondWaveTimeOffset; //time for second wave to start. Should always be half of first wave's TotalMs. - const char *m_textureName; //name of texture to use on wave. - const char *m_waveTypeName; //name of this wave type. -}; - -waveInfo waveTypeInfo[WaveTypeMax]= -{ - {28.0f, 18.0f, 25.0f, 0.018f, 900, 0.01f, 0.18f, 1500, 0,"wave256.tga","Pond"}, //pond - {55.0f, 36.0f, 80.0f, 0.015f, 2000, 0.5f, 0.18f, 1000, 6267,"wave256.tga","Ocean"}, //ocean - {55.0f, 36.0f, 80.0f, 0.015f, 2000, 0.05f, 0.18f, 1000, 6267,"wave256.tga","Close Ocean"}, - {55.0f, 36.0f, 80.0f, 0.015f, 4000, 0.01f, 0.18f, 2000, 6267,"wave256.tga","Close Ocean Double"}, - {55.0f, 27.0f, 80.0f, 0.015f, 2000, 0.01f, 8.0f, 2000, 5367,"wave256.tga","Radial"}, -}; - -//============================================================================= -// WaterTracksObj::~WaterTracksObj -//============================================================================= -/** Destructor. Releases w3d assets. */ -//============================================================================= -WaterTracksObj::~WaterTracksObj(void) -{ - freeWaterTracksResources(); -} - -//============================================================================= -// WaterTracksObj::WaterTracksObj -//============================================================================= -/** Constructor. Just nulls out some variables. */ -//============================================================================= -WaterTracksObj::WaterTracksObj(void) -{ - m_stageZeroTexture=NULL; - m_bound=false; - m_initTimeOffset=0; -} - -//============================================================================= -// WaterTracksObj::Get_Obj_Space_Bounding_Sphere -//============================================================================= -/** WW3D method that returns object bounding sphere used in frustum culling*/ -//============================================================================= -void WaterTracksObj::Get_Obj_Space_Bounding_Sphere(SphereClass & sphere) const -{ /// @todo: Add code to cull track marks to screen by constantly updating bounding volumes - sphere=m_boundingSphere; -} - -//============================================================================= -// WaterTracksObj::Get_Obj_Space_Bounding_Box -//============================================================================= -/** WW3D method that returns object bounding box used in collision detection*/ -//============================================================================= -void WaterTracksObj::Get_Obj_Space_Bounding_Box(AABoxClass & box) const -{ - box=m_boundingBox; -} - -//============================================================================= -// WaterTracksObj::freeWaterTracksResources -//============================================================================= -/** Free any W3D resources associated with this object */ -//============================================================================= -Int WaterTracksObj::freeWaterTracksResources(void) -{ - REF_PTR_RELEASE(m_stageZeroTexture); - return 0; -} - -//============================================================================= -// WaterTracksObj::init -//============================================================================= -/** Setup size settings and allocate W3D texture -* The width/length define the size of the polygon quad which will contain -* the specified texture. - */ -//============================================================================= -void WaterTracksObj::init( Real width, Real length, const Vector2 &start, const Vector2 &end, const Char *texturename, Int waveTimeOffset) -{ - freeWaterTracksResources(); //free old resources used by this track - - //save original settings used to create this wave - m_initStartPos = start; - m_initEndPos = end; - m_initTimeOffset = waveTimeOffset; - - m_boundingSphere.Init(Vector3(0,0,0),400); - m_boundingBox.Center.Set(0.0f, 0.0f, 0.0f); - m_boundingBox.Extent.Set(400.0f, 400.0f, 1.0f); - m_x=WATER_STRIP_X; - m_y=WATER_STRIP_Y; - m_elapsedMs=m_initTimeOffset; - m_startPos=start; - m_perpDir=m_waveDir=end-start; - m_perpDir.Rotate(-1.57079632679f); //get vector perpendicular to wave motion. - m_perpDir.Normalize(); - - m_waveDir=m_perpDir; - m_waveDir.Rotate(PI/2); //get vector along wave travel direction. - //move back by width of wave so start point turns into maximum reach of wave. - //m_startPos -= m_waveDir*m_width; - //move back initial tip off of wave a couple units off the final position - //to give it some room to travel. Travel vector is stored in m_waveDir. - m_waveDistance = waveTypeInfo[m_type].m_waveDistance; //total distance traveled by wave front - - m_waveDir *= m_waveDistance; - m_startPos -= m_waveDir; //move start point down away from shoreline - - m_initialVelocity=waveTypeInfo[m_type].m_initialVelocity; //velocity per ms - m_totalMs = m_waveDistance/m_initialVelocity; //amount of time for wave to travel complete distance - - m_fadeMs = waveTypeInfo[m_type].m_fadeMs; //time for wave to fade out after it stops on beach - - m_waveInitialWidth=length * waveTypeInfo[m_type].m_initialWidthFraction;///Get_Texture(texturename); -} - -//============================================================================= -// WaterTracksObj::init -//============================================================================= -/** Setup size settings and allocate W3D texture -* Alternate version of init where: -* (start, end) define a vector perpendicular to wave travel. The length of this -* vector is used as the length of the wave segment. The line between start-end -* defines the maximum distance the wave will reach. - */ -//============================================================================= -void WaterTracksObj::init( Real width, const Vector2 &start, const Vector2 &end, const Char *texturename) -{ - freeWaterTracksResources(); //free old resources used by this track - m_boundingSphere.Init(Vector3(0,0,0),400); - m_boundingBox.Center.Set(0.0f, 0.0f, 0.0f); - m_boundingBox.Extent.Set(400.0f, 400.0f, 1.0f); - m_perpDir=end-start; - m_startPos=start + m_perpDir*0.5f; //move start point to middle - Real length=m_perpDir.Length(); - m_perpDir *= 1.0f/length; //normalize it. - m_waveDir=m_perpDir; - m_waveDir.Rotate(PI/2); //get vector along wave travel direction. - m_startPos -= m_waveDir*width; //move back by width of wave - m_waveDir *= 1.3f*MAP_XY_FACTOR; //travel 4 units - m_startPos -= m_waveDir; //move start point down away from shoreline - m_x=WATER_STRIP_X; - m_y=WATER_STRIP_Y; - m_elapsedMs=0; - m_initialVelocity=0.001f*MAP_XY_FACTOR; //velocity per ms - m_totalMs=m_waveDir.Length()/m_initialVelocity; - m_fadeMs = 3000; //time for wave to fade out after it stops on beach - - m_stageZeroTexture=WW3DAssetManager::Get_Instance()->Get_Texture(texturename); -} - -//============================================================================= -// WaterTracksObj::update -//============================================================================= -/** Update state of object - advance animations and other states. - */ -//============================================================================= -Int WaterTracksObj::update(Int msElapsed) -{ - return TRUE; //assume we had an update -} - -#define waveInitialV = 0.01f -#define waveAcceleration = -0.01f - -//============================================================================= -// WaterTracksObj::render -//============================================================================= -/** Draws the object in it's current state. - */ -//============================================================================= - -Int WaterTracksObj::render(DX8VertexBufferClass *vertexBuffer, Int batchStart) -{ - // TheSuperHackers @tweak The wave movement time step is now decoupled from the render update. - m_elapsedMs += TheFramePacer->getLogicTimeStepMilliseconds(); - - VertexFormatXYZDUV1 *vb; - Vector2 waveTailOrigin,waveFrontOrigin; - Real ooWaveDirLen=1.0f/m_waveDir.Length(); //one over length - Real waterHeight; - Real waveAlpha; - Real widthFrac; - Real heightFrac; - - if (batchStart < (WATER_VB_PAGES*WATER_STRIP_X*WATER_STRIP_Y-m_x*m_y)) - { //we have room in current VB, append new verts - if(vertexBuffer->Get_DX8_Vertex_Buffer()->Lock(batchStart*vertexBuffer->FVF_Info().Get_FVF_Size(),m_x*m_y*vertexBuffer->FVF_Info().Get_FVF_Size(),(unsigned char**)&vb,D3DLOCK_NOOVERWRITE) != D3D_OK) - return batchStart; - } - else - { //ran out of room in last VB, request a substitute VB. - if(vertexBuffer->Get_DX8_Vertex_Buffer()->Lock(0,m_x*m_y*vertexBuffer->FVF_Info().Get_FVF_Size(),(unsigned char**)&vb,D3DLOCK_DISCARD) != D3D_OK) - return batchStart; - batchStart=0; //reset start of page to first vertex - } - - //Adjust wave position in a non-linear way so that it slows down as it hits the target. Using 1/4 sine wave - //seems to work okay since it maxes out at 1.0 at our final position. - //Real timeFrac=(Real)m_elapsedMs/(Real)m_totalMs;//sinf(0.5f*3.14159f*(Real)m_elapsedMs/(Real)m_totalMs); - - //Real displacement=m_elapsedMs*waveInitialV+0.5*waveAcceleration*m_elapsed*m_elapsed; - - heightFrac=1.0f; - widthFrac = 1.0f; - - if (m_type == WaveTypeStationary) - { //stationary wave - waveFrontOrigin = m_startPos; - waveFrontOrigin -= m_perpDir*m_waveFinalWidth*0.5f; //offset to left edge of wave - waveTailOrigin = waveFrontOrigin - m_waveFinalHeight * ooWaveDirLen*m_waveDir; - waveAlpha = 0.0f; - - if (m_elapsedMs >= m_totalMs) - m_elapsedMs = 0; //done with effect*/ - if (m_elapsedMs > (m_timeToReachBeach + m_timeToStop -1000 + m_fadeMs)) - { //fading out - waveAlpha = m_elapsedMs-(m_timeToReachBeach + m_timeToStop - 1000 +m_fadeMs);//(m_totalMs-m_timeToRetreat -m_fadeMs - m_elapsedMs)/m_fadeMs; - waveAlpha = waveAlpha / m_timeToRetreat; - waveAlpha = 1.0f - waveAlpha; - if (waveAlpha < 0.0f) - waveAlpha = 0.0f; - } - else - if (m_elapsedMs > (m_timeToReachBeach + m_timeToStop - 1000)) - { //start fading up - - waveAlpha = m_elapsedMs-(m_timeToReachBeach + m_timeToStop - 1000);//(m_totalMs-m_timeToRetreat -m_fadeMs - m_elapsedMs)/m_fadeMs; - waveAlpha = waveAlpha / m_fadeMs; - if (waveAlpha > 1.0f) - waveAlpha = 1.0f; - } - } - else - { //moving wave - - //get coordinate of top left of wave strip - if (m_elapsedMs < m_timeToReachBeach) - { //wave has not reached beach yet so position only depends on velocity - waveAlpha = m_elapsedMs / m_timeToReachBeach; - widthFrac = waveAlpha; - widthFrac=(m_waveInitialWidth + widthFrac* (m_waveFinalWidth-m_waveInitialWidth))/m_waveFinalWidth; - - waveFrontOrigin = m_startPos + m_initialVelocity*m_elapsedMs*ooWaveDirLen*m_waveDir; - waveFrontOrigin -= m_perpDir*m_waveFinalWidth*0.5f*widthFrac; //offset to left edge of wave - //Tail of wave will be behind the front by fixed amount. - waveTailOrigin = waveFrontOrigin - m_waveInitialHeight * ooWaveDirLen*m_waveDir; - } - else //wave has reached beach and is decelerating - if (m_elapsedMs < m_totalMs) - { waveAlpha = 1.0f; - widthFrac = 1.0f; - //Get position of wave when it hit the beach - waveFrontOrigin = m_startPos + m_initialVelocity*m_timeToReachBeach*ooWaveDirLen*m_waveDir; - waveTailOrigin = waveFrontOrigin; //store position for calculating tail position - //Add movement after it hit the beach - Real elapsedMs=m_elapsedMs - m_timeToReachBeach; - waveFrontOrigin += (m_initialVelocity*elapsedMs+0.5f*m_frontSlowDownAcc*elapsedMs*elapsedMs)*ooWaveDirLen*m_waveDir; - waveFrontOrigin -= m_perpDir*m_waveFinalWidth*0.5f*widthFrac; //offset to left edge of wave - - Real timeSinceBacktrack = m_elapsedMs - m_timeToReachBeach - m_timeToStop; - if (timeSinceBacktrack < 0) - timeSinceBacktrack = 0; - waveAlpha = timeSinceBacktrack/m_fadeMs; - if (waveAlpha > 1.0f) - waveAlpha = 1.0f; - - waveAlpha = 1.0f - waveAlpha; - - //Get position of tail when front hits the beach. - waveTailOrigin -= m_waveInitialHeight * ooWaveDirLen*m_waveDir; - - if (m_elapsedMs > (m_timeToReachBeach+m_timeToStop+m_timeToCompress)) - { elapsedMs=elapsedMs; ///@todo: bug? - waveTailOrigin += (0.5f*m_backSlowDownAcc*(m_timeToStop+m_timeToCompress)*(m_timeToStop+m_timeToCompress))*ooWaveDirLen*m_waveDir; - //get time since wave should have stopped moving forward - Real newElapsed = m_elapsedMs - (m_timeToReachBeach+m_timeToStop+m_timeToCompress); - waveTailOrigin += (0.5f*m_frontSlowDownAcc*newElapsed*newElapsed)*ooWaveDirLen*m_waveDir; - } - else - // if (m_elapsedMs < (m_totalMs-m_timeToRetreat)) - //find position of tail including slowdown after it hit the beach - // waveTailOrigin += (m_initialVelocity*elapsedMs+0.5f*m_backSlowDownAcc*elapsedMs*elapsedMs)*ooWaveDirLen*m_waveDir; - waveTailOrigin += (0.5f*m_backSlowDownAcc*elapsedMs*elapsedMs)*ooWaveDirLen*m_waveDir; - - waveTailOrigin -= m_perpDir*m_waveFinalWidth*0.5f*widthFrac; //offset to left edge of wave - } - else - { m_elapsedMs = 0; - waveAlpha = m_elapsedMs / m_timeToReachBeach; - widthFrac = waveAlpha; - widthFrac=(m_waveInitialWidth + widthFrac* (m_waveFinalWidth-m_waveInitialWidth))/m_waveFinalWidth; - - waveFrontOrigin = m_startPos + m_initialVelocity*m_elapsedMs*ooWaveDirLen*m_waveDir; - waveFrontOrigin -= m_perpDir*m_waveFinalWidth*0.5f*widthFrac; //offset to left edge of wave - //Tail of wave will be behind the front by fixed amount. - waveTailOrigin = waveFrontOrigin - m_waveInitialHeight * ooWaveDirLen*m_waveDir; - } - } - - //First insert tail of wave: - Vector2 testPoint(waveTailOrigin); - TheTerrainLogic->isUnderwater(testPoint.X,testPoint.Y,&waterHeight); - vb->x= testPoint.X; - vb->y= testPoint.Y; - vb->z=waterHeight+1.5f; - vb->diffuse=(REAL_TO_INT(waveAlpha*255.0f)<<24) |0xffffff; - if (m_flipU) - vb->u1=1; - else - vb->u1=0; - vb->v1=0; - vb++; - testPoint.Set(waveTailOrigin + m_perpDir*m_waveFinalWidth*widthFrac); - vb->x= testPoint.X; - vb->y= testPoint.Y; - vb->z=waterHeight+1.5f; - vb->diffuse=(REAL_TO_INT(waveAlpha*255.0f)<<24) |0xffffff; - if (m_flipU) - vb->u1=0.0f; - else - vb->u1=1.0f; - vb->v1=0; - vb++; - //insert front of wave - testPoint.Set(waveFrontOrigin); - vb->x= testPoint.X; - vb->y= testPoint.Y; - vb->z=waterHeight+1.5f; - vb->diffuse=(REAL_TO_INT(waveAlpha*255.0f)<<24) |0xffffff; - if (m_flipU) - vb->u1=1; - else - vb->u1=0; - vb->v1=1.0f; - vb++; - testPoint.Set(waveFrontOrigin + m_perpDir*m_waveFinalWidth*widthFrac); - vb->x= testPoint.X; - vb->y= testPoint.Y; - vb->z=waterHeight+1.5f; - vb->diffuse=(REAL_TO_INT(waveAlpha*255.0f)<<24) |0xffffff; - if (m_flipU) - vb->u1=0; - else - vb->u1=1.0f; - vb->v1=1.0f; - vb++; - - vertexBuffer->Get_DX8_Vertex_Buffer()->Unlock(); - - Int idxCount=(m_y-1)*(m_x*2+2) - 2; //index count - - DX8Wrapper::Set_Index_Buffer(TheWaterTracksRenderSystem->m_indexBuffer,batchStart); - DX8Wrapper::Draw_Strip(0,idxCount-2,0,m_x*m_y); //there are always n-2 primitives for n index strip. - - return batchStart+m_x*m_y; //return new offset into unused area of vertex buffer -} - -//============================================================================= -//WaterTracksRenderSystem::bindTrack -//============================================================================= -/** Grab a track from the free store. If no free tracks exist, return NULL. - As long as a track is bound to an object (like a tank) it is ready to accept - updates with additional edges. Once it is unbound, it will expire and return - to the free store once all tracks have faded out. -*/ -//============================================================================= -WaterTracksObj *WaterTracksRenderSystem::bindTrack(waveType type) -{ - WaterTracksObj *mod,*nextmod,*prevmod; - - mod = m_freeModules; - if( mod ) - { - // take module off the free list - if( mod->m_nextSystem ) - mod->m_nextSystem->m_prevSystem = mod->m_prevSystem; - if( mod->m_prevSystem ) - mod->m_prevSystem->m_nextSystem = mod->m_nextSystem; - else - m_freeModules = mod->m_nextSystem; - - mod->m_type=type; - - // put module on the used list (sorted next to similar types) - nextmod=NULL,prevmod=NULL; - for( nextmod = m_usedModules; nextmod; prevmod=nextmod,nextmod = nextmod->m_nextSystem ) - { - if (nextmod->m_type==type) - { //found start of other shadows using same texture, insert new shadow here. - mod->m_nextSystem=nextmod; - mod->m_prevSystem=prevmod; - nextmod->m_prevSystem=mod; - if (prevmod) - { prevmod->m_nextSystem=mod; - } - else - m_usedModules=mod; - break; - } - } - - if (nextmod==NULL) - { //shadow with new texture. Add to top of list. - mod->m_nextSystem = m_usedModules; - if (m_usedModules) - m_usedModules->m_prevSystem=mod; - m_usedModules = mod; - } - - mod->m_bound=true; - } - - #ifdef SYNC_WAVES - nextmod=m_usedModules; - - while(nextmod) - { - nextmod->m_elapsedMs=nextmod->m_initTimeOffset; - nextmod=nextmod->m_nextSystem; - } - #endif - - return mod; -} - -//============================================================================= -//WaterTracksRenderSystem::unbindTrack -//============================================================================= -/** Called when an object (i.e Tank) will not lay down any more tracks and -doesn't need this object anymore. The track-laying object will be returned -to pool of available tracks as soon as any remaining track edges have faded out. -*/ -//============================================================================= -void WaterTracksRenderSystem::unbindTrack( WaterTracksObj *mod ) -{ - //this object should return to free store as soon as there is nothing - //left to render. - mod->m_bound=false; - releaseTrack(mod); -} - -//============================================================================= -//WaterTracksRenderSystem::releaseTrack -//============================================================================= -/** Returns a track laying object to free store to be used again later. -*/ -void WaterTracksRenderSystem::releaseTrack( WaterTracksObj *mod ) -{ - if (mod==NULL) - return; - - assert(mod->m_bound == false); - - // remove module from used list - if( mod->m_nextSystem ) - mod->m_nextSystem->m_prevSystem = mod->m_prevSystem; - if( mod->m_prevSystem ) - mod->m_prevSystem->m_nextSystem = mod->m_nextSystem; - else - m_usedModules = mod->m_nextSystem; - - // add module to free list - mod->m_prevSystem = NULL; - mod->m_nextSystem = m_freeModules; - if( m_freeModules ) - m_freeModules->m_prevSystem = mod; - m_freeModules = mod; - mod->freeWaterTracksResources(); -} - -//============================================================================= -// WaterTracksRenderSystem::WaterTracksRenderSystem -//============================================================================= -/** Constructor. Just nulls out some variables. */ -//============================================================================= -WaterTracksRenderSystem::WaterTracksRenderSystem() -{ - m_usedModules = NULL; - m_freeModules = NULL; - m_indexBuffer = NULL; - m_vertexMaterialClass = NULL; - m_vertexBuffer = NULL; - m_stripSizeX=WATER_STRIP_X; - m_stripSizeY=WATER_STRIP_Y; - m_batchStart=0; - TheWaterTracksRenderSystem = this; //only allow one instance of this object. -} - -//============================================================================= -// WaterTracksRenderSystem::~WaterTracksRenderSystem -//============================================================================= -/** Destructor. Free all pre-allocated track laying render objects*/ -//============================================================================= -WaterTracksRenderSystem::~WaterTracksRenderSystem( void ) -{ - - // free all data - shutdown(); - - m_vertexMaterialClass=NULL; - -} - -//============================================================================= -// WaterTracksRenderSystem::ReAcquireResources -//============================================================================= -/** (Re)allocates all W3D assets after a reset.. */ -//============================================================================= -void WaterTracksRenderSystem::ReAcquireResources(void) -{ - Int i,j,k; -// const Int numModules=16; ///@todo: Get a value out of gdf - - // just for paranoia's sake. - REF_PTR_RELEASE(m_indexBuffer); - REF_PTR_RELEASE(m_vertexBuffer); - - //Will need m_y-1 strips, each of length m_x*2. - //Will also need 2 extra indices to connect each strip to next one (except last strip) - //Total index buffer size = (m_y-1)*(m_x*2+2) - 2 (drop the extra 2 indices from last strip) - - Int idxCount=(m_stripSizeY-1)*(m_stripSizeX*2+2) - 2; - - m_indexBuffer=NEW_REF(DX8IndexBufferClass,(idxCount)); - - // Fill up the IB - { - DX8IndexBufferClass::WriteLockClass lockIdxBuffer(m_indexBuffer); - UnsignedShort *ib=lockIdxBuffer.Get_Index_Array(); - - for (i=0,j=0,k=0; im_waterPositionZ; - - ReAcquireResources(); - //go with a preset material for now. - m_vertexMaterialClass=VertexMaterialClass::Get_Preset(VertexMaterialClass::PRELIT_DIFFUSE); - - //use a multi-texture shader: - m_shaderClass = ShaderClass::_PresetAlphaShader; - m_shaderClass.Set_Cull_Mode(ShaderClass::CULL_MODE_DISABLE); //water should be visible from both sides - - // we cannot initialize a system that is already initialized - if( m_freeModules || m_usedModules ) - { - - // system already online! - assert( 0 ); - return; - - } - - // allocate our modules for this system - for( i = 0; i < numModules; i++ ) - { - - mod = NEW WaterTracksObj; - - if( mod == NULL ) - { - - // unable to allocate modules needed - assert( 0 ); - return; - - } - - mod->m_prevSystem = NULL; - mod->m_nextSystem = m_freeModules; - if( m_freeModules ) - m_freeModules->m_prevSystem = mod; - m_freeModules = mod; - - } - -} - -void WaterTracksRenderSystem::reset(void) -{ - WaterTracksObj *nextMod,*mod; - - //release unbound tracks that may still be fading out - mod=m_usedModules; - - while(mod) - { - nextMod=mod->m_nextSystem; - mod->m_bound=false; - releaseTrack(mod); - - mod = nextMod; - } - - - // free all attached things and used modules - assert( m_usedModules == NULL ); -} - -//============================================================================= -// WaterTracksRenderSystem::shutdown -//============================================================================= -/** Shutdown and free all memory for this system */ -//============================================================================= -void WaterTracksRenderSystem::shutdown( void ) -{ - WaterTracksObj *nextMod,*mod; - - //release unbound tracks that may still be fading out - mod=m_usedModules; - - while(mod) - { - nextMod=mod->m_nextSystem; - - if (!mod->m_bound) - releaseTrack(mod); - - mod = nextMod; - } - - - // free all attached things and used modules - assert( m_usedModules == NULL ); - - // free all module storage - while( m_freeModules ) - { - - nextMod = m_freeModules->m_nextSystem; - delete m_freeModules; - m_freeModules = nextMod; - - } - - REF_PTR_RELEASE(m_indexBuffer); - REF_PTR_RELEASE(m_vertexMaterialClass); - REF_PTR_RELEASE(m_vertexBuffer); - -} - -//============================================================================= -// WaterTracksRenderSystem::update -//============================================================================= -/** Update the state of all active track marks - fade, expire, etc. */ -//============================================================================= -void WaterTracksRenderSystem::update() -{ - - static Int iLastTime=timeGetTime(); - WaterTracksObj *mod=m_usedModules,*nextMod; - - Int timeDiff = timeGetTime()-iLastTime; - iLastTime += timeDiff; - - //first update all the tracks - while( mod ) - { - nextMod = mod->m_nextSystem; - - if (!mod->m_bound || (!mod->update(timeDiff) && !mod->m_bound)) - { //object is not longer updating and is unbound so ok to release it. - releaseTrack(mod); - } - - mod = nextMod; - } -} - - -void TestWaterUpdate(void); -void setFPMode( void ); - -//============================================================================= -// WaterTracksRenderSystem::flush -//============================================================================= -/** Draw all active track marks for this frame */ -//============================================================================= -void WaterTracksRenderSystem::flush(RenderInfoClass & rinfo) -{ -/** @todo: Optimize system by drawing tracks as triangle strips and use dynamic vertex buffer access. -May also try rendering all tracks with one call to W3D/D3D by grouping them by texture. -Try improving the fit to vertical surfaces like cliffs. -*/ - Int diffuseLight; - - if (!TheGlobalData->m_showSoftWaterEdge || TheWaterTransparency->m_transparentWaterDepth ==0 ) - return; - - if (TheGlobalData->m_usingWaterTrackEditor) - TestWaterUpdate(); - - update(); //update positions of all the tracks - - rinfo.Camera.Apply(); - - if (!m_usedModules || ShaderClass::Is_Backface_Culling_Inverted()) - return; //don't render track marks in reflections. - - //According to Nvidia there's a D3D bug that happens if you don't start with a - //new dynamic VB each frame - so we force a DISCARD by overflowing the counter. - m_batchStart = 0xffff; - - // adjust shading for time of day. - Real shadeR, shadeG, shadeB; - shadeR = TheGlobalData->m_terrainAmbient[0].red; - shadeG = TheGlobalData->m_terrainAmbient[0].green; - shadeB = TheGlobalData->m_terrainAmbient[0].blue; - shadeR += TheGlobalData->m_terrainDiffuse[0].red/2; - shadeG += TheGlobalData->m_terrainDiffuse[0].green/2; - shadeB += TheGlobalData->m_terrainDiffuse[0].blue/2; - shadeR*=255.0f; - shadeG*=255.0f; - shadeB*=255.0f; - - diffuseLight=REAL_TO_INT(shadeB) | (REAL_TO_INT(shadeG) << 8) | (REAL_TO_INT(shadeR) << 16); - - Matrix3D tm(1); ///set to identity - DX8Wrapper::Set_Transform(D3DTS_WORLD,tm); //position the water surface - - DX8Wrapper::Set_Material(m_vertexMaterialClass); - DX8Wrapper::Set_Shader(m_shaderClass); - - DX8Wrapper::Set_Vertex_Buffer(m_vertexBuffer); - DX8Wrapper::Set_DX8_Render_State(D3DRS_ZBIAS,8); - //Force apply of render states so we can override them. - DX8Wrapper::Apply_Render_State_Changes(); - - if (TheTerrainRenderObject->getShroud()) - { - W3DShaderManager::setTexture(0,TheTerrainRenderObject->getShroud()->getShroudTexture()); - W3DShaderManager::setShader(W3DShaderManager::ST_SHROUD_TEXTURE, 1); - - //modulate with shroud texture - DX8Wrapper::Set_DX8_Texture_Stage_State( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE ); //stage 1 texture - DX8Wrapper::Set_DX8_Texture_Stage_State( 1, D3DTSS_COLORARG2, D3DTA_CURRENT ); //previous stage texture - DX8Wrapper::Set_DX8_Texture_Stage_State( 1, D3DTSS_COLOROP, D3DTOP_MODULATE ); - DX8Wrapper::Set_DX8_Texture_Stage_State( 1, D3DTSS_ALPHAOP, D3DTOP_MODULATE ); - - //Shroud shader uses z-compare of EQUAL which wouldn't work on water because it doesn't - //write to the zbuffer. Change to LESSEQUAL. - DX8Wrapper::Set_DX8_Render_State(D3DRS_ZFUNC, D3DCMP_LESSEQUAL); - } - - Int LastTextureType=-1; - - WaterTracksObj *mod=m_usedModules; - - while( mod ) - { - if (LastTextureType != mod->m_type) - DX8Wrapper::Set_Texture(0,mod->m_stageZeroTexture); - - Int vertsRendered=mod->render(m_vertexBuffer,m_batchStart); - - m_batchStart = vertsRendered; //advance past vertices already in buffer - - mod = mod->m_nextSystem; - } - - DX8Wrapper::Set_DX8_Render_State(D3DRS_ZBIAS,0); - - if (TheTerrainRenderObject->getShroud()) - { //we used the shroud shader, so reset it. - DX8Wrapper::Set_DX8_Render_State(D3DRS_ZFUNC, D3DCMP_EQUAL); - W3DShaderManager::resetShader(W3DShaderManager::ST_SHROUD_TEXTURE); - } -} - -WaterTracksObj *WaterTracksRenderSystem::findTrack(Vector2 &start, Vector2 &end, waveType type) -{ - WaterTracksObj *mod=m_usedModules; - - while( mod ) - { - if (mod->m_initEndPos == end && - mod->m_initStartPos == start && - mod->m_type == type) - return mod; - mod = mod->m_nextSystem; - } - return NULL; -} -void WaterTracksRenderSystem::saveTracks(void) -{ - - if (!TheTerrainLogic) - return; - - AsciiString fileName=TheTerrainLogic->getSourceFilename(); - char path[256]; - - strlcpy(path, fileName.str(), ARRAY_SIZE(path)); - strlcat(path, ".wak", ARRAY_SIZE(path)); - - WaterTracksObj *umod; - Int trackCount=0; - - FILE *fp=fopen(path,"wb"); - - if (fp) - { - umod=m_usedModules; - while(umod) - { if (umod->m_initTimeOffset == 0) - { //only save the primary wave front, second layer is added automatically. - fwrite(&umod->m_initStartPos,sizeof(umod->m_startPos),1,fp); - fwrite(&umod->m_initEndPos,sizeof(umod->m_perpDir),1,fp); - fwrite(&umod->m_type,sizeof(umod->m_type),1,fp); - // fwrite(&umod->m_initTimeOffset,sizeof(umod->m_initTimeOffset),1,fp); - trackCount++; - } - umod=umod->m_nextSystem; - } - fwrite(&trackCount,sizeof(trackCount),1,fp); - fclose(fp); - } -} - -void WaterTracksRenderSystem::loadTracks(void) -{ - - if (!TheTerrainLogic) - return; - - AsciiString fileName=TheTerrainLogic->getSourceFilename(); - char path[256]; - - strlcpy(path, fileName.str(), ARRAY_SIZE(path)); - strlcat(path, ".wak", ARRAY_SIZE(path)); - - File *file = TheFileSystem->openFile(path, File::READ | File::BINARY); - WaterTracksObj *umod; - Int trackCount=0; - Int flipU=0; - Vector2 startPos,endPos; - waveType wtype; - - if (file) - { - file->seek(-4,File::END); - file->read(&trackCount,sizeof(trackCount)); - file->seek(0, File::START); - for (Int i=0; iread(&startPos,sizeof(startPos)); - file->read(&endPos,sizeof(endPos)); - file->read(&wtype,sizeof(wtype)); - //Check if this track already exists. - if (findTrack(startPos,endPos,wtype)) - { i++; - goto tryagain; - } - - umod=TheWaterTracksRenderSystem->bindTrack(wtype); - if (umod) - { //umod->init(1.5f*MAP_XY_FACTOR,Vector2(0,0),Vector2(1,1),"wave256.tga"); - flipU ^= 1; //toggle flip state - umod->init(waveTypeInfo[wtype].m_finalHeight,waveTypeInfo[wtype].m_finalWidth,startPos,endPos,waveTypeInfo[wtype].m_textureName,0); - umod->m_flipU=flipU; - - if (waveTypeInfo[wtype].m_secondWaveTimeOffset) //check if we need a second wave to follow - { - umod=TheWaterTracksRenderSystem->bindTrack(wtype); - if (umod) - { - umod->init(waveTypeInfo[wtype].m_finalHeight,waveTypeInfo[wtype].m_finalWidth,startPos,endPos,waveTypeInfo[wtype].m_textureName,waveTypeInfo[wtype].m_secondWaveTimeOffset); - umod->m_flipU = !flipU; - } - } - } - } - file->close(); - } - -#if 0 //Obsolete code used before there was another editor to place waves. - //Look for all waypoints that start with "waveStart_" - for (Waypoint *way = TheTerrainLogic->getFirstWaypoint(); way; way = way->getNext()) - { - if (way->getName().startsWith("waveStart_") && way->getNumLinks() == 1) - { - Waypoint *nextWay = way->getLink(0); - Coord3D startPos = *way->getLocation(); - Coord3D endPos = *nextWay->getLocation(); - - //initialize surface layer (1) - WaterTracksObj *umod=TheWaterTracksRenderSystem->bindTrack(1); - if (umod) - { - umod->init(DEFAULT_FINAL_WAVE_HEIGHT,DEFAULT_FINAL_WAVE_WIDTH,Vector2(startPos.x,startPos.y),Vector2(endPos.x,endPos.y),"wave1.tga",0); - } -/* - //initialize foam layer (0) - umod=TheWaterTracksRenderSystem->bindTrack(0); - if (umod) - { - umod->init(2.5f*MAP_XY_FACTOR,5.0f*MAP_XY_FACTOR,Vector2(startPos.x,startPos.y),Vector2(endPos.x,endPos.y),"wave2.tga"); -// umod->m_fadeMs += 1500; //take extra 500 ms to fade out wave. -// umod->m_retreatFrac = 1.0f; //don't move wave back after it hits final position. - }*/ - } - } -#endif -} - -/**@todo: this is a quick hack for adding/removing/testing breaking waves inside the client. -Will need to move this code to an external editor at some pont. */ -#include "GameClient/Display.h" - -extern HWND ApplicationHWnd; - -//TODO: Fix editor so it actually draws the wave segment instead of line while editing -//Could freeze all the water while editing? Or keep setting elapsed time on current segment. -//Have to make it so seamless merge of segments at final position. -static void TestWaterUpdate(void) -{ - static Int doInit=1; - static WaterTracksObj *track=NULL,*track2=NULL; - static Int trackEditMode=0; - static waveType currentWaveType = WaveTypeOcean; - POINT screenPoint; - POINT endPoint; - static POINT mouseAnchor; - static Int haveStart=0; - static Int haveEnd=0; - static Coord3D terrainPointStart,terrainPointEnd; - //flags to tell me when the user lets go of a key - static Int trackEditModeReset=1; - static Int addPointReset=1; - static Int deleteTrackReset=1; - static Int saveTracksReset=1; - static Int loadTracksReset=1; - static Int changeTypeReset=1; - - pauseWaves=FALSE; - - if (doInit) - { //create the system - doInit=0; - -// TheWaterTracksRenderSystem = NEW (WaterTracksRenderSystem); -// TheWaterTracksRenderSystem->init(); - - //create a dummy track -// track=TheWaterTracksRenderObjClassSystem->bindTrack(0); -// track->init(1.5f,8.0f,Vector2(147.0f,67.0f),Vector2(146.9f,68.6f),"wave2.tga"); - -// track=TheWaterTracksRenderObjClassSystem->bindTrack(0); -// track->init(1.5f,8.0f,Vector2(139.0f,66.0f),Vector2(138.8f,67.6f),"wave2.tga"); - } - - if (GetAsyncKeyState(VK_F5) & 0x8001) //check if F5 pressed since last call - { - if (trackEditModeReset) - { - if (trackEditMode) - { - UnicodeString string; - string.format(L"Leaving Water Track Edit Mode"); - TheInGameUI->message(string); - } - else - { - UnicodeString string; - string.format(L"Entering Water Track Edit Mode"); - TheInGameUI->message(string); - - string.format(L"Wave Type: %hs",waveTypeInfo[currentWaveType].m_waveTypeName); - TheInGameUI->message(string); - } - - trackEditMode ^= 1; //toggle editor on/off - - if (trackEditMode == 0) - { //editor was turned off, save changes - haveStart=0; - haveEnd=0; - } - trackEditModeReset=0; - } - } - else - trackEditModeReset=1; - - if (trackEditMode) - { //we are in wave edit mode - - if (GetCursorPos(&screenPoint)) //read mouse position - { - ScreenToClient( ApplicationHWnd, &screenPoint); - - if (GetAsyncKeyState(VK_F6) & 0x8001) - { - if (addPointReset) - { - if (!haveStart) - { mouseAnchor=screenPoint; - TheTacticalView->screenToTerrain( (ICoord2D *)&screenPoint, &terrainPointStart); - haveStart=1; - UnicodeString string; - string.format(L"Added Start"); - TheInGameUI->message(string); - } - else - { - endPoint=screenPoint; - TheTacticalView->screenToTerrain( (ICoord2D *)&screenPoint, &terrainPointEnd); - haveEnd=1; - //Have enough info to add a wave now - track=TheWaterTracksRenderSystem->bindTrack(currentWaveType); - if (track) - {// track->init(1.5f*MAP_XY_FACTOR,Vector2(terrainPointStart.x,terrainPointStart.y),Vector2(terrainPointEnd.x,terrainPointEnd.y),"wave256.tga"); - //Generate valid input for the 2 points - Vector2 startPoint(terrainPointStart.x,terrainPointStart.y); - Vector2 endPoint(terrainPointEnd.x,terrainPointEnd.y); - Vector2 midPoint = endPoint - startPoint; - Vector2 m_perpDir = midPoint; - m_perpDir.Rotate(1.57079632679f); //get vector perpendicular to wave motion. - m_perpDir.Normalize(); - midPoint = startPoint + (midPoint)*0.5f; - Vector2 dirMidPoint = midPoint + m_perpDir; - - track->init(waveTypeInfo[currentWaveType].m_finalHeight,waveTypeInfo[currentWaveType].m_finalWidth,Vector2(midPoint.X,midPoint.Y),Vector2(dirMidPoint.X,dirMidPoint.Y),waveTypeInfo[currentWaveType].m_textureName,0); - - if (waveTypeInfo[currentWaveType].m_secondWaveTimeOffset) - { - //Add a second track slightly behind this one - track2=TheWaterTracksRenderSystem->bindTrack(currentWaveType); - if (track2) - { - track2->init(waveTypeInfo[currentWaveType].m_finalHeight,waveTypeInfo[currentWaveType].m_finalWidth,Vector2(midPoint.X,midPoint.Y),Vector2(dirMidPoint.X,dirMidPoint.Y),waveTypeInfo[currentWaveType].m_textureName,waveTypeInfo[currentWaveType].m_secondWaveTimeOffset); - } - } - - UnicodeString string; - string.format(L"Added End"); - TheInGameUI->message(string); - } - haveStart=0; //reset for next segment - haveEnd=0; - } - addPointReset=0; - } - } - else - addPointReset=1; - - if (GetAsyncKeyState(VK_DELETE) & 0x8001) - { //delete last segment added - if (deleteTrackReset && track) - { deleteTrackReset=0; - TheWaterTracksRenderSystem->unbindTrack(track); - if (track2) - TheWaterTracksRenderSystem->unbindTrack(track2); - haveStart=0; //reset for next segment - haveEnd=0; - track=NULL; - track2=NULL; - } - } - else - deleteTrackReset=1; - - if (GetAsyncKeyState(VK_INSERT) & 0x8001) - { //change current wave type - if (changeTypeReset) - { changeTypeReset=0; - currentWaveType = (waveType)((Int)currentWaveType + 1); - if (currentWaveType > WaveTypeLast) - currentWaveType = WaveTypeFirst; - - UnicodeString string; - string.format(L"Wave Type: %hs",waveTypeInfo[currentWaveType].m_waveTypeName); - TheInGameUI->message(string); - } - } - else - changeTypeReset=1; - - if (GetAsyncKeyState(VK_F7) & 0x8001) - { //save all segments added - if (saveTracksReset) - { saveTracksReset=0; - TheWaterTracksRenderSystem->saveTracks(); - haveStart=0; //reset for next segment - haveEnd=0; - track=NULL; - track2=NULL; - UnicodeString string; - string.format(L"Saved Tracks"); - TheInGameUI->message(string); - } - } - else - saveTracksReset=1; - - if (GetAsyncKeyState(VK_F8) & 0x8001) - { //load tracks for map - if (loadTracksReset) - { loadTracksReset=0; - TheWaterTracksRenderSystem->reset(); - TheWaterTracksRenderSystem->loadTracks(); - haveStart=0; //reset for next segment - haveEnd=0; - track=NULL; - track2=NULL; - UnicodeString string; - string.format(L"Loaded Tracks"); - TheInGameUI->message(string); - } - } - else - saveTracksReset=1; - }; - - if (haveStart && !haveEnd) - { //draw a guide line -// View *tacticalView = TheDisplay->getFirstView(); -// tacticalView->worldToScreen( &m_moveHint[i].pos, &pos ); - - TheTacticalView->screenToTerrain( (ICoord2D *)&screenPoint, &terrainPointEnd); - //Check if point is within correct distance of start - Real xdiff=terrainPointEnd.x - terrainPointStart.x; - Real ydiff=terrainPointEnd.y - terrainPointStart.y; - if (sqrt (xdiff * xdiff + ydiff * ydiff) <= waveTypeInfo[currentWaveType].m_finalWidth) - { TheDisplay->drawLine(mouseAnchor.x, mouseAnchor.y, screenPoint.x, screenPoint.y,1,0xffccccff); - DX8Wrapper::Invalidate_Cached_Render_States(); - ShaderClass::Invalidate(); - } - - pauseWaves=TRUE; - -// char buffer[64]; -// sprintf(buffer,"\n%d,%d,%d,%d",mouseAnchor.x, mouseAnchor.y, screenPoint.x, screenPoint.y); -// OutputDebugString (buffer); - } - } -} diff --git a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/wave.nvp b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/wave.nvp deleted file mode 100644 index 6468dcd0df3..00000000000 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/wave.nvp +++ /dev/null @@ -1,54 +0,0 @@ -; -; 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 . -; - -;//////////////////////////////////////////////////////////////////////////////// -;// // -;// (c) 2001-2003 Electronic Arts Inc. // -;// // -;//////////////////////////////////////////////////////////////////////////////// - -; Waves pixel shader -; Kenny Mitchell April 2001 -; Modified July 2001 Mark Wilczynski - -; Declare pixel shader version 1.1 -ps.1.1 - -; Define t0 as a standard 3-vector from bumpmap -tex t0 - -; Perform EMBM to get a local normal bump reflection. -texbem t1, t0 ; compute new (u,v) values - -#ifndef DO_WATER_ALPHA_TEXTURE - -; result goes in output color multiplied by diffuse -mul r0, t1, v0 - -#else - -;alternate version which uses a third texture which provides per-pixel alpha. -; result goes in output color multiplied by diffuse -tex t2 ; get alpha texture -mul r0.rgb, t1, v0 -+mul r0.a, t2, v0 - -#endif - - - diff --git a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/wave.nvv b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/wave.nvv deleted file mode 100644 index c33486962fc..00000000000 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/wave.nvv +++ /dev/null @@ -1,72 +0,0 @@ -; -; 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 . -; - -;//////////////////////////////////////////////////////////////////////////////// -;// // -;// (c) 2001-2003 Electronic Arts Inc. // -;// // -;//////////////////////////////////////////////////////////////////////////////// - -; Waves vertex shader -; Kenny Mitchell April 2001 -; Modified July 2001 Mark Wilczynski - -#define CV_ZERO 0 -#define CV_ONE 1 - -#define CV_WORLDVIEWPROJ_0 2 -#define CV_WORLDVIEWPROJ_1 3 -#define CV_WORLDVIEWPROJ_2 4 -#define CV_WORLDVIEWPROJ_3 5 - -#define CV_TEXPROJ_0 6 -#define CV_TEXPROJ_1 7 -#define CV_TEXPROJ_2 8 -#define CV_TEXPROJ_3 9 -#define CV_PATCH_SCALE_OFFSET 10 - -#define V_POSITION v0 -#define V_DIFFUSE v1 -#define V_TEXTURE v2 -#define V_TEXTURE2 v3 - -vs.1.1 - -; Below is Kenny's new optimized version -; Transform position to clip space and output it -dp4 r0.x, V_POSITION, c[CV_WORLDVIEWPROJ_0] -dp4 r0.y, V_POSITION, c[CV_WORLDVIEWPROJ_1] -dp4 r0.z, V_POSITION, c[CV_WORLDVIEWPROJ_2] -dp4 r0.w, V_POSITION, c[CV_WORLDVIEWPROJ_3] - -mov oPos, r0 - -; get 1/w and multiply it onto x and y -rcp r1.w, r0.w -mul r1.xy, r0.xy, r1.w - -; scale/flip/offset tex coords to screen -mad oT1.xy, r1.xy, c[CV_TEXPROJ_0].xy,c[CV_TEXPROJ_0].zw - -mov oT0, V_TEXTURE -mov oD0, V_DIFFUSE - -#ifdef DO_WATER_ALPHA_TEXTURE -;generate uv coordinates for a third texture (alpha channel) -mad oT2.xy,v0.xz,c[CV_PATCH_SCALE_OFFSET].zw,c[CV_PATCH_SCALE_OFFSET].xy -#endif diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt b/Generals/Code/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt index 01148543c86..0a51c6d9648 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt @@ -15,8 +15,8 @@ set(WW3D2_SRC #assetstatus.h #bitmaphandler.cpp #bitmaphandler.h - bmp2d.cpp - bmp2d.h + #bmp2d.cpp + #bmp2d.h boxrobj.cpp boxrobj.h #bwrender.cpp @@ -54,8 +54,8 @@ set(WW3D2_SRC #dx8polygonrenderer.h dx8renderer.cpp dx8renderer.h - dx8texman.cpp - dx8texman.h + #dx8texman.cpp + #dx8texman.h dx8vertexbuffer.cpp dx8vertexbuffer.h #dx8webbrowser.cpp @@ -104,8 +104,8 @@ set(WW3D2_SRC mapper.h #matinfo.cpp #matinfo.h - matpass.cpp - matpass.h + #matpass.cpp + #matpass.h matrixmapper.cpp matrixmapper.h mesh.cpp @@ -195,18 +195,18 @@ set(WW3D2_SRC #stripoptimizer.h #surfaceclass.cpp #surfaceclass.h - texproject.cpp - texproject.h + #texproject.cpp + #texproject.h #textdraw.cpp #textdraw.h - texture.cpp - texture.h - texturefilter.cpp - texturefilter.h - textureloader.cpp - textureloader.h - texturethumbnail.cpp - texturethumbnail.h + #texture.cpp + #texture.h + #texturefilter.cpp + #texturefilter.h + #textureloader.cpp + #textureloader.h + #texturethumbnail.cpp + #texturethumbnail.h vertmaterial.cpp vertmaterial.h #visrasterizer.cpp diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/bmp2d.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/bmp2d.cpp deleted file mode 100644 index 8f0ba147a09..00000000000 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/bmp2d.cpp +++ /dev/null @@ -1,299 +0,0 @@ -/* -** 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 . -*/ - -/*************************************************************************** - *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** - *************************************************************************** - * * - * Project Name : Commando/G * - * * - * $Archive:: /Commando/Code/ww3d2/bmp2d.cpp $* - * * - * $Org Author:: Jani_p $* - * * - * $Author:: Kenny_m $* - * * - * $Modtime:: 08/05/02 10:44a $* - * * - * $Revision:: 12 $* - * * - * 08/05/02 KM Texture class redesign - *-------------------------------------------------------------------------* - * Functions: * - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - -#include "bmp2d.h" -#include "pot.h" -#include "ww3d.h" -#include "texture.h" -#include "surfaceclass.h" -#include "assetmgr.h" -#include "textureloader.h" -#include "ww3dformat.h" - -Bitmap2DObjClass::Bitmap2DObjClass -( - const char *filename, - float screen_x, - float screen_y, - bool center, - bool additive, - bool colorizable, - int usable_width, - int usable_height, - bool ignore_alpha -) - : DynamicScreenMeshClass(2, 4) -{ - - int resw, resh, resbits; - bool windowed; - - // find the resolution (for centering and pixel to pixel translation) - WW3D::Get_Device_Resolution(resw, resh, resbits, windowed); - // This should be the correct way to do things - // but other code expects an aspect ratio of 1.0 - // Hector Yee 2/22/01 - // Set_Aspect(resh/(float)resw); - - - // load up the surfaces file name - TextureClass *tex = WW3DAssetManager::Get_Instance()->Get_Texture(filename, MIP_LEVELS_1); - if (!tex->Is_Initialized()) - TextureLoader::Request_Foreground_Loading(tex); - - SurfaceClass *surface = tex->Get_Surface_Level(0); - - if (!surface) { - surface = NEW_REF(SurfaceClass, (32, 32, Get_Valid_Texture_Format(WW3D_FORMAT_R8G8B8,true))); - } - - SurfaceClass::SurfaceDescription sd; - surface->Get_Description(sd); - - if (usable_width == -1) - usable_width = sd.Width; - if (usable_height == -1) - usable_height = sd.Height; - - // if we requested the image to be centered around a point adjust the - // coordinates accordingly. - if (center) { - screen_x -= ((float)usable_width / resw) / 2; - screen_y -= ((float)usable_height / resh) / 2; - } - - // The image will be broken down into square textures. The size of these - // textures will be the smallest POT (power of two) which is equal or - // greater than the smaller dimension of the image. Also, the pieces can - // never be larger than 256 texels because some rendering devices don't - // support textures larger than that. - int surf_w = usable_width; - int surf_h = usable_height; - int piece = Find_POT(MIN(surf_w, surf_h)); - piece = MIN(piece, 256); - - // now take the image in question and break it down into - // "piece"x"piece"-pixel polygons and calculate the number of textures - // based from those calculations. - int mw = (surf_w & (piece - 1)) ? (surf_w / piece)+1 : (surf_w /piece); - int mh = (surf_h & (piece - 1)) ? (surf_h / piece)+1 : (surf_h /piece); - - // for every square texture it takes four vertexes to express the two - // polygons. - Resize(mw * mh *2, mw * mh * 4); - - // Set shader to additive if requested, else alpha or opaque depending on - // whether the texture has an alpha channel. Sorting is always set so that - // sortbias can be used to determine occlusion between the various 2D - // elements. - ShaderClass shader; - - if (additive) { - shader = ShaderClass::_PresetAdditive2DShader; - } else { - if (ignore_alpha == false && Has_Alpha(sd.Format)) { - shader = ShaderClass::_PresetAlpha2DShader; - } else { - shader = ShaderClass::_PresetOpaque2DShader; - } - } - - Enable_Sort(); - - - // If we want to be able to colorize this bitmap later (by setting - // emissive color for the vertex material, or via a vertex emissive color - // array) we need to enable the primary gradient in the shader (it is - // disabled in the 2D presets), and set an appropriate vertex material. - if (colorizable) { - shader.Set_Primary_Gradient(ShaderClass::GRADIENT_MODULATE); - VertexMaterialClass *vertex_material = NEW_REF( VertexMaterialClass, ()); - vertex_material->Set_Ambient(0.0f, 0.0f, 0.0f); - vertex_material->Set_Diffuse(0.0f, 0.0f, 0.0f); - vertex_material->Set_Specular(0.0f, 0.0f, 0.0f); - vertex_material->Set_Emissive(1.0f, 1.0f, 1.0f); - Set_Vertex_Material(vertex_material, true); - vertex_material->Release_Ref(); - } - - // Set desired shader. - Set_Shader(shader); - - // loop through the rows and columns of the image and make valid - // textures from the pieces. - for (int lpy = 0, tlpy=0; lpy < mh; lpy++, tlpy += piece) { - for (int lpx = 0, tlpx = 0; lpx < mw; lpx++, tlpx += piece) { - - // figure the desired width and height of the texture (max "piece") - int iw = MIN(piece, usable_width - (tlpx)); - int ih = MIN(piece, usable_height - (tlpy)); - int pot = MAX(Find_POT(iw), Find_POT(ih)); - - // create the texture and turn MIP-mapping off. - SurfaceClass *piece_surface=NEW_REF(SurfaceClass,(pot,pot,sd.Format)); - piece_surface->Copy(0,0,tlpx,tlpy,pot,pot,surface); - TextureClass *piece_texture =NEW_REF(TextureClass,(piece_surface,MIP_LEVELS_1)); - piece_texture->Get_Filter().Set_U_Addr_Mode(TextureFilterClass::TEXTURE_ADDRESS_CLAMP); - piece_texture->Get_Filter().Set_V_Addr_Mode(TextureFilterClass::TEXTURE_ADDRESS_CLAMP); - REF_PTR_RELEASE(piece_surface); - - // calculate our actual texture coordinates based on the difference between - // the width and height of the texture and the width and height the font - // occupys. - float tw = (float)iw / (float)pot; - float th = (float)ih / (float)pot; - - // convert image width and image height to normalized values - float vw = (float)iw / (float)resw; - float vh = (float)ih / (float)resh; - - // figure out the screen space x and y positions of the object in question. - float x = screen_x + (((float)tlpx) / (float)resw); - float y = screen_y + (((float)tlpy) / (float)resh); - - Set_Texture(piece_texture); - Begin_Tri_Strip(); - Vertex( x, y, 0, 0, 0); - Vertex( x + vw, y, 0, tw, 0); - Vertex( x, y + vh, 0, 0, th); - Vertex( x + vw, y + vh, 0, tw, th); - End_Tri_Strip(); - - // release our reference to the texture - REF_PTR_RELEASE(piece_texture); - } - } - REF_PTR_RELEASE(tex); - REF_PTR_RELEASE(surface); - - Set_Dirty(); -} - -Bitmap2DObjClass::Bitmap2DObjClass -( - TextureClass *texture, - float screen_x, - float screen_y, - bool center, - bool additive, - bool colorizable, - bool ignore_alpha -) - : DynamicScreenMeshClass(2, 4) -{ - int resw, resh, resbits; - bool windowed; - - // find the resolution (for centering and pixel to pixel translation) - WW3D::Get_Device_Resolution(resw, resh, resbits, windowed); - // This should be the correct way to do things - // but other code expects an aspect ratio of 1.0 - // Hector Yee 2/22/01 - //Set_Aspect(resh/(float)resw); - - // Find the dimensions of the texture: -// SurfaceClass::SurfaceDescription sd; -// texture->Get_Level_Description(sd); - - if (!texture->Is_Initialized()) - TextureLoader::Request_Foreground_Loading(texture); - - // convert image width and image height to normalized values - float vw = (float) texture->Get_Width() / (float)resw; - float vh = (float) texture->Get_Height() / (float)resh; - - // if we requested the image to be centered around a point adjust the - // coordinates accordingly. - if (center) { - screen_x -= vw / 2; - screen_y -= vh / 2; - } - - // Set shader to additive if requested, else alpha or opaque depending on whether the texture - // has an alpha channel. Sorting is never set - if you wish to sort these types of objects you - // should use static sort levels (note that static sort levels are not implemented for these - // objects yet, but it should be very simple to do). - ShaderClass shader; - - if (additive) { - shader = ShaderClass::_PresetAdditive2DShader; - } else { - if (ignore_alpha == false && Has_Alpha(texture->Get_Texture_Format())) { - shader = ShaderClass::_PresetAlpha2DShader; - } else { - shader = ShaderClass::_PresetOpaque2DShader; - } - } - Disable_Sort(); - - // If we want to be able to colorize this bitmap later (by setting - // emissive color for the vertex material, or via a vertex emissive color - // array) we need to enable the primary gradient in the shader (it is - // disabled in the 2D presets), and set an appropriate vertex material. - if (colorizable) { - shader.Set_Primary_Gradient(ShaderClass::GRADIENT_MODULATE); - VertexMaterialClass *vertex_material = NEW_REF( VertexMaterialClass, ()); - vertex_material->Set_Ambient(0.0f, 0.0f, 0.0f); - vertex_material->Set_Diffuse(0.0f, 0.0f, 0.0f); - vertex_material->Set_Specular(0.0f, 0.0f, 0.0f); - vertex_material->Set_Emissive(1.0f, 1.0f, 1.0f); - Set_Vertex_Material(vertex_material, true); - vertex_material->Release_Ref(); - } - - // Set desired shader. - Set_Shader(shader); - - // Set texture to requested texture: - Set_Texture(texture); - - Begin_Tri_Strip(); - Vertex( screen_x, screen_y, 0, 0, 0); - Vertex( screen_x + vw, screen_y, 0, 1.0, 0); - Vertex( screen_x, screen_y + vh, 0, 0, 1.0); - Vertex( screen_x + vw, screen_y + vh, 0, 1.0, 1.0); - End_Tri_Strip(); - - Set_Dirty(); -} - -RenderObjClass * Bitmap2DObjClass::Clone(void) const -{ - return NEW_REF( Bitmap2DObjClass, (*this)); -} diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/bmp2d.h b/Generals/Code/Libraries/Source/WWVegas/WW3D2/bmp2d.h deleted file mode 100644 index b09e595ecbe..00000000000 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/bmp2d.h +++ /dev/null @@ -1,52 +0,0 @@ -/* -** 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 . -*/ - -/*************************************************************************** - *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** - *************************************************************************** - * * - * Project Name : Commando/G * - * * - * $Archive:: /Commando/Code/ww3d2/bmp2d.h $* - * * - * $Author:: Hector_y $* - * * - * $Modtime:: 2/21/01 1:31p $* - * * - * $Revision:: 3 $* - * * - *-------------------------------------------------------------------------* - * Functions: * - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - -#pragma once - -#include "dynamesh.h" - -class Bitmap2DObjClass : public DynamicScreenMeshClass -{ - public: - Bitmap2DObjClass(const char *filename, float norm_x, float norm_y, - bool center, bool additive, bool colorizable = false, int width = -1, int height = -1, bool ignore_alpha = false); - Bitmap2DObjClass(TextureClass *texture, float norm_x, float norm_y, - bool center, bool additive, bool colorizable = false, bool ignore_alpha = false); - Bitmap2DObjClass( const Bitmap2DObjClass & src) : DynamicScreenMeshClass(src) {} - - virtual RenderObjClass * Clone(void) const; - virtual int Class_ID(void) const { return CLASSID_BITMAP2D; } -}; diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8texman.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8texman.cpp deleted file mode 100644 index 0d66a497ae6..00000000000 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8texman.cpp +++ /dev/null @@ -1,198 +0,0 @@ -/* -** 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 . -*/ - -/*********************************************************************************************** - *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** - *********************************************************************************************** - * * - * Project Name : DX8 Texture Manager * - * * - * $Archive:: /Commando/Code/ww3d2/dx8texman.cpp $* - * * - * Original Author:: Hector Yee * - * * - * Author : Kenny Mitchell * - * * - * $Modtime:: 06/27/02 1:27p $* - * * - * $Revision:: 4 $* - * * - * 06/27/02 KM Texture class abstraction * - *---------------------------------------------------------------------------------------------* - * Functions: * - * DX8TextureManagerClass::Shutdown -- Shuts down the texture manager * - * DX8TextureManagerClass::Add -- Adds a texture to be managed * - * DX8TextureManagerClass::Remove -- Removes a texture from being managed * - * DX8TextureManagerClass::Release_Textures -- Releases the internal d3d texture * - * DX8TextureManagerClass::Recreate_Textures -- Reallocates lost textures * - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - - -// This class manages textures that are in the default pool -// ensuring that they are released on device loss -// and created on device reset - -// Note: It does NOT addref to textures because it is called in the texture -// destructor - -#include "dx8texman.h" - -TextureTrackerList DX8TextureManagerClass::Managed_Textures; - - -/*********************************************************************************************** - * DX8TextureManagerClass::Shutdown -- Shuts down the texture manager * - * * - * * - * * - * * - * INPUT: * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 4/25/2001 hy : Created. * - * 5/16/2002 km : Added depth stencil texture tracking and abstraction * - *=============================================================================================*/ -void DX8TextureManagerClass::Shutdown() -{ - while (!Managed_Textures.Is_Empty()) - { - TextureTrackerClass *track=Managed_Textures.Remove_Head(); - delete track; - } -} - -/*********************************************************************************************** - * DX8TextureManagerClass::Add -- Adds a texture to be managed * - * * - * * - * * - * * - * INPUT: * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 4/25/2001 hy : Created. * - * 5/16/2002 km : Added depth stencil texture tracking and abstraction * - *=============================================================================================*/ -void DX8TextureManagerClass::Add(TextureTrackerClass *track) -{ - // this function should only be called by the texture constructor - Managed_Textures.Add(track); -} - - -/*********************************************************************************************** - * DX8TextureManagerClass::Remove -- Removes a texture from being managed * - * * - * * - * * - * * - * INPUT: * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 4/25/2001 hy : Created. * - * 5/16/2002 km : Added depth stencil texture tracking and abstraction * - *=============================================================================================*/ -void DX8TextureManagerClass::Remove(TextureBaseClass *tex) -{ - // this function should only be called by the texture destructor - TextureTrackerListIterator it(&Managed_Textures); - - while (!it.Is_Done()) - { - TextureTrackerClass *track=it.Peek_Obj(); - if (track->Get_Texture()==tex) - { - it.Remove_Current_Object(); - delete track; - break; - } - it.Next(); - } -} - - -/*********************************************************************************************** - * DX8TextureManagerClass::Release_Textures -- Releases the internal d3d texture * - * * - * * - * * - * * - * INPUT: * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 4/25/2001 hy : Created. * - * 5/16/2002 km : Added depth stencil texture tracking and abstraction * - *=============================================================================================*/ -void DX8TextureManagerClass::Release_Textures() -{ - TextureTrackerListIterator it(&Managed_Textures); - - while (!it.Is_Done()) - { - TextureTrackerClass *track=it.Peek_Obj(); - track->Release(); - it.Next(); - } -} - - -/*********************************************************************************************** - * DX8TextureManagerClass::Recreate_Textures -- Reallocates lost textures * - * * - * * - * * - * * - * INPUT: * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 4/25/2001 hy : Created. * - * 5/16/2002 km : Added depth stencil texture tracking and abstraction * - *=============================================================================================*/ -void DX8TextureManagerClass::Recreate_Textures() -{ - TextureTrackerListIterator it(&Managed_Textures); - - while (!it.Is_Done()) - { - TextureTrackerClass *track=it.Peek_Obj(); - track->Recreate(); - track->Get_Texture()->Set_Dirty(); - it.Next(); - } -} - diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8texman.h b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8texman.h deleted file mode 100644 index bc188322071..00000000000 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8texman.h +++ /dev/null @@ -1,171 +0,0 @@ -/* -** 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 . -*/ - -/*********************************************************************************************** - *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** - *********************************************************************************************** - * * - * Project Name : DX8 Texture Manager * - * * - * $Archive:: /Commando/Code/ww3d2/dx8texman.h $* - * * - * Original Author:: Hector Yee * - * * - * Author : Kenny Mitchell * - * * - * $Modtime:: 06/27/02 1:27p $* - * * - * $Revision:: 4 $* - * * - * 06/27/02 KM Texture class abstraction * - *---------------------------------------------------------------------------------------------* - * Functions: * - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - -#pragma once - -#include "always.h" -#include "texture.h" -#include "dx8wrapper.h" -#include "ww3dformat.h" -#include "dx8list.h" -#include "multilist.h" - -class DX8TextureManagerClass; - -class TextureTrackerClass : public MultiListObjectClass -{ -public: - TextureTrackerClass - ( - unsigned int w, - unsigned int h, - MipCountType count, - TextureBaseClass *tex - ) - : Width(w), - Height(h), - Mip_level_count(count), - Texture(tex) - { - } - - virtual void Recreate() const =0; - - void Release() - { - Texture->Set_D3D_Base_Texture(NULL); - } - - TextureBaseClass* Get_Texture() const { return Texture; } - - -protected: - - unsigned int Width; - unsigned int Height; - MipCountType Mip_level_count; - TextureBaseClass *Texture; -}; - -class DX8TextureTrackerClass : public TextureTrackerClass -{ -public: - DX8TextureTrackerClass - ( - unsigned int w, - unsigned int h, - WW3DFormat format, - MipCountType count, - TextureBaseClass *tex, - bool rt - ) - : TextureTrackerClass(w,h,count,tex), Format(format), RenderTarget(rt) - { - } - - virtual void Recreate() const - { - WWASSERT(Texture->Peek_D3D_Base_Texture()==NULL); - Texture->Poke_Texture - ( - DX8Wrapper::_Create_DX8_Texture - ( - Width, - Height, - Format, - Mip_level_count, - D3DPOOL_DEFAULT, - RenderTarget - ) - ); - } - -private: - WW3DFormat Format; - bool RenderTarget; -}; - -class DX8ZTextureTrackerClass : public TextureTrackerClass -{ -public: - DX8ZTextureTrackerClass - ( - unsigned int w, - unsigned int h, - WW3DZFormat zformat, - MipCountType count, - TextureBaseClass* tex - ) - : TextureTrackerClass(w,h,count,tex), ZFormat(zformat) - { - } - - virtual void Recreate() const - { - WWASSERT(Texture->Peek_D3D_Base_Texture()==NULL); - Texture->Poke_Texture - ( - DX8Wrapper::_Create_DX8_ZTexture - ( - Width, - Height, - ZFormat, - Mip_level_count, - D3DPOOL_DEFAULT - ) - ); - } - - -private: - WW3DZFormat ZFormat; -}; - - -class DX8TextureManagerClass -{ -public: - static void Shutdown(); - static void Add(TextureTrackerClass *track); - static void Remove(TextureBaseClass *tex); - static void Release_Textures(); - static void Recreate_Textures(); -private: - static TextureTrackerList Managed_Textures; -}; diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/matpass.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/matpass.cpp deleted file mode 100644 index d7fc3aa660a..00000000000 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/matpass.cpp +++ /dev/null @@ -1,234 +0,0 @@ -/* -** 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 . -*/ - -/*********************************************************************************************** - *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** - *********************************************************************************************** - * * - * Project Name : WW3d * - * * - * $Archive:: /Commando/Code/ww3d2/matpass.cpp $* - * * - * Original Author:: Greg Hjelstrom * - * * - * Author : Kenny Mitchell * - * * - * $Modtime:: 06/27/02 1:27p $* - * * - * $Revision:: 8 $* - * * - * 06/27/02 KM Changes to max texture stage caps * - *---------------------------------------------------------------------------------------------* - * Functions: * - * MaterialPassClass::MaterialPassClass -- Constructor * - * MaterialPassClass::~MaterialPassClass -- Destructor * - * MaterialPassClass::Install_Materials -- Plug our material settings into D3D * - * MaterialPassClass::Set_Texture -- Set texture to use * - * MaterialPassClass::Set_Shader -- Set the shader to use * - * MaterialPassClass::Set_Material -- set vertex material to use * - * MaterialPassClass::Get_Texture -- Get a pointer to the texture * - * MaterialPassClass::Get_Material -- get the vertex material * - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - - -#include "matpass.h" -#include "vertmaterial.h" -#include "shader.h" -#include "texture.h" -#include "statistics.h" -#include "dx8wrapper.h" - - -bool MaterialPassClass::EnablePerPolygonCulling = true; - - -/*********************************************************************************************** - * MaterialPassClass::MaterialPassClass -- Constructor * - * * - * INPUT: * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 2/26/2001 gth : Created. * - *=============================================================================================*/ -MaterialPassClass::MaterialPassClass(void) : - Shader(0), - Material(NULL), - CullVolume(NULL), - EnableOnTranslucentMeshes(true) -{ - for (int i=0; iGet_Max_Textures_Per_Pass();++i) - { - DX8Wrapper::Set_Texture(i,Peek_Texture(i)); - } -} - - -/*********************************************************************************************** - * MaterialPassClass::Set_Texture -- Set texture to use * - * * - * INPUT: * - * tex - pointer to the texture for this material pass (or NULL) * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 12/9/99 gth : Created. * - *=============================================================================================*/ -void MaterialPassClass::Set_Texture(TextureClass * tex,int stage) -{ - WWASSERT(stage >= 0); - WWASSERT(stage < MAX_TEX_STAGES); - - REF_PTR_SET(Texture[stage],tex); -} - - -/*********************************************************************************************** - * MaterialPassClass::Set_Shader -- Set the shader to use * - * * - * INPUT: * - * shader - shader for this material pass * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 12/9/99 gth : Created. * - *=============================================================================================*/ -void MaterialPassClass::Set_Shader(ShaderClass shader) -{ - Shader = shader; - Shader.Enable_Fog ("MaterialPassClass"); -} - - -/*********************************************************************************************** - * MaterialPassClass::Set_Material -- set vertex material to use * - * * - * INPUT: * - * mat - pointer to the vertex material this material pass uses * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 12/9/99 gth : Created. * - *=============================================================================================*/ -void MaterialPassClass::Set_Material(VertexMaterialClass * mat) -{ - REF_PTR_SET(Material,mat); -} - - -/*********************************************************************************************** - * MaterialPassClass::Get_Texture -- Get a pointer to the texture * - * * - * INPUT: * - * * - * OUTPUT: * - * reference counted pointer to the texture this material pass is using * - * * - * WARNINGS: * - * * - * HISTORY: * - * 12/9/99 gth : Created. * - *=============================================================================================*/ -TextureClass * MaterialPassClass::Get_Texture(int stage) const -{ - WWASSERT(stage >= 0); - WWASSERT(stage < MAX_TEX_STAGES); - - if (Texture[stage]) { - Texture[stage]->Add_Ref(); - } - return Texture[stage]; -} - - -/*********************************************************************************************** - * MaterialPassClass::Get_Material -- get the vertex material * - * * - * INPUT: * - * * - * OUTPUT: * - * reference counted pointer to the vertex material being used by this material pass * - * * - * WARNINGS: * - * * - * HISTORY: * - * 12/9/99 gth : Created. * - *=============================================================================================*/ -VertexMaterialClass * MaterialPassClass::Get_Material(void) const -{ - if (Material) { - Material->Add_Ref(); - } - return Material; -} diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/matpass.h b/Generals/Code/Libraries/Source/WWVegas/WW3D2/matpass.h deleted file mode 100644 index afa22264645..00000000000 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/matpass.h +++ /dev/null @@ -1,114 +0,0 @@ -/* -** 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 . -*/ - -/*********************************************************************************************** - *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** - *********************************************************************************************** - * * - * Project Name : ww3d * - * * - * $Archive:: /Commando/Code/ww3d2/matpass.h $* - * * - * Original Author:: Greg Hjelstrom * - * * - * Author : Kenny Mitchell * - * * - * $Modtime:: 06/27/02 1:27p $* - * * - * $Revision:: 6 $* - * * - * 06/27/02 KM Texture class abstraction * - *---------------------------------------------------------------------------------------------* - * Functions: * - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - -#pragma once - -#include "always.h" -#include "shader.h" - -class TextureClass; -class VertexMaterialClass; -class MeshModelClass; -class OBBoxClass; - -/** -** MaterialPassClass -** -** This class wraps all of the data needed to describe an additional -** material pass for any object. The motivation for this class is to -** implement certain types of special effects. All data needed to -** apply the pass should be generated procedurally. Typically a -** vertex processor will be used to generate any needed u-v's or vertex -** colors. Alternatively, we could add the option to request to -** re-use the model's existing u-v's or vertex colors. -** -** -*/ -class MaterialPassClass : public RefCountClass -{ -public: - - MaterialPassClass(void); - ~MaterialPassClass(void); - - /// MW: Had to make this virtual so app can perform direct/custom D3D setup. - virtual void Install_Materials(void) const; - virtual void UnInstall_Materials(void) const { }; ///< reset/cleanup D3D states - - void Set_Texture(TextureClass * Texture,int stage = 0); - void Set_Shader(ShaderClass shader); - void Set_Material(VertexMaterialClass * mat); - - TextureClass * Get_Texture(int stage = 0) const; - VertexMaterialClass * Get_Material(void) const; - - TextureClass * Peek_Texture(int stage = 0) const; - ShaderClass Peek_Shader(void) const { return Shader; } - VertexMaterialClass * Peek_Material(void) const { return Material; } - - void Set_Cull_Volume(OBBoxClass * volume) { CullVolume = volume; } - OBBoxClass * Get_Cull_Volume(void) const { return CullVolume; } - - void Enable_On_Translucent_Meshes(bool onoff) { EnableOnTranslucentMeshes = onoff; } - bool Is_Enabled_On_Translucent_Meshes(void) { return EnableOnTranslucentMeshes; } - - static void Enable_Per_Polygon_Culling(bool onoff) { EnablePerPolygonCulling = onoff; } - static bool Is_Per_Polygon_Culling_Enabled(void) { return EnablePerPolygonCulling; } - -protected: - - enum { MAX_TEX_STAGES = 8 }; - - TextureClass * Texture[MAX_TEX_STAGES]; - ShaderClass Shader; - VertexMaterialClass * Material; - bool EnableOnTranslucentMeshes; - - OBBoxClass * CullVolume; - static bool EnablePerPolygonCulling; - -}; - - -inline TextureClass * MaterialPassClass::Peek_Texture(int stage) const -{ - WWASSERT(stage >= 0); - WWASSERT(stage < MAX_TEX_STAGES); - return Texture[stage]; -} diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/texproject.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/texproject.cpp deleted file mode 100644 index 79ea6d9804b..00000000000 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/texproject.cpp +++ /dev/null @@ -1,1389 +0,0 @@ -/* -** 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 . -*/ - -/*********************************************************************************************** - *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** - *********************************************************************************************** - * * - * Project Name : WW3D * - * * - * $Archive:: /Commando/Code/ww3d2/texproject.cpp $* - * * - * Original Author:: Greg Hjelstrom * - * * - * $Author:: Kenny Mitchell * - * * - * $Modtime:: 08/05/02 10:03a $* - * * - * $Revision:: 22 $* - * * - * 06/26/02 KM Matrix name change to avoid MAX conflicts * - * 06/27/02 KM Render to shadow buffer texture support * - * 08/05/02 KM Texture class redesign - *---------------------------------------------------------------------------------------------* - * Functions: * - * TexProjectClass::TexProjectClass -- Constructor * - * TexProjectClass::~TexProjectClass -- Destructor * - * TexProjectClass::Set_Texture_Size -- Set the size of texture to use * - * TexProjectClass::Get_Texture_Size -- Returns the stored texture size * - * TexProjectClass::Set_Flag -- Turn specified flag on or off * - * TexProjectClass::Get_Flag -- Get the current state of specified flag * - * TexProjectClass::Set_Intensity -- Set the intensity of this projector * - * TexProjectClass::Get_Intensity -- returns the current "desired" intensity * - * TexProjectClass::Set_Attenuation -- Set the attenuation factor * - * TexProjectClass::Get_Attenuation -- Returns the attenuation value * - * TexProjectClass::Enable_Attenuation -- Set the state of the ATTENUATE flag * - * TexProjectClass::Is_Attenuation_Enabled -- Get the state of the ATTENUATE flag * - * TexProjectClass::Is_Depth_Gradient_Enabled -- returns whether the depth gradient is enabl * - * TexProjectClass::Enable_Depth_Gradient -- enable/disable depth gradient * - * TexProjectClass::Init_Multiplicative -- Initialize this to be a multiplicative texture pr * - * TexProjectClass::Is_Intensity_Zero -- check if we can eliminate this projector * - * TexProjectClass::Init_Additive -- Set up the projector to be additive * - * TexProjectClass::Set_Perspective_Projection -- Set up a perspective projection * - * TexProjectClass::Set_Ortho_Projection -- Set up an orthographic projection * - * TexProjectClass::Set_Texture -- Set the texture to be projected * - * TexProjectClass::Get_Texture -- Returns the texture being projected * - * TexProjectClass::Peek_Texture -- Returns the texture being projected * - * TexProjectClass::Peek_Material_Pass -- Returns the material pass object * - * TexProjectClass::Compute_Perspective_Projection -- Set up a perspective projection of an * - * TexProjectClass::Compute_Perspective_Projection -- Set up a perspective projection of an * - * TexProjectClass::Compute_Ortho_Projection -- Automatic Orthographic projection * - * TexProjectClass::Compute_Ortho_Projection -- Automatic Orthographic projection * - * TexProjectClass::Compute_Texture -- Generates texture by rendering an object * - * TexProjectClass::Configure_Camera -- setup a camera to match this projector * - * TexProjectClass::Pre_Render_Update -- Prepare the projector for rendering * - * TexProjectClass::Update_WS_Bounding_Volume -- Recalculate the world-space bounding box * - * TexProjectClass::Get_Surface -- Returns pointer to the texture surface * - * TexProjectClass::Set_Render_Target -- Install a render target for this projector to use * - * TexProjectClass::Needs_Render_Target -- returns wheter this projector needs a render targ * - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - - -#include "texproject.h" -#include "vertmaterial.h" -#include "shader.h" -#include "texture.h" -#include "rendobj.h" -#include "rinfo.h" -#include "camera.h" -#include "matpass.h" -#include "bwrender.h" -#include "assetmgr.h" -#include "dx8wrapper.h" - - -// DEBUG DEBUG -#include "MPU.h" - -#define DEBUG_SHADOW_RENDERING 0 -//#define DEFAULT_TEXTURE_SIZE 64 - -const float INTENSITY_RATE_OF_CHANGE = 1.0f; // change in intensity per second - - -/* -** -** Shadow mapping: from pre-projected view coordinates back to world space -** then to shadow space -** -** (1) Vshadow = PShadow * Mwrld-shadow * Vwrld -** -** (2) Vview = Mwrld-camera * Vwrld -** -** Using (2) to solve for Vwrld in terms of Vview -** -1 -** (3) Mwrld-camera * Vview = Vwrld -** -** Substituting (3) into (1) -** -1 -** (4) Vshadow = Pshadow * Mwrld-shadow * Mwrld-camera * Vview -** -** --------------------------------------------------------------------------------- -** -** Shadow mapping: from pre-projected view space to world space, to shadow space, -** then projecting. -** -** (1) Vshadow = Mwrld-shadow * Vwrld -** -** (2) Vview = Mwrld-camera * Vwrld -** -** solving (2) for Vwrld: -** -1 -** (3) Mwrld-camera * Vview = Vwrld -** -** substitute into (1) -** -1 -** (4) Vshadow = Mwrld-shadow * Mwrld-camera * Vview -** -** project shadow -** -1 -** (5) Vproj-shadow = Pshadow * (Mwrld-shadow * Mwrld-camera ) * Vview -** -** aaah! same thing :-) -** -** --------------------------------------------------------------------------------- -** -** Shadow mapping: from pre-projected view coordinates back to obj space -** then to shadow space -** -** (1) Vshadow = PShadow * Mwrld-shadow * Mobj-wrld * Vobj -** -** (2) Vview = Mwrld-camera * Mobj-wrld * Vobj -** -1 -1 -** (3) Mobj-wrld * Mwrld-camera * Vview = Vobj -** -1 -1 -** (4) Vshadow = PShadow * Mwrld-shadow * Mobj-wrld * Mobj-wrld * Mwrld-camera * Vview -** -1 -** (5) Vshadow = PShadow * Mwrld-shadow * Mvrld-camera * Vview -** -** -** Ideas: -** - Use Texture Projectors to implement spot lights and stained glass windows -** - Attenuate texture projections with distance from the projector -** - Should be able to handle lots of pre-calculated static texture projectors. They -** should cull well and we can pre-generate the textures. -** -** Ideas maybe used in conjunction with texture projections: -** - Light volumes: the problem is when the volume is cliped it looks funny, we can -** fill in the clipped face of a non-translucent object by rendering the backfaces -** - Use the backface-fill to make the camera slicing through the commando look like -** its *really* slicing through the commando :-) -** - The back-face-fill trick might be able to use el-cheapo screen mapping! -** -*/ - - - -/*********************************************************************************************** - * TexProjectClass::TexProjectClass -- Constructor * - * * - * INPUT: * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 1/4/00 gth : Created. * - *=============================================================================================*/ -TexProjectClass::TexProjectClass(void) : - Flags(DEFAULT_FLAGS), - DesiredIntensity(1.0f), - Intensity(1.0f), - Attenuation(1.0f), - MaterialPass(NULL), - Mapper1(NULL), - RenderTarget(NULL), - DepthStencilTarget(NULL), - HFov(90.0f), - VFov(90.0f), - XMin(-10.0f), - XMax(10.0f), - YMin(-10.0f), - YMax(10.0f), - ZNear(1.0f), - ZFar(1000.0f) -{ - // create a material pass class - MaterialPass = NEW_REF(MaterialPassClass,()); - MaterialPass->Set_Cull_Volume(&WorldBoundingVolume); - - // create a vertex material - VertexMaterialClass * vmtl = NEW_REF(VertexMaterialClass,()); - WWASSERT(vmtl != NULL); - - // Plug our parent's mapper into our vertex material - // the mapper for stage1 will be allocated as needed - vmtl->Set_Mapper(Mapper); - - MaterialPass->Set_Material(vmtl); - vmtl->Release_Ref(); - vmtl = NULL; - - // by default init our material pass to be multiplicative (shadow) - Init_Multiplicative(); -} - - -/*********************************************************************************************** - * TexProjectClass::~TexProjectClass -- Destructor * - * * - * INPUT: * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 1/4/00 gth : Created. * - *=============================================================================================*/ -TexProjectClass::~TexProjectClass(void) -{ - REF_PTR_RELEASE(Mapper1); - REF_PTR_RELEASE(MaterialPass); - REF_PTR_RELEASE(RenderTarget); - REF_PTR_RELEASE(DepthStencilTarget); -} - - -/*********************************************************************************************** - * TexProjectClass::Set_Texture_Size -- Set the size of texture to use * - * * - * This function stores the desired texture size in this TexProjectClass. Note that * - * this size is only used if you have the TexProjectClass generate a texture. * - * * - * INPUT: * - * size - dimension of the texture in pixels * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 1/4/00 gth : Created. * - *=============================================================================================*/ -void TexProjectClass::Set_Texture_Size(int size) -{ - WWASSERT(size > 0); - WWASSERT(size <= 512); - Flags &= ~SIZE_MASK; - Flags |= (size << SIZE_SHIFT); -} - - -/*********************************************************************************************** - * TexProjectClass::Get_Texture_Size -- Returns the stored texture size * - * * - * Returns the size stored in the flags variable. This can be different than the actual * - * texture's size if you manually installed a texture. This size is only used when * - * automatically generating a texture as is the case when creating shadows. * - * * - * INPUT: * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 1/4/00 gth : Created. * - *=============================================================================================*/ -int TexProjectClass::Get_Texture_Size(void) -{ - return (Flags & SIZE_MASK) >> SIZE_SHIFT; -} - - -/*********************************************************************************************** - * TexProjectClass::Set_Flag -- Turn specified flag on or off * - * * - * See the TexProjectClass header file for valid flags * - * * - * INPUT: * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 1/4/00 gth : Created. * - *=============================================================================================*/ -void TexProjectClass::Set_Flag(uint32 flag,bool onoff) -{ - if (onoff) { - Flags |= flag; - } else { - Flags &= ~flag; - } -} - - -/*********************************************************************************************** - * TexProjectClass::Get_Flag -- Get the current state of specified flag * - * * - * See the TexProjectClass header file for valid flags * - * * - * INPUT: * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 1/4/00 gth : Created. * - *=============================================================================================*/ -bool TexProjectClass::Get_Flag(uint32 flag) const -{ - return (Flags & flag) == flag; -} - - -/*********************************************************************************************** - * TexProjectClass::Set_Intensity -- Set the intensity of this projector * - * * - * The "intensity" is a value between 0 and 1. At 0, the projector will have no effect * - * At 1, the projector will be at its highest strength. The intensity will automatically * - * smoothly interpolate towards the value specified unless you use the immediate option. * - * * - * INPUT: * - * intensity - desired intensity, 0 <= intensity <= 1 * - * immediate - should the intensity be immediately set to the desired value? (default = false) * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 1/4/00 gth : Created. * - *=============================================================================================*/ -void TexProjectClass::Set_Intensity(float intensity,bool immediate) -{ - WWASSERT(intensity <= 1.0f); - WWASSERT(intensity >= 0.0f); - - DesiredIntensity = intensity; - if (immediate) { - Intensity = DesiredIntensity; - } -} - - -/*********************************************************************************************** - * TexProjectClass::Get_Intensity -- returns the current "desired" intensity * - * * - * This will return the last value that was sent into this object through Set_Intensity. * - * Note however that the actual intensity used in rendering may not have arrived at * - * that value yet. * - * * - * INPUT: * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 1/4/00 gth : Created. * - *=============================================================================================*/ -float TexProjectClass::Get_Intensity(void) -{ - return DesiredIntensity; -} - - -/*********************************************************************************************** - * TexProjectClass::Is_Intensity_Zero -- check if we can eliminate this projector * - * * - * Only returns true if the current intensity is zero AND the target intensity is zero * - * * - * INPUT: * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 1/4/00 gth : Created. * - *=============================================================================================*/ -bool TexProjectClass::Is_Intensity_Zero(void) -{ - return ((Intensity == 0.0f) && (DesiredIntensity == 0.0f)); -} - - -/*********************************************************************************************** - * TexProjectClass::Set_Attenuation -- Set the attenuation factor * - * * - * Attenuation scales the intensity. I use attenuation to make shadows fade away as they * - * get farther away from the light source or from the viewer. * - * * - * INPUT: * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 1/4/00 gth : Created. * - *=============================================================================================*/ -void TexProjectClass::Set_Attenuation(float attenuation) -{ - WWASSERT(attenuation >= 0.0f); - WWASSERT(attenuation <= 1.0f); - Attenuation = attenuation; -} - - -/*********************************************************************************************** - * TexProjectClass::Get_Attenuation -- Returns the attenuation value * - * * - * INPUT: * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 1/4/00 gth : Created. * - *=============================================================================================*/ -float TexProjectClass::Get_Attenuation(void) -{ - return Attenuation; -} - - -/*********************************************************************************************** - * TexProjectClass::Enable_Attenuation -- Set the state of the ATTENUATE flag * - * * - * INPUT: * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 1/4/00 gth : Created. * - *=============================================================================================*/ -void TexProjectClass::Enable_Attenuation(bool onoff) -{ - Set_Flag(ATTENUATE,onoff); -} - - -/*********************************************************************************************** - * TexProjectClass::Is_Attenuation_Enabled -- Get the state of the ATTENUATE flag * - * * - * INPUT: * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 1/4/00 gth : Created. * - *=============================================================================================*/ -bool TexProjectClass::Is_Attenuation_Enabled(void) -{ - return Get_Flag(ATTENUATE); -} - - -/*********************************************************************************************** - * TexProjectClass::Enable_Depth_Gradient -- enable/disable depth gradient * - * * - * INPUT: * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 2/25/2000 gth : Created. * - *=============================================================================================*/ -void TexProjectClass::Enable_Depth_Gradient(bool onoff) -{ - Set_Flag(USE_DEPTH_GRADIENT,onoff); - - // re-setup the shader settings - if (Get_Flag(ADDITIVE)) { - Init_Additive(); - } else { - Init_Multiplicative(); - } -} - - -/*********************************************************************************************** - * TexProjectClass::Is_Depth_Gradient_Enabled -- returns whether the depth gradient is enabled * - * * - * INPUT: * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 2/25/2000 gth : Created. * - *=============================================================================================*/ -bool TexProjectClass::Is_Depth_Gradient_Enabled(bool onoff) -{ - return Get_Flag(USE_DEPTH_GRADIENT); -} - -/*********************************************************************************************** - * TexProjectClass::Init_Multiplicative -- Initialize this to be a multiplicative texture proj * - * * - * Set up the internal materials so that the texture is multiplied with whatever it is * - * projected onto. * - * * - * INPUT: * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 1/4/00 gth : Created. * - *=============================================================================================*/ -void TexProjectClass::Init_Multiplicative(void) -{ - Set_Flag(ADDITIVE,false); - - /* - ** Set up the shader - */ - static ShaderClass mult_shader( SHADE_CNST( ShaderClass::PASS_LEQUAL, //depth_compare, - ShaderClass::DEPTH_WRITE_DISABLE, //depth_mask, - ShaderClass::COLOR_WRITE_ENABLE, //color_mask, - ShaderClass::SRCBLEND_ZERO, //src_blend, - ShaderClass::DSTBLEND_SRC_COLOR, //dst_blend, - ShaderClass::FOG_DISABLE, //fog, - ShaderClass::GRADIENT_ADD, //pri_grad, - ShaderClass::SECONDARY_GRADIENT_DISABLE, //sec_grad, - ShaderClass::TEXTURING_ENABLE, //texture, - - ShaderClass::ALPHATEST_DISABLE, //alpha_test, - ShaderClass::CULL_MODE_ENABLE, //cull mode - 0, //post_det_color, - 0) ); //post_det_alpha - - if (WW3DAssetManager::Get_Instance()->Get_Activate_Fog_On_Load()) { - mult_shader.Enable_Fog ("TexProjectClass"); - } - - if (Get_Flag(USE_DEPTH_GRADIENT)) { - - /* - ** enable multi-texturing - */ - mult_shader.Set_Post_Detail_Color_Func(ShaderClass::DETAILCOLOR_ADD); - - /* - ** plug the gradient texture into the second stage - */ - TextureClass * grad_tex = WW3DAssetManager::Get_Instance()->Get_Texture("MultProjectorGradient.tga"); - if (grad_tex) { - grad_tex->Get_Filter().Set_U_Addr_Mode(TextureFilterClass::TEXTURE_ADDRESS_CLAMP); - grad_tex->Get_Filter().Set_V_Addr_Mode(TextureFilterClass::TEXTURE_ADDRESS_CLAMP); - MaterialPass->Set_Texture(grad_tex,1); - grad_tex->Release_Ref(); - } else { - WWDEBUG_SAY(("Could not find texture: MultProjectorGradient.tga!")); - } - - } else { - - /* - ** disable multi-texturing - */ - mult_shader.Set_Post_Detail_Color_Func(ShaderClass::DETAILCOLOR_DISABLE); - - /* - ** remove the texture from the second stage - */ - MaterialPass->Set_Texture(NULL,1); - } - -#if (DEBUG_SHADOW_RENDERING) - // invert the shader so we can see what polygons it is hitting - mult_shader.Set_Dst_Blend_Func(ShaderClass::DSTBLEND_ONE); - mult_shader.Set_Src_Blend_Func(ShaderClass::SRCBLEND_ONE); -#endif - - MaterialPass->Set_Shader(mult_shader); - - /* - ** Set up the Vertex Material parameters - */ - VertexMaterialClass * vmtl = MaterialPass->Peek_Material(); - vmtl->Set_Ambient(0,0,0); - vmtl->Set_Diffuse(0,0,0); - vmtl->Set_Specular(0,0,0); - vmtl->Set_Emissive(0.0f,0.0f,0.0f); - vmtl->Set_Opacity(1.0f); - vmtl->Set_Lighting(true); // I need the emissive value to scale the intensity of the shadow - - /* - ** Set up some mapper settings related to depth gradient - */ - if (Get_Flag(USE_DEPTH_GRADIENT)) { - if (Mapper1 == NULL) { - Mapper1 = NEW_REF(MatrixMapperClass,(1)); - } - Mapper1->Set_Type(MatrixMapperClass::DEPTH_GRADIENT); - vmtl->Set_Mapper(Mapper1,1); - } else { - vmtl->Set_Mapper(NULL,1); - } -} - - -/*********************************************************************************************** - * TexProjectClass::Init_Additive -- Set up the projector to be additive * - * * - * INPUT: * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 1/11/00 gth : Created. * - *=============================================================================================*/ -void TexProjectClass::Init_Additive(void) -{ - Set_Flag(ADDITIVE,true); - - /* - ** Set up the shader - */ - static ShaderClass add_shader( SHADE_CNST( ShaderClass::PASS_LEQUAL, //depth_compare, - ShaderClass::DEPTH_WRITE_DISABLE, //depth_mask, - ShaderClass::COLOR_WRITE_ENABLE, //color_mask, - ShaderClass::SRCBLEND_ONE, //src_blend, - ShaderClass::DSTBLEND_ONE, //dst_blend, - ShaderClass::FOG_DISABLE, //fog, - ShaderClass::GRADIENT_MODULATE, //pri_grad, - ShaderClass::SECONDARY_GRADIENT_DISABLE, //sec_grad, - ShaderClass::TEXTURING_ENABLE, //texture, - ShaderClass::ALPHATEST_DISABLE, //alpha_test, - ShaderClass::CULL_MODE_ENABLE, //cullmode, - ShaderClass::DETAILCOLOR_DISABLE, //post_det_color, - ShaderClass::DETAILALPHA_DISABLE) ); //post_det_alpha - - if (WW3DAssetManager::Get_Instance()->Get_Activate_Fog_On_Load()) { - add_shader.Enable_Fog ("TexProjectClass"); - } - - /* - ** Additive projectors always use the normal gradient so they need multi-texturing - */ - add_shader.Set_Post_Detail_Color_Func(ShaderClass::DETAILCOLOR_SCALE); - - /* - ** plug in the gradient texture - */ - TextureClass * grad_tex = WW3DAssetManager::Get_Instance()->Get_Texture("AddProjectorGradient.tga"); - if (grad_tex) { - grad_tex->Get_Filter().Set_U_Addr_Mode(TextureFilterClass::TEXTURE_ADDRESS_CLAMP); - grad_tex->Get_Filter().Set_V_Addr_Mode(TextureFilterClass::TEXTURE_ADDRESS_CLAMP); - MaterialPass->Set_Texture(grad_tex,1); - grad_tex->Release_Ref(); - } else { - WWDEBUG_SAY(("Could not find texture: AddProjectorGradient.tga!")); - } - -#if (DEBUG_SHADOW_RENDERING) - // invert the shader so we can see what polygons it is hitting - add_shader.Set_Dst_Blend_Func(ShaderClass::DSTBLEND_SRC_COLOR); - add_shader.Set_Src_Blend_Func(ShaderClass::SRCBLEND_ZERO); -#endif - - MaterialPass->Set_Shader(add_shader); - - /* - ** Set up the Vertex Material parameters - */ - VertexMaterialClass * vmtl = MaterialPass->Peek_Material(); - vmtl->Set_Ambient(0,0,0); - vmtl->Set_Diffuse(0,0,0); - vmtl->Set_Specular(0,0,0); - vmtl->Set_Emissive(1,1,1); - vmtl->Set_Opacity(1.0f); - vmtl->Set_Lighting(true); //need emissive to scale the intensity of the projector - - /* - ** Set up some mapper settings related to depth gradient - ** Additive texture projections always use the normal gradient - */ - if (Mapper1 == NULL) { - Mapper1 = NEW_REF(MatrixMapperClass,(1)); - } - Mapper1->Set_Type(MatrixMapperClass::NORMAL_GRADIENT); - vmtl->Set_Mapper(Mapper1,1); -} - - -/*********************************************************************************************** - * TexProjectClass::Set_Texture -- Set the texture to be projected * - * * - * INPUT: * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 1/11/00 gth : Created. * - *=============================================================================================*/ -void TexProjectClass::Set_Texture(TextureClass * texture) -{ - if (texture != NULL) - { - texture->Get_Filter().Set_U_Addr_Mode(TextureFilterClass::TEXTURE_ADDRESS_CLAMP); - texture->Get_Filter().Set_V_Addr_Mode(TextureFilterClass::TEXTURE_ADDRESS_CLAMP); - MaterialPass->Set_Texture(texture); - } -} - - -/*********************************************************************************************** - * TexProjectClass::Get_Texture -- Returns the texture being projected * - * * - * INPUT: * - * * - * OUTPUT: * - * * - * WARNINGS: * - * the pointer is ref-counted! make sure to keep track of your references * - * * - * HISTORY: * - * 1/11/00 gth : Created. * - *=============================================================================================*/ -TextureClass * TexProjectClass::Get_Texture(void) const -{ - return MaterialPass->Get_Texture(); -} - - -/*********************************************************************************************** - * TexProjectClass::Peek_Texture -- Returns the texture being projected * - * * - * INPUT: * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 1/11/00 gth : Created. * - *=============================================================================================*/ -TextureClass * TexProjectClass::Peek_Texture(void) const -{ - return MaterialPass->Peek_Texture(); -} - - -/*********************************************************************************************** - * TexProjectClass::Peek_Material_Pass -- Returns the material pass object * - * * - * INPUT: * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 1/11/00 gth : Created. * - *=============================================================================================*/ -MaterialPassClass * TexProjectClass::Peek_Material_Pass(void) -{ - return MaterialPass; -} - - -/*********************************************************************************************** - * TexProjectClass::Set_Perspective_Projection -- set up a perspective projection * - * * - * INPUT: * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 1/27/00 gth : Created. * - *=============================================================================================*/ -void TexProjectClass::Set_Perspective_Projection(float hfov,float vfov,float znear,float zfar) -{ - HFov = hfov; - VFov = vfov; - ZNear = znear; - ZFar = zfar; - - ProjectorClass::Set_Perspective_Projection(hfov,vfov,znear,zfar); - Set_Flag(PERSPECTIVE,true); -} - - -/*********************************************************************************************** - * TexProjectClass::Set_Ortho_Projection -- set up an orthographic projection * - * * - * INPUT: * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 1/27/00 gth : Created. * - *=============================================================================================*/ -void TexProjectClass::Set_Ortho_Projection(float xmin,float xmax,float ymin,float ymax,float znear,float zfar) -{ - XMin = xmin; - XMax = xmax; - YMin = ymin; - YMax = ymax; - ZNear = znear; - ZFar = zfar; - - ProjectorClass::Set_Ortho_Projection(xmin,xmax,ymin,ymax,znear,zfar); - Set_Flag(PERSPECTIVE,false); -} - -/*********************************************************************************************** - * TexProjectClass::Compute_Perspective_Projection -- Set up a perspective projection of an ob * - * * - * This function automates the process of generating the perspective parameters needed to * - * tightly bound the projection of an object. * - * * - * INPUT: * - * model - object which we are created a projection of * - * lightpos - positional light source * - * znear - distance to near clipping plane for the projection (if -1.0, will be generated) * - * zfar - distance to far clipping plane for the projection (if -1.0, will be generated) * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 1/11/00 gth : Created. * - *=============================================================================================*/ -bool TexProjectClass::Compute_Perspective_Projection -( - RenderObjClass * model, - const Vector3 & lightpos, - float znear, - float zfar -) -{ - if (model == NULL) { - WWDEBUG_SAY(("Attempting to generate projection for a NULL model")); - return false; - } - - AABoxClass box; - model->Get_Obj_Space_Bounding_Box(box); - const Matrix3D & tm = model->Get_Transform(); - - return Compute_Perspective_Projection(box,tm,lightpos,znear,zfar); -} - - -/*********************************************************************************************** - * TexProjectClass::Compute_Perspective_Projection -- Set up a perspective projection of an ob * - * * - * This function automates the process of generating the perspective parameters needed to * - * tightly bound the projection of an object. * - * * - * INPUT: * - * obj_box - object space bounding box of the object we are projecting * - * tm - transform of the object we are projecting * - * lightpos - positional light source * - * user_znear - distance to near clipping plane for the projection (if -1.0, will be generated)* - * user_zfar - distance to far clipping plane for the projection (if -1.0, will be generated) * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 1/11/00 gth : Created. * - *=============================================================================================*/ -bool TexProjectClass::Compute_Perspective_Projection -( - const AABoxClass & obj_box, - const Matrix3D & tm, - const Vector3 & lightpos, - float user_znear, - float user_zfar -) -{ - /* - ** Compute the center of the box in world-space - */ - Vector3 wrld_center; - Matrix3D::Transform_Vector(tm,obj_box.Center,&wrld_center); - - /* - ** Create a camera transform looking at the object. - ** Set this as our transform later in this routine. - */ - Matrix3D texture_tm,texture_tm_inv; - texture_tm.Look_At(lightpos,wrld_center,0.0f); - texture_tm.Get_Orthogonal_Inverse(texture_tm_inv); - - /* - ** Calculate the axis-aligned bounding box of the model in the camera's coordinate system. - */ - AABoxClass box = obj_box; - Matrix3D obj_to_world = tm; - Matrix3D obj_to_texture; - Matrix3D::Multiply(texture_tm_inv,obj_to_world,&obj_to_texture); - box.Transform(obj_to_texture); - - /* - ** If the box is behind the viewpoint or the viewpoint is inside the box - ** our FOV will be > 180 degrees. Have to give up - */ - if ((box.Center.Z > 0.0f) || (box.Extent.Z > WWMath::Fabs(box.Center.Z))) { - return false; - } - - /* - ** Compute the frustum parameters. Remember that our z coordinates are negative but the - ** projection code needs positive z distances. - */ - float znear = -box.Center.Z; //-(box.Center.Z + obj_box.Extent.Quick_Length()); - float zfar = -(box.Center.Z - obj_box.Extent.Quick_Length()) * 2.0f; - - if (user_znear != -1.0f) { - znear = box.Center.Z + user_znear; - } - if (user_zfar != -1.0f) { - zfar = box.Center.Z + user_zfar; - } - - float tan_hfov2 = WWMath::Fabs(box.Extent.X / (box.Center.Z + box.Extent.Z)); - float tan_vfov2 = WWMath::Fabs(box.Extent.Y / (box.Center.Z + box.Extent.Z)); - float hfov = 2.0f * WWMath::Atan(tan_hfov2); - float vfov = 2.0f * WWMath::Atan(tan_vfov2); - - /* - ** Plug in the results. - */ - Set_Perspective_Projection(hfov,vfov,znear,zfar); - Set_Transform(texture_tm); - return true; -} - - -/*********************************************************************************************** - * TexProjectClass::Compute_Ortho_Projection -- Automatic Orthographic projection * - * * - * Generates the orthographic projection parameters to tightly bound an object * - * * - * INPUT: * - * model - object which we are created a projection of * - * lightdir - directional light source * - * znear - distance to near clipping plane for the projection (if -1.0, will be generated) * - * zfar - distance to far clipping plane for the projection (if -1.0, will be generated) * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 1/11/00 gth : Created. * - *=============================================================================================*/ -bool TexProjectClass::Compute_Ortho_Projection -( - RenderObjClass * model, - const Vector3 & lightdir, - float znear, - float zfar -) -{ - if (model == NULL) { - WWDEBUG_SAY(("Attempting to generate projection for a NULL model")); - return false; - } - - AABoxClass box; - model->Get_Obj_Space_Bounding_Box(box); - const Matrix3D & tm = model->Get_Transform(); - - return Compute_Ortho_Projection(box,tm,lightdir,znear,zfar); -} - - -/*********************************************************************************************** - * TexProjectClass::Compute_Ortho_Projection -- Automatic Orthographic projection * - * * - * Generates the orthographic projection parameters to tightly bound an object * - * * - * INPUT: * - * obj_box - object space bounding box of the object we are projecting * - * tm - transform of the object we are projecting * - * lightdir - directional light * - * user_znear - distance to near clipping plane for the projection (if -1.0, will be generated)* - * user_zfar - distance to far clipping plane for the projection (if -1.0, will be generated) * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 1/11/00 gth : Created. * - *=============================================================================================*/ -bool TexProjectClass::Compute_Ortho_Projection -( - const AABoxClass & obj_box, - const Matrix3D & tm, - const Vector3 & lightdir, - float user_znear, - float user_zfar -) -{ - /* - ** Compute the center of the box in world-space - */ - AABoxClass wrldbox = obj_box; - wrldbox.Transform(tm); - - /* - ** Create a camera transform looking at the object. - ** Set this as our transform later in this routine. - */ - Vector3 camera_target = wrldbox.Center; - Vector3 camera_position = camera_target - 2.0f * wrldbox.Extent.Length() * lightdir; - - Matrix3D texture_tm,texture_tm_inv; - texture_tm.Look_At(camera_position,camera_target,0.0f); - texture_tm.Get_Orthogonal_Inverse(texture_tm_inv); - - /* - ** Calculate the axis-aligned bounding box of the model in the camera's coordinate system. - */ - AABoxClass box = obj_box; - Matrix3D obj_to_world = tm; - Matrix3D obj_to_texture; - Matrix3D::Multiply(texture_tm_inv,obj_to_world,&obj_to_texture); - box.Transform(obj_to_texture); - - /* - ** Expand the box to help with bounding box errors - */ - box.Extent *= 1.0f; - - /* - ** Compute the frustum parameters. Note that znear and zfar are supposed to - ** be positive distances for the projection code. - */ - float znear = -box.Center.Z; //-(box.Center.Z + obj_box.Extent.Quick_Length()); - float zfar = -(box.Center.Z - obj_box.Extent.Quick_Length()) * 2.0f; - - if (user_znear != -1.0f) { - znear = -box.Center.Z + user_znear; - } - if (user_zfar != -1.0f) { - zfar = -box.Center.Z + user_zfar; - } - - /* - ** All done! - */ - Set_Ortho_Projection( box.Center.X - box.Extent.X, - box.Center.X + box.Extent.X, - box.Center.Y - box.Extent.Y, - box.Center.Y + box.Extent.Y, - znear, - zfar ); - Set_Transform(texture_tm); - return true; -} - -/*********************************************************************************************** - * TexProjectClass::Compute_Texture -- Generates texture by rendering an object * - * * - * INPUT: * - * model - pointer to the render object to generate a shadow texture for * - * context - shadow render context which has been initialized to resolution * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 1/11/00 gth : Created. * - * 5/16/02 kjm : Added optional custom depth/stencil target * - *=============================================================================================*/ -bool TexProjectClass::Compute_Texture -( - RenderObjClass * model, - SpecialRenderInfoClass * context -) -{ - if ((model == NULL) || (context == NULL)) - { - return false; - } - /* - ** Render to texture - */ - TextureClass * rtarget=NULL; - ZTextureClass* ztarget=NULL; - - Peek_Render_Target(&rtarget,&ztarget); - - if (rtarget != NULL) - { - // set projector for render context KJM - context->Texture_Projector=this; - - /* - ** Set the render target - */ - DX8Wrapper::Set_Render_Target_With_Z (rtarget,ztarget); - - /* - ** Set up the camera - */ - Configure_Camera(context->Camera); - - /* - ** Render the object - */ - Vector3 color(0.0f,0.0f,0.0f); - if (Get_Flag(ADDITIVE) == false) { - color.Set(1.0f,1.0f,1.0f); - } - - bool zclear=ztarget!=NULL; - - bool snapshot=WW3D::Is_Snapshot_Activated(); - SNAPSHOT_SAY(("TexProjectCLass::Begin_Render()")); - WW3D::Begin_Render(true,zclear,color); // false to zclear as we don't have z-buffer - WW3D::Render(*model,*context); - SNAPSHOT_SAY(("TexProjectCLass::End_Render()")); - WW3D::End_Render(false); - WW3D::Activate_Snapshot(snapshot); // End_Render() ends the shapsnot, so restore the state - - DX8Wrapper::Set_Render_Target((IDirect3DSurface8 *)NULL); - - } - -#if 0 - - /* - ** Render the object with the BW Renderer into our color surface - */ - BWRenderClass bwr((unsigned char*)shadow_surface->getDataPtr(),tex_size); - bwr.Fill(0xff); - context->BWRenderer = &bwr; - model->Special_Render(*context); - context->BWRenderer = NULL; -#endif - return true; -} - - -/*********************************************************************************************** - * TexProjectClass::Needs_Render_Target -- returns wheter this projector needs a render target * - * * - * INPUT: * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 4/17/2001 gth : Created. * - *=============================================================================================*/ -bool TexProjectClass::Needs_Render_Target(void) -{ - return Get_Flag(TEXTURE_DIRTY); -} - - -/*********************************************************************************************** - * TexProjectClass::Set_Render_Target -- Install a render target for this projector to use * - * * - * INPUT: * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 4/16/2001 gth : Created. * - *=============================================================================================*/ -void TexProjectClass::Set_Render_Target -( - TextureClass* render_target, - ZTextureClass* zbuffer -) -{ - REF_PTR_SET(RenderTarget,render_target); - Set_Texture(RenderTarget); - REF_PTR_SET(DepthStencilTarget,zbuffer); -} - -/*********************************************************************************************** - * TexProjectClass::Peek_Render_Target -- Returns pointer to the render target if we have one * - * * - * INPUT: * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 4/5/2001 gth : Created. * - * 5/16/2002 kjm : Added optional custom zbuffer * - *=============================================================================================*/ -TextureClass* TexProjectClass::Peek_Render_Target -( - TextureClass** rtarget, - ZTextureClass** ztarget -) -{ - // some uses of this function just want to know if a render target exists - if (rtarget==NULL) return RenderTarget; - - *rtarget=RenderTarget; - - // don't set if pointer isn't supplied - if (ztarget!=NULL) - *ztarget=DepthStencilTarget; - - return RenderTarget; -} - -/*********************************************************************************************** - * TexProjectClass::Configure_Camera -- set up a camera to match this projector * - * * - * INPUT: * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 1/11/00 gth : Created. * - *=============================================================================================*/ -void TexProjectClass::Configure_Camera(CameraClass & camera) -{ - camera.Set_Transform(Transform); - camera.Set_Clip_Planes(0.01f,ZFar); - - if (Get_Flag(PERSPECTIVE)) { - camera.Set_Projection_Type(CameraClass::PERSPECTIVE); - camera.Set_View_Plane(HFov,VFov); - - } else { - camera.Set_Projection_Type(CameraClass::ORTHO); - camera.Set_View_Plane(Vector2(XMin,YMin),Vector2(XMax,YMax)); - } - - // Set one-pixel borders to the texture to avoid "flooding" shadows... - float size=Get_Texture_Size(); - float inv_size=1.0f/size; - Vector2 vmin(1.0f*inv_size,1.0f*inv_size); - Vector2 vmax((size-1.0f)*inv_size,(size-1.0f)*inv_size); - camera.Set_Viewport(vmin,vmax); -} - - -/*********************************************************************************************** - * TexProjectClass::Pre_Render_Update -- Prepare the projector for rendering * - * * - * INPUT: * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 1/11/00 gth : Created. * - *=============================================================================================*/ -void TexProjectClass::Pre_Render_Update(const Matrix3D & camera) -{ - /* - ** Mview-texture = PShadow * Mwrld-texture * Mcamera-vrld - */ - Matrix3D world_to_texture; - Matrix3D tmp; - Matrix4x4 view_to_texture; - - Transform.Get_Orthogonal_Inverse(world_to_texture); - Matrix3D::Multiply(world_to_texture,camera,&tmp); - Matrix4x4::Multiply(Projection,tmp,&view_to_texture); - - /* - ** update the current intensity by iterating it towards the desired intensity - */ - float intensity_delta = DesiredIntensity - Intensity; - float max_intensity_delta = INTENSITY_RATE_OF_CHANGE * WW3D::Get_Logic_Frame_Time_Seconds(); - - if (intensity_delta > max_intensity_delta) { - Intensity += max_intensity_delta; - } else if (intensity_delta < -max_intensity_delta) { - Intensity -= max_intensity_delta; - } else { - Intensity = DesiredIntensity; - } - - float actual_intensity = Intensity * Attenuation; - - /* - ** install the current intensity - */ - VertexMaterialClass * vmat = MaterialPass->Peek_Material(); - if (Get_Flag(ADDITIVE)) { - vmat->Set_Emissive(actual_intensity,actual_intensity,actual_intensity); - } else { - vmat->Set_Emissive(1.0f - actual_intensity,1.0f - actual_intensity,1.0f - actual_intensity); - } - - /* - ** update the mappers - */ - if (Get_Flag(PERSPECTIVE)) { - Mapper->Set_Type(MatrixMapperClass::PERSPECTIVE_PROJECTION); - } else { - Mapper->Set_Type(MatrixMapperClass::ORTHO_PROJECTION); - } - - if (Get_Texture_Size() == 0) { -// SurfaceClass::SurfaceDescription surface_desc; -// MaterialPass->Peek_Texture()->Get_Level_Description(surface_desc); - Set_Texture_Size(MaterialPass->Peek_Texture()->Get_Width()); - WWASSERT(Get_Texture_Size() != 0); - } - - Mapper->Set_Texture_Transform(view_to_texture,Get_Texture_Size()); - if (Mapper1) { - Mapper1->Set_Texture_Transform(view_to_texture,Get_Texture_Size()); - } -} - - -/*********************************************************************************************** - * TexProjectClass::Update_WS_Bounding_Volume -- Recalculate the world-space bounding box * - * * - * INPUT: * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 1/11/00 gth : Created. * - *=============================================================================================*/ -void TexProjectClass::Update_WS_Bounding_Volume(void) -{ - ProjectorClass::Update_WS_Bounding_Volume(); - - /* - ** Tell our culling system that we've changed - */ - Vector3 extent; - WorldBoundingVolume.Compute_Axis_Aligned_Extent(&extent); - Set_Cull_Box(AABoxClass(WorldBoundingVolume.Center,extent)); -} - diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/texproject.h b/Generals/Code/Libraries/Source/WWVegas/WW3D2/texproject.h deleted file mode 100644 index 0ad5aa9efd7..00000000000 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/texproject.h +++ /dev/null @@ -1,239 +0,0 @@ -/* -** 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 . -*/ - -/*********************************************************************************************** - *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** - *********************************************************************************************** - * * - * Project Name : WW3D * - * * - * $Archive:: /Commando/Code/ww3d2/texproject.h $* - * * - * Original Author:: Greg Hjelstrom * - * * - * $Author:: Kenny Mitchell * - * * - * $Modtime:: 06/26/02 4:04p $* - * * - * $Revision:: 8 $* - * * - * 06/27/02 KM Render to shadow buffer texture support * - *---------------------------------------------------------------------------------------------* - * Functions: * - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - -#pragma once - -#include "always.h" -#include "matrix3d.h" -#include "matrix4.h" -#include "obbox.h" -#include "matpass.h" -#include "matrixmapper.h" -#include "cullsys.h" -#include "multilist.h" -#include "projector.h" - - -class SpecialRenderInfoClass; -class RenderObjClass; -class MaterialPassClass; -class SurfaceClass; - -class TextureClass; -class ZTextureClass; - - -/** -** TexProjectClass -** This class is used to project textures onto object in the world. It contains -** a pointer to the texture to be projected, a bounding volume for the projection, -** and a material pass which can perform the projection. -** -** Design Goals: -** - Texture Projectors should be easy to place in the world and move around. -** solution: Store the bounding volume and any other parameters in a coordinate -** system local to the projector. Update the world-space cache whenever needed. -** The automatically generated shadow texture projectors are a special case subset -** of the general texture projection code. For this reason, a local bounding -** volume will be stored and its world-space equivalent will be updated whenever -** needed. -** -** - Texture projectors need to be compatible with the culling systems. -** solution: inherit the Cullable interface. -** -** - Texture projectors need to be quickly pulled in and out of many lists during -** the rendering process. -** solution: list system similar to PhysListClass? I really need to templatize this. -** - done: MultiListClass! -** -** - Dynamic Texture projectors need to be updated in stages. Update/recompute only the -** bounding volume first, then defer computing the actual texture until it is -** determined that the volume falls into the frustum and is applied to at least one -** object. -** solution: Code the bounding volume/projection paramter generation separate from -** the texture generation code. A derived texture projection object. Let texture -** projectors know about the object they are projecting so that they can have that -** object rendered from the desired viewpoint. Need a 'Dirty' flag and a pointer to -** a 'parent' object. Perhaps separate this code into a ShadowProjectClass since shadows -** are the only case I can think of that need the ability to re-render their 'parent' -** object. Everything else should be a static texture-map either generated 'artistically' -** or generated off-line. -** -*/ -class TexProjectClass : public ProjectorClass, public CullableClass, public MultiListObjectClass -{ -public: - - TexProjectClass(void); - virtual ~TexProjectClass(void); - - /* - ** Material settings - */ - void Set_Texture_Size(int size); - int Get_Texture_Size(void); - void Init_Multiplicative(void); - void Init_Additive(void); - void Set_Intensity(float intensity,bool immediate = false); // 1.0 = on 100%, 0.0 = 'off' - float Get_Intensity(void); - bool Is_Intensity_Zero(void); - void Set_Attenuation(float attenuation); // 1.0 = on, 0.0 = off - float Get_Attenuation(void); - void Enable_Attenuation(bool onoff); - bool Is_Attenuation_Enabled(void); - MaterialPassClass * Peek_Material_Pass(void); - - /* - ** Options - */ - void Enable_Affect_Dynamic_Objects(bool onoff) { Set_Flag(AFFECT_DYNAMIC_OBJS,onoff); } - bool Is_Affect_Dynamic_Objects_Enabled(void) { return Get_Flag(AFFECT_DYNAMIC_OBJS); } - void Enable_Affect_Static_Objects(bool onoff) { Set_Flag(AFFECT_STATIC_OBJS,onoff); } - bool Is_Affect_Static_Objects_Enabled(void) { return Get_Flag(AFFECT_STATIC_OBJS); } - void Enable_Depth_Gradient(bool onoff); - bool Is_Depth_Gradient_Enabled(bool onoff); - - /* - ** Manual initialization of a TexProjectClass - ** 1 - call ProjectorClass::Set_Transform - ** 2 - call Set_Projection_Perspective -or- Set_Projection_Ortho - ** 3 - call Set_Texture. - */ - virtual void Set_Perspective_Projection(float hfov,float vfov,float znear,float zfar); - virtual void Set_Ortho_Projection(float xmin,float xmax,float ymin,float ymax,float znear,float zfar); - - void Set_Texture(TextureClass * texture); - TextureClass * Get_Texture(void) const; - TextureClass * Peek_Texture(void) const; - - - void Set_DepthStencilBuffer(ZTextureClass* ztex); - ZTextureClass* Get_DepthStencilBuffer() const; - ZTextureClass* Peek_DepthStencilBuffer() const; - - /* - ** Automatic initialization of a TexProjectClass. - ** First set up your projection parameters, give the projector a render target, then call Compute_Texture - */ - bool Compute_Perspective_Projection(RenderObjClass * obj,const Vector3 & lightpos,float znear=-1.0f,float zfar=-1.0f); - bool Compute_Perspective_Projection(const AABoxClass & obj_box,const Matrix3D & tm,const Vector3 & lightpos,float znear=-1.0f,float zfar=-1.0f); - - bool Compute_Ortho_Projection(RenderObjClass * obj,const Vector3 & lightdir,float znear=-1.0f,float zfar=-1.0f); - bool Compute_Ortho_Projection(const AABoxClass & obj_box,const Matrix3D & tm,const Vector3 & lightdir,float znear=-1.0f,float zfar=-1.0f); - - bool Needs_Render_Target(void); - void Set_Render_Target(TextureClass* render_target, ZTextureClass* ztarget=NULL); - TextureClass* Peek_Render_Target(TextureClass** rtarget=NULL, ZTextureClass** ztarget=NULL); - - bool Compute_Texture(RenderObjClass * model,SpecialRenderInfoClass * context); - - /* - ** Prep for rendering, called by the scene prior to usage. - */ - virtual void Pre_Render_Update(const Matrix3D & camera); - - /* - ** virtual interface for getting the pointer of the object that generated this shadow. - ** defaults to returning NULL. This is implemented by some derived classes and used by - ** the system to prevent a projection from being applied to the object that generated - ** the projection... - ** (gth) feels kludgy, this got a little messy when I moved this code into WW3D from WWPhys - */ - virtual void * Get_Projection_Object_ID(void) const { return NULL; } - -protected: - - void Set_Flag(uint32 flag,bool onoff); - bool Get_Flag(uint32 flag) const; - virtual void Update_WS_Bounding_Volume(void); - void Configure_Camera(CameraClass & camera); - - enum FlagsType - { - PERSPECTIVE = 0x00000001, // PERSPECTIVE or ORTHO - ADDITIVE = 0x00000002, // ADDITIVE or MULTIPLICATIVE - TEXTURE_DIRTY = 0x00000004, // used by derived DynTexProjectClass - VOLATILE = 0x00000008, // this is a volatile texture. - ATTENUATE = 0x00000010, // this projector should be attenuated based on distance to viewer - AFFECT_DYNAMIC_OBJS = 0x00000020, // this projector affects dynamic objects - AFFECT_STATIC_OBJS = 0x00000040, // this projector affects static objects - USE_DEPTH_GRADIENT = 0x00000080, // fade the projection as a function of depth - HAS_RENDER_TARGET = 0x00000100, // the texture we have can be a render target - SIZE_MASK = 0xFFF00000, // desired texture size stored in upper 3 nibbles - SIZE_SHIFT = 20, - - DEFAULT_FLAGS = ATTENUATE | AFFECT_DYNAMIC_OBJS | AFFECT_STATIC_OBJS - }; - - uint32 Flags; - - /* - ** Intensity Controls - */ - float DesiredIntensity; // last input desired intensity. - float Intensity; // basic shadow intensity. value between 0 and 1 - float Attenuation; // attenuation factor based on distance from camera. value between 0 and 1 - - /* - ** Material pass to be added to any object that intersects the volume - */ - MaterialPassClass * MaterialPass; - MatrixMapperClass * Mapper1; - TextureClass * RenderTarget; - ZTextureClass* DepthStencilTarget; - - /* - ** I have to remember all of these values so that I can properly initialize a CameraClass - ** when we do render-to-texture. Some day we will merge CameraClass and ProjectorClass. - */ - float HFov; // horizontal fov (for perspective mode) - float VFov; // vertical fov (for perspective mode) - float XMin; // left x clip plane (for ortho) - float XMax; // right x clip plane (for ortho) - float YMin; // bottom y clip plane (for ortho) - float YMax; // top y clip plane (for ortho) - float ZNear,ZFar; // z clip planes (for both modes) -}; - - -/* -** Texture Projector Lists -*/ -typedef RefMultiListClass TexProjListClass; -typedef RefMultiListIterator TexProjListIterator; diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/texture.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/texture.cpp deleted file mode 100644 index cbd16fb276c..00000000000 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/texture.cpp +++ /dev/null @@ -1,1908 +0,0 @@ -/* -** 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 . -*/ - -/*********************************************************************************************** - *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** - *********************************************************************************************** - * * - * Project Name : WW3D * - * * - * $Archive:: /Commando/Code/ww3d2/texture.cpp $* - * * - * $Org Author:: Steve_t $* - * * - * Author : Kenny Mitchell * - * * - * $Modtime:: 08/05/02 1:27p $* - * * - * $Revision:: 85 $* - * * - * 06/27/02 KM Texture class abstraction * - * 08/05/02 KM Texture class redesign (revisited) - *---------------------------------------------------------------------------------------------* - * Functions: * - * FileListTextureClass::Load_Frame_Surface -- Load source texture * - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - -#include "texture.h" - -#include -#include -#include "dx8wrapper.h" -#include "TARGA.h" -#include -#include "w3d_file.h" -#include "assetmgr.h" -#include "formconv.h" -#include "textureloader.h" -#include "missingtexture.h" -#include "ffactory.h" -#include "dx8caps.h" -#include "dx8texman.h" -#include "meshmatdesc.h" -#include "texturethumbnail.h" -#include "wwprofile.h" - -const unsigned DEFAULT_INACTIVATION_TIME=20000; - -/* -** Definitions of static members: -*/ - -static unsigned unused_texture_id; - -// This throttles submissions to the background texture loading queue. -static unsigned TexturesAppliedPerFrame; -const unsigned MAX_TEXTURES_APPLIED_PER_FRAME=2; - - -/*! - * KM General base constructor for texture classes - */ -TextureBaseClass::TextureBaseClass -( - unsigned int width, - unsigned int height, - enum MipCountType mip_level_count, - enum PoolType pool, - bool rendertarget, - bool reducible -) -: MipLevelCount(mip_level_count), - D3DTexture(NULL), - Initialized(false), - Name(""), - FullPath(""), - texture_id(unused_texture_id++), - IsLightmap(false), - IsProcedural(false), - IsReducible(reducible), - IsCompressionAllowed(false), - InactivationTime(0), - ExtendedInactivationTime(0), - LastInactivationSyncTime(0), - LastAccessed(0), - Width(width), - Height(height), - Pool(pool), - Dirty(false), - TextureLoadTask(NULL), - ThumbnailLoadTask(NULL), - HSVShift(0.0f,0.0f,0.0f) -{ -} - - -//********************************************************************************************** -//! Base texture class destructor -/*! KJM -*/ -TextureBaseClass::~TextureBaseClass(void) -{ - delete TextureLoadTask; - TextureLoadTask=NULL; - delete ThumbnailLoadTask; - ThumbnailLoadTask=NULL; - - if (D3DTexture) - { - D3DTexture->Release(); - D3DTexture = NULL; - } - - DX8TextureManagerClass::Remove(this); -} - - - - -//********************************************************************************************** -//! Invalidate old unused textures -/*! -*/ -void TextureBaseClass::Invalidate_Old_Unused_Textures(unsigned invalidation_time_override) -{ - // (gth) If thumbnails are not enabled, then we don't run this code. - if (WW3D::Get_Thumbnail_Enabled() == false) { - return; - } - - // Zero the texture apply count in this function because this is called every frame...(this wasn't in E&B main branch KJM) - TexturesAppliedPerFrame=0; - - unsigned synctime=WW3D::Get_Sync_Time(); - HashTemplateIterator ite(WW3DAssetManager::Get_Instance()->Texture_Hash()); - // Loop through all the textures in the manager - - for (ite.First ();!ite.Is_Done();ite.Next ()) - { - TextureClass* tex=ite.Peek_Value(); - - // Consider invalidating if texture has been initialized and defines inactivation time - if (tex->Initialized && tex->InactivationTime) - { - unsigned age=synctime-tex->LastAccessed; - - if (invalidation_time_override) - { - if (age>invalidation_time_override) - { - tex->Invalidate(); - tex->LastInactivationSyncTime=synctime; - } - } - else - { - // Not used in the last n milliseconds? - if (age>(tex->InactivationTime+tex->ExtendedInactivationTime)) - { - tex->Invalidate(); - tex->LastInactivationSyncTime=synctime; - } - } - } - } -} - - - - - -//********************************************************************************************** -//! Invalidate this texture -/*! -*/ -void TextureBaseClass::Invalidate() -{ - if (TextureLoadTask) { - return; - } - if (ThumbnailLoadTask) { - return; - } - - // Don't invalidate procedural textures - if (IsProcedural) { - return; - } - - if (D3DTexture) - { - D3DTexture->Release(); - D3DTexture = NULL; - } - - Initialized=false; - - LastAccessed=WW3D::Get_Sync_Time(); -/* was battlefield version// If the texture has already been initialised we should exit now - if (Initialized) return; - - WWPROFILE(("TextureClass::Init()")); - - // If the texture has recently been inactivated, increase the inactivation time (this texture obviously - // should not have been inactivated yet). - - if (InactivationTime && LastInactivationSyncTime) { - if ((WW3D::Get_Sync_Time()-LastInactivationSyncTime)Release(); - D3DTexture = NULL; - } - - Initialized=false; - - LastAccessed=WW3D::Get_Sync_Time();*/ -} - -//********************************************************************************************** -//! Returns a pointer to the d3d texture -/*! -*/ -IDirect3DBaseTexture8 * TextureBaseClass::Peek_D3D_Base_Texture() const -{ - LastAccessed=WW3D::Get_Sync_Time(); - return D3DTexture; -} - -//********************************************************************************************** -//! Set the d3d texture pointer. Handles ref counts properly. -/*! -*/ -void TextureBaseClass::Set_D3D_Base_Texture(IDirect3DBaseTexture8* tex) -{ - // (gth) Generals does stuff directly with the D3DTexture pointer so lets - // reset the access timer whenever someon messes with this pointer. - LastAccessed=WW3D::Get_Sync_Time(); - - if (D3DTexture != NULL) { - D3DTexture->Release(); - } - D3DTexture = tex; - if (D3DTexture != NULL) { - D3DTexture->AddRef(); - } -} - - -//********************************************************************************************** -//! Load locked surface -/*! -*/ -void TextureBaseClass::Load_Locked_Surface() -{ - WWPROFILE(("TextureClass::Load_Locked_Surface()")); - if (D3DTexture) D3DTexture->Release(); - D3DTexture=0; - TextureLoader::Request_Thumbnail(this); - Initialized=false; -} - - -//********************************************************************************************** -//! Is missing texture -/*! -*/ -bool TextureBaseClass::Is_Missing_Texture() -{ - bool flag = false; - IDirect3DBaseTexture8 *missing_texture = MissingTexture::_Get_Missing_Texture(); - - if (D3DTexture == missing_texture) - flag = true; - - if (missing_texture) - { - missing_texture->Release(); - } - - return flag; -} - - -//********************************************************************************************** -//! Set texture name -/*! -*/ -void TextureBaseClass::Set_Texture_Name(const char * name) -{ - Name=name; -} - - - - -//********************************************************************************************** -//! Get priority -/*! -*/ -unsigned int TextureBaseClass::Get_Priority(void) -{ - if (!D3DTexture) - { - WWASSERT_PRINT(0, "Get_Priority: D3DTexture is NULL!"); - return 0; - } - -#ifndef _XBOX - return D3DTexture->GetPriority(); -#else - return 0; -#endif -} - - -//********************************************************************************************** -//! Set priority -/*! -*/ -unsigned int TextureBaseClass::Set_Priority(unsigned int priority) -{ - if (!D3DTexture) - { - WWASSERT_PRINT(0, "Set_Priority: D3DTexture is NULL!"); - return 0; - } - -#ifndef _XBOX - return D3DTexture->SetPriority(priority); -#else - return 0; -#endif -} - - -//********************************************************************************************** -//! Get reduction mip levels -/*! -*/ -unsigned TextureBaseClass::Get_Reduction() const -{ - // don't reduce if the texture is too small already or - // has no mip map levels - if (MipLevelCount==MIP_LEVELS_1) return 0; - if (Width <= 32 || Height <= 32) return 0; - - int reduction=WW3D::Get_Texture_Reduction(); - - // 'large texture extra reduction' causes textures above 256x256 to be reduced one more step. - if (WW3D::Is_Large_Texture_Extra_Reduction_Enabled() && (Width > 256 || Height > 256)) { - reduction++; - } - if (MipLevelCount && reduction>MipLevelCount) { - reduction=MipLevelCount; - } - return reduction; -} - - - -//********************************************************************************************** -//! Apply NULL texture state -/*! -*/ -void TextureBaseClass::Apply_Null(unsigned int stage) -{ - // This function sets the render states for a "NULL" texture - DX8Wrapper::Set_DX8_Texture(stage, NULL); -} - -// ---------------------------------------------------------------------------- -// Setting HSV_Shift value is always relative to the original texture. This function invalidates the -// texture surface and causes the texture to be reloaded. For thumbnailable textures, the hue shifting -// is done in the background loading thread. -// ---------------------------------------------------------------------------- -void TextureBaseClass::Set_HSV_Shift(const Vector3 &hsv_shift) -{ - Invalidate(); - HSVShift=hsv_shift; -} - -//********************************************************************************************** -//! Get total locked surface size -/*! KM -*/ -int TextureBaseClass::_Get_Total_Locked_Surface_Size() -{ - int total_locked_surface_size=0; - - HashTemplateIterator ite(WW3DAssetManager::Get_Instance()->Texture_Hash()); - // Loop through all the textures in the manager - for (ite.First ();!ite.Is_Done();ite.Next ()) - { - // Get the current texture - TextureBaseClass* tex=ite.Peek_Value(); - if (!tex->Initialized) - { - total_locked_surface_size+=tex->Get_Texture_Memory_Usage(); - } - } - return total_locked_surface_size; -} - -//********************************************************************************************** -//! Get total texture size -/*! KM -*/ -int TextureBaseClass::_Get_Total_Texture_Size() -{ - int total_texture_size=0; - - HashTemplateIterator ite(WW3DAssetManager::Get_Instance()->Texture_Hash()); - // Loop through all the textures in the manager - for (ite.First ();!ite.Is_Done();ite.Next ()) - { - // Get the current texture - TextureBaseClass* tex=ite.Peek_Value(); - total_texture_size+=tex->Get_Texture_Memory_Usage(); - } - return total_texture_size; -} - -// ---------------------------------------------------------------------------- - - -//********************************************************************************************** -//! Get total lightmap texture size -/*! -*/ -int TextureBaseClass::_Get_Total_Lightmap_Texture_Size() -{ - int total_texture_size=0; - - HashTemplateIterator ite(WW3DAssetManager::Get_Instance()->Texture_Hash()); - // Loop through all the textures in the manager - for (ite.First ();!ite.Is_Done();ite.Next ()) - { - // Get the current texture - TextureBaseClass* tex=ite.Peek_Value(); - if (tex->Is_Lightmap()) - { - total_texture_size+=tex->Get_Texture_Memory_Usage(); - } - } - return total_texture_size; -} - - -//********************************************************************************************** -//! Get total procedural texture size -/*! -*/ -int TextureBaseClass::_Get_Total_Procedural_Texture_Size() -{ - int total_texture_size=0; - - HashTemplateIterator ite(WW3DAssetManager::Get_Instance()->Texture_Hash()); - // Loop through all the textures in the manager - for (ite.First ();!ite.Is_Done();ite.Next ()) - { - // Get the current texture - TextureBaseClass* tex=ite.Peek_Value(); - if (tex->Is_Procedural()) - { - total_texture_size+=tex->Get_Texture_Memory_Usage(); - } - } - return total_texture_size; -} - -//********************************************************************************************** -//! Get total texture count -/*! -*/ -int TextureBaseClass::_Get_Total_Texture_Count() -{ - int texture_count=0; - - HashTemplateIterator ite(WW3DAssetManager::Get_Instance()->Texture_Hash()); - // Loop through all the textures in the manager - for (ite.First ();!ite.Is_Done();ite.Next ()) - { - texture_count++; - } - - return texture_count; -} - -// ---------------------------------------------------------------------------- - - -//********************************************************************************************** -//! Get total light map texture count -/*! -*/ -int TextureBaseClass::_Get_Total_Lightmap_Texture_Count() -{ - int texture_count=0; - - HashTemplateIterator ite(WW3DAssetManager::Get_Instance()->Texture_Hash()); - // Loop through all the textures in the manager - for (ite.First ();!ite.Is_Done();ite.Next ()) - { - if (ite.Peek_Value()->Is_Lightmap()) - { - texture_count++; - } - } - - return texture_count; -} - -//********************************************************************************************** -//! Get total procedural texture count -/*! -*/ -int TextureBaseClass::_Get_Total_Procedural_Texture_Count() -{ - int texture_count=0; - - HashTemplateIterator ite(WW3DAssetManager::Get_Instance()->Texture_Hash()); - // Loop through all the textures in the manager - for (ite.First ();!ite.Is_Done();ite.Next ()) - { - if (ite.Peek_Value()->Is_Procedural()) - { - texture_count++; - } - } - - return texture_count; -} - - -//********************************************************************************************** -//! Get total locked surface count -/*! -*/ -int TextureBaseClass::_Get_Total_Locked_Surface_Count() -{ - int texture_count=0; - - HashTemplateIterator ite(WW3DAssetManager::Get_Instance()->Texture_Hash()); - // Loop through all the textures in the manager - for (ite.First ();!ite.Is_Done();ite.Next ()) - { - // Get the current texture - TextureBaseClass* tex=ite.Peek_Value(); - if (!tex->Initialized) - { - texture_count++; - } - } - - return texture_count; -} - -/************************************************************************* -** TextureClass -*************************************************************************/ -TextureClass::TextureClass -( - unsigned width, - unsigned height, - WW3DFormat format, - MipCountType mip_level_count, - PoolType pool, - bool rendertarget, - bool allow_reduction -) -: TextureBaseClass(width, height, mip_level_count, pool, rendertarget,allow_reduction), - Filter(mip_level_count), - TextureFormat(format) -{ - Initialized=true; - IsProcedural=true; - IsReducible=false; - - switch (format) - { - case WW3D_FORMAT_DXT1: - case WW3D_FORMAT_DXT2: - case WW3D_FORMAT_DXT3: - case WW3D_FORMAT_DXT4: - case WW3D_FORMAT_DXT5: - IsCompressionAllowed=true; - break; - default : break; - } - - D3DPOOL d3dpool=(D3DPOOL)0; - switch(pool) - { - case POOL_DEFAULT : d3dpool=D3DPOOL_DEFAULT; break; - case POOL_MANAGED : d3dpool=D3DPOOL_MANAGED; break; - case POOL_SYSTEMMEM : d3dpool=D3DPOOL_SYSTEMMEM; break; - default: WWASSERT(0); - } - - Poke_Texture - ( - DX8Wrapper::_Create_DX8_Texture - ( - width, - height, - format, - mip_level_count, - d3dpool, - rendertarget - ) - ); - - if (pool==POOL_DEFAULT) - { - Set_Dirty(); - DX8TextureTrackerClass *track=new DX8TextureTrackerClass - ( - width, - height, - format, - mip_level_count, - this, - rendertarget - ); - DX8TextureManagerClass::Add(track); - } - LastAccessed=WW3D::Get_Sync_Time(); -} - - - -// ---------------------------------------------------------------------------- -TextureClass::TextureClass -( - const char *name, - const char *full_path, - MipCountType mip_level_count, - WW3DFormat texture_format, - bool allow_compression, - bool allow_reduction -) -: TextureBaseClass(0, 0, mip_level_count), - Filter(mip_level_count), - TextureFormat(texture_format) -{ - IsCompressionAllowed=allow_compression; - InactivationTime=DEFAULT_INACTIVATION_TIME; // Default inactivation time 30 seconds - IsReducible=allow_reduction; - - switch (TextureFormat) - { - case WW3D_FORMAT_DXT1: - case WW3D_FORMAT_DXT2: - case WW3D_FORMAT_DXT3: - case WW3D_FORMAT_DXT4: - case WW3D_FORMAT_DXT5: - IsCompressionAllowed=true; - break; - case WW3D_FORMAT_U8V8: // Bumpmap - case WW3D_FORMAT_L6V5U5: // Bumpmap - case WW3D_FORMAT_X8L8V8U8: // Bumpmap - // If requesting bumpmap format that isn't available we'll just return the surface in whatever color - // format the texture file is in. (This is illegal case, the format support should always be queried - // before creating a bump texture!) - if (!DX8Wrapper::Is_Initted() || !DX8Wrapper::Get_Current_Caps()->Support_Texture_Format(TextureFormat)) - { - TextureFormat=WW3D_FORMAT_UNKNOWN; - } - // If bump format is valid, make sure compression is not allowed so that we don't even attempt to load - // from a compressed file (quality isn't good enough for bump map). Also disable mipmapping. - else - { - IsCompressionAllowed=false; - MipLevelCount=MIP_LEVELS_1; - Filter.Set_Mip_Mapping(TextureFilterClass::FILTER_TYPE_NONE); - } - break; - default: break; - } - - WWASSERT_PRINT(name && name[0], "TextureClass CTor: NULL or empty texture name"); - int len=strlen(name); - for (int i=0;iGet_Original_Texture_Width(); - Height=thumb->Get_Original_Texture_Height(); - if (MipLevelCount!=MIP_LEVELS_1) { - MipLevelCount=(MipCountType)thumb->Get_Original_Texture_Mip_Level_Count(); - } - } - - LastAccessed=WW3D::Get_Sync_Time(); - - // If the thumbnails are not enabled, init the texture at this point to avoid stalling when the - // mesh is rendered. - if (!WW3D::Get_Thumbnail_Enabled()) - { - if (TextureLoader::Is_DX8_Thread()) - { - Init(); - } - } -} - -// ---------------------------------------------------------------------------- -TextureClass::TextureClass -( - SurfaceClass *surface, - MipCountType mip_level_count -) -: TextureBaseClass(0,0,mip_level_count), - Filter(mip_level_count), - TextureFormat(surface->Get_Surface_Format()) -{ - IsProcedural=true; - Initialized=true; - IsReducible=false; - - SurfaceClass::SurfaceDescription sd; - surface->Get_Description(sd); - Width=sd.Width; - Height=sd.Height; - switch (sd.Format) - { - case WW3D_FORMAT_DXT1: - case WW3D_FORMAT_DXT2: - case WW3D_FORMAT_DXT3: - case WW3D_FORMAT_DXT4: - case WW3D_FORMAT_DXT5: - IsCompressionAllowed=true; - break; - default: break; - } - - Poke_Texture - ( - DX8Wrapper::_Create_DX8_Texture - ( - surface->Peek_D3D_Surface(), - mip_level_count - ) - ); - LastAccessed=WW3D::Get_Sync_Time(); -} - -// ---------------------------------------------------------------------------- -TextureClass::TextureClass(IDirect3DBaseTexture8* d3d_texture) -: TextureBaseClass - ( - 0, - 0, - ((MipCountType)d3d_texture->GetLevelCount()) - ), - Filter((MipCountType)d3d_texture->GetLevelCount()) -{ - Initialized=true; - IsProcedural=true; - IsReducible=false; - - Set_D3D_Base_Texture(d3d_texture); - IDirect3DSurface8* surface; - DX8_ErrorCode(Peek_D3D_Texture()->GetSurfaceLevel(0,&surface)); - D3DSURFACE_DESC d3d_desc; - ::ZeroMemory(&d3d_desc, sizeof(D3DSURFACE_DESC)); - DX8_ErrorCode(surface->GetDesc(&d3d_desc)); - Width=d3d_desc.Width; - Height=d3d_desc.Height; - TextureFormat=D3DFormat_To_WW3DFormat(d3d_desc.Format); - switch (TextureFormat) - { - case WW3D_FORMAT_DXT1: - case WW3D_FORMAT_DXT2: - case WW3D_FORMAT_DXT3: - case WW3D_FORMAT_DXT4: - case WW3D_FORMAT_DXT5: - IsCompressionAllowed=true; - break; - default: break; - } - - LastAccessed=WW3D::Get_Sync_Time(); -} - -//********************************************************************************************** -//! Initialise the texture -/*! -*/ -void TextureClass::Init() -{ - // If the texture has already been initialised we should exit now - if (Initialized) return; - - WWPROFILE("TextureClass::Init"); - - // If the texture has recently been inactivated, increase the inactivation time (this texture obviously - // should not have been inactivated yet). - if (InactivationTime && LastInactivationSyncTime) - { - if ((WW3D::Get_Sync_Time()-LastInactivationSyncTime)Release(); - - Poke_Texture(d3d_texture);//TextureLoadTask->Peek_D3D_Texture(); - d3d_texture->AddRef(); - - if (initialized) Initialized=true; - if (disable_auto_invalidation) InactivationTime = 0; - - WWASSERT(d3d_texture); - IDirect3DSurface8* surface; - DX8_ErrorCode(Peek_D3D_Texture()->GetSurfaceLevel(0,&surface)); - D3DSURFACE_DESC d3d_desc; - ::ZeroMemory(&d3d_desc, sizeof(D3DSURFACE_DESC)); - DX8_ErrorCode(surface->GetDesc(&d3d_desc)); - if (initialized) - { - TextureFormat=D3DFormat_To_WW3DFormat(d3d_desc.Format); - Width=d3d_desc.Width; - Height=d3d_desc.Height; - } - surface->Release(); - -} - - -//********************************************************************************************** -//! Apply texture states -/*! -*/ -void TextureClass::Apply(unsigned int stage) -{ - // Initialization needs to be done when texture is used if it hasn't been done before. - // XBOX always initializes textures at creation time. - if (!Initialized) - { - Init(); - - /* was in battlefield// Non-thumbnailed textures are always initialized when used - if (MipLevelCount==MIP_LEVELS_1) - { - } - // Thumbnailed textures have delayed initialization and a background loading system - else - { - // Limit the number of texture initializations per frame to reduce stuttering - if (TexturesAppliedPerFrameGetSurfaceLevel(level, &d3d_surface)); - SurfaceClass *surface = new SurfaceClass(d3d_surface); - d3d_surface->Release(); - - return surface; -} - -//********************************************************************************************** -//! Get surface description for a mip level -/*! -*/ -void TextureClass::Get_Level_Description( SurfaceClass::SurfaceDescription & desc, unsigned int level ) -{ - SurfaceClass * surf = Get_Surface_Level(level); - if (surf != NULL) { - surf->Get_Description(desc); - } - REF_PTR_RELEASE(surf); -} - -//********************************************************************************************** -//! Get D3D surface from mip level -/*! -*/ -IDirect3DSurface8 *TextureClass::Get_D3D_Surface_Level(unsigned int level) -{ - if (!Peek_D3D_Texture()) - { - WWASSERT_PRINT(0, "Get_D3D_Surface_Level: D3DTexture is NULL!"); - return 0; - } - - IDirect3DSurface8 *d3d_surface = NULL; - DX8_ErrorCode(Peek_D3D_Texture()->GetSurfaceLevel(level, &d3d_surface)); - return d3d_surface; -} - -//********************************************************************************************** -//! Get texture memory usage -/*! -*/ -unsigned TextureClass::Get_Texture_Memory_Usage() const -{ - int size=0; - if (!Peek_D3D_Texture()) return 0; - for (unsigned i=0;iGetLevelCount();++i) - { - D3DSURFACE_DESC desc; - DX8_ErrorCode(Peek_D3D_Texture()->GetLevelDesc(i,&desc)); - size+=desc.Size; - } - return size; -} - - -// Utility functions -TextureClass* Load_Texture(ChunkLoadClass & cload) -{ - // Assume failure - TextureClass *newtex = NULL; - - char name[256]; - if (cload.Open_Chunk () && (cload.Cur_Chunk_ID () == W3D_CHUNK_TEXTURE)) - { - - W3dTextureInfoStruct texinfo; - bool hastexinfo = false; - - /* - ** Read in the texture filename, and a possible texture info structure. - */ - while (cload.Open_Chunk()) { - switch (cload.Cur_Chunk_ID()) { - case W3D_CHUNK_TEXTURE_NAME: - cload.Read(&name,cload.Cur_Chunk_Length()); - break; - - case W3D_CHUNK_TEXTURE_INFO: - cload.Read(&texinfo,sizeof(W3dTextureInfoStruct)); - hastexinfo = true; - break; - }; - cload.Close_Chunk(); - } - cload.Close_Chunk(); - - /* - ** Get the texture from the asset manager - */ - if (hastexinfo) - { - - MipCountType mipcount; - - bool no_lod = ((texinfo.Attributes & W3DTEXTURE_NO_LOD) == W3DTEXTURE_NO_LOD); - - if (no_lod) - { - mipcount = MIP_LEVELS_1; - } - else - { - switch (texinfo.Attributes & W3DTEXTURE_MIP_LEVELS_MASK) { - - case W3DTEXTURE_MIP_LEVELS_ALL: - mipcount = MIP_LEVELS_ALL; - break; - - case W3DTEXTURE_MIP_LEVELS_2: - mipcount = MIP_LEVELS_2; - break; - - case W3DTEXTURE_MIP_LEVELS_3: - mipcount = MIP_LEVELS_3; - break; - - case W3DTEXTURE_MIP_LEVELS_4: - mipcount = MIP_LEVELS_4; - break; - - default: - WWASSERT (false); - mipcount = MIP_LEVELS_ALL; - break; - } - } - - WW3DFormat format=WW3D_FORMAT_UNKNOWN; - - switch (texinfo.Attributes & W3DTEXTURE_TYPE_MASK) - { - - case W3DTEXTURE_TYPE_COLORMAP: - // Do nothing. - break; - - case W3DTEXTURE_TYPE_BUMPMAP: - { - if (DX8Wrapper::Is_Initted() && DX8Wrapper::Get_Current_Caps()->Support_Bump_Envmap()) - { - // No mipmaps to bumpmap for now - mipcount=MIP_LEVELS_1; - - if (DX8Wrapper::Get_Current_Caps()->Support_Texture_Format(WW3D_FORMAT_U8V8)) format=WW3D_FORMAT_U8V8; - else if (DX8Wrapper::Get_Current_Caps()->Support_Texture_Format(WW3D_FORMAT_X8L8V8U8)) format=WW3D_FORMAT_X8L8V8U8; - else if (DX8Wrapper::Get_Current_Caps()->Support_Texture_Format(WW3D_FORMAT_L6V5U5)) format=WW3D_FORMAT_L6V5U5; - } - break; - } - - default: - WWASSERT (false); - break; - } - - newtex = WW3DAssetManager::Get_Instance()->Get_Texture (name, mipcount, format); - - if (no_lod) - { - newtex->Get_Filter().Set_Mip_Mapping(TextureFilterClass::FILTER_TYPE_NONE); - } - bool u_clamp = ((texinfo.Attributes & W3DTEXTURE_CLAMP_U) != 0); - newtex->Get_Filter().Set_U_Addr_Mode(u_clamp ? TextureFilterClass::TEXTURE_ADDRESS_CLAMP : TextureFilterClass::TEXTURE_ADDRESS_REPEAT); - bool v_clamp = ((texinfo.Attributes & W3DTEXTURE_CLAMP_V) != 0); - newtex->Get_Filter().Set_V_Addr_Mode(v_clamp ? TextureFilterClass::TEXTURE_ADDRESS_CLAMP : TextureFilterClass::TEXTURE_ADDRESS_REPEAT); - - } else - { - newtex = WW3DAssetManager::Get_Instance()->Get_Texture(name); - } - - WWASSERT(newtex); - } - - // Return a pointer to the new texture - return newtex; -} - -// Utility function used by Save_Texture -void setup_texture_attributes(TextureClass * tex, W3dTextureInfoStruct * texinfo) -{ - texinfo->Attributes = 0; - - if (tex->Get_Filter().Get_Mip_Mapping() == TextureFilterClass::FILTER_TYPE_NONE) texinfo->Attributes |= W3DTEXTURE_NO_LOD; - if (tex->Get_Filter().Get_U_Addr_Mode() == TextureFilterClass::TEXTURE_ADDRESS_CLAMP) texinfo->Attributes |= W3DTEXTURE_CLAMP_U; - if (tex->Get_Filter().Get_V_Addr_Mode() == TextureFilterClass::TEXTURE_ADDRESS_CLAMP) texinfo->Attributes |= W3DTEXTURE_CLAMP_V; -} - - -void Save_Texture(TextureClass * texture,ChunkSaveClass & csave) -{ - const char * filename; - W3dTextureInfoStruct texinfo; - memset(&texinfo,0,sizeof(texinfo)); - - filename = texture->Get_Full_Path(); - - setup_texture_attributes(texture, &texinfo); - - csave.Begin_Chunk(W3D_CHUNK_TEXTURE_NAME); - csave.Write(filename,strlen(filename)+1); - csave.End_Chunk(); - - if ((texinfo.Attributes != 0) || (texinfo.AnimType != 0) || (texinfo.FrameCount != 0)) { - csave.Begin_Chunk(W3D_CHUNK_TEXTURE_INFO); - csave.Write(&texinfo, sizeof(texinfo)); - csave.End_Chunk(); - } -} - - -/*! - * KJM depth stencil texture constructor - */ -ZTextureClass::ZTextureClass -( - unsigned width, - unsigned height, - WW3DZFormat zformat, - MipCountType mip_level_count, - PoolType pool -) -: TextureBaseClass(width,height, mip_level_count, pool), - DepthStencilTextureFormat(zformat) -{ - D3DPOOL d3dpool=(D3DPOOL)0; - switch (pool) - { - case POOL_DEFAULT: d3dpool=D3DPOOL_DEFAULT; break; - case POOL_MANAGED: d3dpool=D3DPOOL_MANAGED; break; - case POOL_SYSTEMMEM: d3dpool=D3DPOOL_SYSTEMMEM; break; - default: WWASSERT(0); - } - - Poke_Texture - ( - DX8Wrapper::_Create_DX8_ZTexture - ( - width, - height, - zformat, - mip_level_count, - d3dpool - ) - ); - - if (pool==POOL_DEFAULT) - { - Set_Dirty(); - DX8ZTextureTrackerClass *track=new DX8ZTextureTrackerClass - ( - width, - height, - zformat, - mip_level_count, - this - ); - DX8TextureManagerClass::Add(track); - } - Initialized=true; - IsProcedural=true; - IsReducible=false; - - LastAccessed=WW3D::Get_Sync_Time(); -} - - -//********************************************************************************************** -//! Apply depth stencil texture -/*! KM -*/ -void ZTextureClass::Apply(unsigned int stage) -{ - DX8Wrapper::Set_DX8_Texture(stage, Peek_D3D_Base_Texture()); -} - -//********************************************************************************************** -//! Apply new surface to texture -/*! KM -*/ -void ZTextureClass::Apply_New_Surface -( - IDirect3DBaseTexture8* d3d_texture, - bool initialized, - bool disable_auto_invalidation -) -{ - IDirect3DBaseTexture8* d3d_tex=Peek_D3D_Base_Texture(); - - if (d3d_tex) d3d_tex->Release(); - - Poke_Texture(d3d_texture);//TextureLoadTask->Peek_D3D_Texture(); - d3d_texture->AddRef(); - - if (initialized) Initialized=true; - if (disable_auto_invalidation) InactivationTime = 0; - - WWASSERT(Peek_D3D_Texture()); - IDirect3DSurface8* surface; - DX8_ErrorCode(Peek_D3D_Texture()->GetSurfaceLevel(0,&surface)); - D3DSURFACE_DESC d3d_desc; - ::ZeroMemory(&d3d_desc, sizeof(D3DSURFACE_DESC)); - DX8_ErrorCode(surface->GetDesc(&d3d_desc)); - if (initialized) - { - DepthStencilTextureFormat=D3DFormat_To_WW3DZFormat(d3d_desc.Format); - Width=d3d_desc.Width; - Height=d3d_desc.Height; - } - surface->Release(); -} - -//********************************************************************************************** -//! Get D3D surface from mip level -/*! -*/ -IDirect3DSurface8* ZTextureClass::Get_D3D_Surface_Level(unsigned int level) -{ - if (!Peek_D3D_Texture()) - { - WWASSERT_PRINT(0, "Get_D3D_Surface_Level: D3DTexture is NULL!"); - return 0; - } - - IDirect3DSurface8 *d3d_surface = NULL; - DX8_ErrorCode(Peek_D3D_Texture()->GetSurfaceLevel(level, &d3d_surface)); - return d3d_surface; -} - -//********************************************************************************************** -//! Get texture memory usage -/*! -*/ -unsigned ZTextureClass::Get_Texture_Memory_Usage() const -{ - int size=0; - if (!Peek_D3D_Texture()) return 0; - for (unsigned i=0;iGetLevelCount();++i) - { - D3DSURFACE_DESC desc; - DX8_ErrorCode(Peek_D3D_Texture()->GetLevelDesc(i,&desc)); - size+=desc.Size; - } - return size; -} - - - -/************************************************************************* -** CubeTextureClass -*************************************************************************/ -CubeTextureClass::CubeTextureClass -( - unsigned width, - unsigned height, - WW3DFormat format, - MipCountType mip_level_count, - PoolType pool, - bool rendertarget, - bool allow_reduction -) -: TextureClass(width, height, format, mip_level_count, pool, rendertarget) -{ - Initialized=true; - IsProcedural=true; - IsReducible=false; - - switch (format) - { - case WW3D_FORMAT_DXT1: - case WW3D_FORMAT_DXT2: - case WW3D_FORMAT_DXT3: - case WW3D_FORMAT_DXT4: - case WW3D_FORMAT_DXT5: - IsCompressionAllowed=true; - break; - default : break; - } - - D3DPOOL d3dpool=(D3DPOOL)0; - switch(pool) - { - case POOL_DEFAULT : d3dpool=D3DPOOL_DEFAULT; break; - case POOL_MANAGED : d3dpool=D3DPOOL_MANAGED; break; - case POOL_SYSTEMMEM : d3dpool=D3DPOOL_SYSTEMMEM; break; - default: WWASSERT(0); - } - - Poke_Texture - ( - DX8Wrapper::_Create_DX8_Cube_Texture - ( - width, - height, - format, - mip_level_count, - d3dpool, - rendertarget - ) - ); - - if (pool==POOL_DEFAULT) - { - Set_Dirty(); - DX8TextureTrackerClass *track=new DX8TextureTrackerClass - ( - width, - height, - format, - mip_level_count, - this, - rendertarget - ); - DX8TextureManagerClass::Add(track); - } - LastAccessed=WW3D::Get_Sync_Time(); -} - - - -// ---------------------------------------------------------------------------- -CubeTextureClass::CubeTextureClass -( - const char *name, - const char *full_path, - MipCountType mip_level_count, - WW3DFormat texture_format, - bool allow_compression, - bool allow_reduction -) -: TextureClass(0,0,mip_level_count, POOL_MANAGED, false, texture_format) -{ - IsCompressionAllowed=allow_compression; - InactivationTime=DEFAULT_INACTIVATION_TIME; // Default inactivation time 30 seconds - - switch (TextureFormat) - { - case WW3D_FORMAT_DXT1: - case WW3D_FORMAT_DXT2: - case WW3D_FORMAT_DXT3: - case WW3D_FORMAT_DXT4: - case WW3D_FORMAT_DXT5: - IsCompressionAllowed=true; - break; - case WW3D_FORMAT_U8V8: // Bumpmap - case WW3D_FORMAT_L6V5U5: // Bumpmap - case WW3D_FORMAT_X8L8V8U8: // Bumpmap - // If requesting bumpmap format that isn't available we'll just return the surface in whatever color - // format the texture file is in. (This is illegal case, the format support should always be queried - // before creating a bump texture!) - if (!DX8Wrapper::Is_Initted() || !DX8Wrapper::Get_Current_Caps()->Support_Texture_Format(TextureFormat)) - { - TextureFormat=WW3D_FORMAT_UNKNOWN; - } - // If bump format is valid, make sure compression is not allowed so that we don't even attempt to load - // from a compressed file (quality isn't good enough for bump map). Also disable mipmapping. - else - { - IsCompressionAllowed=false; - MipLevelCount=MIP_LEVELS_1; - Filter.Set_Mip_Mapping(TextureFilterClass::FILTER_TYPE_NONE); - } - break; - default: break; - } - - WWASSERT_PRINT(name && name[0], "TextureClass CTor: NULL or empty texture name"); - int len=strlen(name); - for (int i=0;iGet_Original_Texture_Width(); - Height=thumb->Get_Original_Texture_Height(); - if (MipLevelCount!=MIP_LEVELS_1) { - MipLevelCount=(MipCountType)thumb->Get_Original_Texture_Mip_Level_Count(); - } - } - - LastAccessed=WW3D::Get_Sync_Time(); - - // If the thumbnails are not enabled, init the texture at this point to avoid stalling when the - // mesh is rendered. - if (!WW3D::Get_Thumbnail_Enabled()) - { - if (TextureLoader::Is_DX8_Thread()) - { - Init(); - } - } -} - -// don't know if these are needed -#if 0 -// ---------------------------------------------------------------------------- -CubeTextureClass::CubeTextureClass -( - SurfaceClass *surface, - MipCountType mip_level_count -) -: TextureClass(0,0,mip_level_count, POOL_MANAGED, false, surface->Get_Surface_Format()) -{ - IsProcedural=true; - Initialized=true; - IsReducible=false; - - SurfaceClass::SurfaceDescription sd; - surface->Get_Description(sd); - Width=sd.Width; - Height=sd.Height; - switch (sd.Format) - { - case WW3D_FORMAT_DXT1: - case WW3D_FORMAT_DXT2: - case WW3D_FORMAT_DXT3: - case WW3D_FORMAT_DXT4: - case WW3D_FORMAT_DXT5: - IsCompressionAllowed=true; - break; - default: break; - } - - Poke_Texture - ( - DX8Wrapper::_Create_DX8_Cube_Texture - ( - surface->Peek_D3D_Surface(), - mip_level_count - ) - ); - LastAccessed=WW3D::Get_Sync_Time(); -} - -// ---------------------------------------------------------------------------- -CubeTextureClass::CubeTextureClass(IDirect3DBaseTexture8* d3d_texture) -: TextureBaseClass - ( - 0, - 0, - ((MipCountType)d3d_texture->GetLevelCount()) - ), - Filter((MipCountType)d3d_texture->GetLevelCount()) -{ - Initialized=true; - IsProcedural=true; - IsReducible=false; - - Peek_Texture()->AddRef(); - IDirect3DSurface8* surface; - DX8_ErrorCode(Peek_D3D_Texture()->GetSurfaceLevel(0,&surface)); - D3DSURFACE_DESC d3d_desc; - ::ZeroMemory(&d3d_desc, sizeof(D3DSURFACE_DESC)); - DX8_ErrorCode(surface->GetDesc(&d3d_desc)); - Width=d3d_desc.Width; - Height=d3d_desc.Height; - TextureFormat=D3DFormat_To_WW3DFormat(d3d_desc.Format); - switch (TextureFormat) - { - case WW3D_FORMAT_DXT1: - case WW3D_FORMAT_DXT2: - case WW3D_FORMAT_DXT3: - case WW3D_FORMAT_DXT4: - case WW3D_FORMAT_DXT5: - IsCompressionAllowed=true; - break; - default: break; - } - - LastAccessed=WW3D::Get_Sync_Time(); -} -#endif - -//********************************************************************************************** -//! Apply new surface to texture -/*! -*/ -void CubeTextureClass::Apply_New_Surface -( - IDirect3DBaseTexture8* d3d_texture, - bool initialized, - bool disable_auto_invalidation -) -{ - IDirect3DBaseTexture8* d3d_tex=Peek_D3D_Base_Texture(); - - if (d3d_tex) d3d_tex->Release(); - - Poke_Texture(d3d_texture);//TextureLoadTask->Peek_D3D_Texture(); - d3d_texture->AddRef(); - - if (initialized) Initialized=true; - if (disable_auto_invalidation) InactivationTime = 0; - - WWASSERT(d3d_texture); - D3DSURFACE_DESC d3d_desc; - ::ZeroMemory(&d3d_desc, sizeof(D3DSURFACE_DESC)); - DX8_ErrorCode(Peek_D3D_CubeTexture()->GetLevelDesc(0,&d3d_desc)); - - if (initialized) - { - TextureFormat=D3DFormat_To_WW3DFormat(d3d_desc.Format); - Width=d3d_desc.Width; - Height=d3d_desc.Height; - } -} - - -/************************************************************************* -** VolumeTextureClass -*************************************************************************/ -VolumeTextureClass::VolumeTextureClass -( - unsigned width, - unsigned height, - unsigned depth, - WW3DFormat format, - MipCountType mip_level_count, - PoolType pool, - bool rendertarget, - bool allow_reduction -) -: TextureClass(width, height, format, mip_level_count, pool, rendertarget), - Depth(depth) -{ - Initialized=true; - IsProcedural=true; - IsReducible=false; - - switch (format) - { - case WW3D_FORMAT_DXT1: - case WW3D_FORMAT_DXT2: - case WW3D_FORMAT_DXT3: - case WW3D_FORMAT_DXT4: - case WW3D_FORMAT_DXT5: - IsCompressionAllowed=true; - break; - default : break; - } - - D3DPOOL d3dpool=(D3DPOOL)0; - switch(pool) - { - case POOL_DEFAULT : d3dpool=D3DPOOL_DEFAULT; break; - case POOL_MANAGED : d3dpool=D3DPOOL_MANAGED; break; - case POOL_SYSTEMMEM : d3dpool=D3DPOOL_SYSTEMMEM; break; - default: WWASSERT(0); - } - - Poke_Texture - ( - DX8Wrapper::_Create_DX8_Volume_Texture - ( - width, - height, - depth, - format, - mip_level_count, - d3dpool - ) - ); - - if (pool==POOL_DEFAULT) - { - Set_Dirty(); - DX8TextureTrackerClass *track=new DX8TextureTrackerClass - ( - width, - height, - format, - mip_level_count, - this, - rendertarget - ); - DX8TextureManagerClass::Add(track); - } - LastAccessed=WW3D::Get_Sync_Time(); -} - - - -// ---------------------------------------------------------------------------- -VolumeTextureClass::VolumeTextureClass -( - const char *name, - const char *full_path, - MipCountType mip_level_count, - WW3DFormat texture_format, - bool allow_compression, - bool allow_reduction -) -: TextureClass(0,0,mip_level_count, POOL_MANAGED, false, texture_format), - Depth(0) -{ - IsCompressionAllowed=allow_compression; - InactivationTime=DEFAULT_INACTIVATION_TIME; // Default inactivation time 30 seconds - - switch (TextureFormat) - { - case WW3D_FORMAT_DXT1: - case WW3D_FORMAT_DXT2: - case WW3D_FORMAT_DXT3: - case WW3D_FORMAT_DXT4: - case WW3D_FORMAT_DXT5: - IsCompressionAllowed=true; - break; - case WW3D_FORMAT_U8V8: // Bumpmap - case WW3D_FORMAT_L6V5U5: // Bumpmap - case WW3D_FORMAT_X8L8V8U8: // Bumpmap - // If requesting bumpmap format that isn't available we'll just return the surface in whatever color - // format the texture file is in. (This is illegal case, the format support should always be queried - // before creating a bump texture!) - if (!DX8Wrapper::Is_Initted() || !DX8Wrapper::Get_Current_Caps()->Support_Texture_Format(TextureFormat)) - { - TextureFormat=WW3D_FORMAT_UNKNOWN; - } - // If bump format is valid, make sure compression is not allowed so that we don't even attempt to load - // from a compressed file (quality isn't good enough for bump map). Also disable mipmapping. - else - { - IsCompressionAllowed=false; - MipLevelCount=MIP_LEVELS_1; - Filter.Set_Mip_Mapping(TextureFilterClass::FILTER_TYPE_NONE); - } - break; - default: break; - } - - WWASSERT_PRINT(name && name[0], "TextureClass CTor: NULL or empty texture name"); - int len=strlen(name); - for (int i=0;iGet_Original_Texture_Width(); - Height=thumb->Get_Original_Texture_Height(); - if (MipLevelCount!=MIP_LEVELS_1) { - MipLevelCount=(MipCountType)thumb->Get_Original_Texture_Mip_Level_Count(); - } - } - - LastAccessed=WW3D::Get_Sync_Time(); - - // If the thumbnails are not enabled, init the texture at this point to avoid stalling when the - // mesh is rendered. - if (!WW3D::Get_Thumbnail_Enabled()) - { - if (TextureLoader::Is_DX8_Thread()) - { - Init(); - } - } -} - -// don't know if these are needed -#if 0 -// ---------------------------------------------------------------------------- -CubeTextureClass::CubeTextureClass -( - SurfaceClass *surface, - MipCountType mip_level_count -) -: TextureClass(0,0,mip_level_count, POOL_MANAGED, false, surface->Get_Surface_Format()) -{ - IsProcedural=true; - Initialized=true; - IsReducible=false; - - SurfaceClass::SurfaceDescription sd; - surface->Get_Description(sd); - Width=sd.Width; - Height=sd.Height; - switch (sd.Format) - { - case WW3D_FORMAT_DXT1: - case WW3D_FORMAT_DXT2: - case WW3D_FORMAT_DXT3: - case WW3D_FORMAT_DXT4: - case WW3D_FORMAT_DXT5: - IsCompressionAllowed=true; - break; - default: break; - } - - Poke_Texture - ( - DX8Wrapper::_Create_DX8_Cube_Texture - ( - surface->Peek_D3D_Surface(), - mip_level_count - ) - ); - LastAccessed=WW3D::Get_Sync_Time(); -} - -// ---------------------------------------------------------------------------- -CubeTextureClass::CubeTextureClass(IDirect3DBaseTexture8* d3d_texture) -: TextureBaseClass - ( - 0, - 0, - ((MipCountType)d3d_texture->GetLevelCount()) - ), - Filter((MipCountType)d3d_texture->GetLevelCount()) -{ - Initialized=true; - IsProcedural=true; - IsReducible=false; - - Peek_Texture()->AddRef(); - IDirect3DSurface8* surface; - DX8_ErrorCode(Peek_D3D_Texture()->GetSurfaceLevel(0,&surface)); - D3DSURFACE_DESC d3d_desc; - ::ZeroMemory(&d3d_desc, sizeof(D3DSURFACE_DESC)); - DX8_ErrorCode(surface->GetDesc(&d3d_desc)); - Width=d3d_desc.Width; - Height=d3d_desc.Height; - TextureFormat=D3DFormat_To_WW3DFormat(d3d_desc.Format); - switch (TextureFormat) - { - case WW3D_FORMAT_DXT1: - case WW3D_FORMAT_DXT2: - case WW3D_FORMAT_DXT3: - case WW3D_FORMAT_DXT4: - case WW3D_FORMAT_DXT5: - IsCompressionAllowed=true; - break; - default: break; - } - - LastAccessed=WW3D::Get_Sync_Time(); -} -#endif - - - - -//********************************************************************************************** -//! Apply new surface to texture -/*! -*/ -void VolumeTextureClass::Apply_New_Surface -( - IDirect3DBaseTexture8* d3d_texture, - bool initialized, - bool disable_auto_invalidation -) -{ - IDirect3DBaseTexture8* d3d_tex=Peek_D3D_Base_Texture(); - - if (d3d_tex) d3d_tex->Release(); - - Poke_Texture(d3d_texture);//TextureLoadTask->Peek_D3D_Texture(); - d3d_texture->AddRef(); - - if (initialized) Initialized=true; - if (disable_auto_invalidation) InactivationTime = 0; - - WWASSERT(d3d_texture); - D3DVOLUME_DESC d3d_desc; - ::ZeroMemory(&d3d_desc, sizeof(D3DVOLUME_DESC)); - - DX8_ErrorCode(Peek_D3D_VolumeTexture()->GetLevelDesc(0,&d3d_desc)); - - if (initialized) - { - TextureFormat=D3DFormat_To_WW3DFormat(d3d_desc.Format); - Width=d3d_desc.Width; - Height=d3d_desc.Height; - Depth=d3d_desc.Depth; - } -} diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/texture.h b/Generals/Code/Libraries/Source/WWVegas/WW3D2/texture.h deleted file mode 100644 index 47eff85d7fb..00000000000 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/texture.h +++ /dev/null @@ -1,475 +0,0 @@ -/* -** 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 . -*/ - -/*********************************************************************************************** - *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** - *********************************************************************************************** - * * - * Project Name : WW3D * - * * - * $Archive:: /Commando/Code/ww3d2/texture.h $* - * * - * $Org Author:: Jani_p $* - * * - * Author : Kenny Mitchell * - * * - * $Modtime:: 08/05/02 1:27p $* - * * - * $Revision:: 46 $* - * * - * 05/16/02 KM Base texture class to abstract major texture types, e.g. 3d, z, cube, etc. - * 06/27/02 KM Texture class abstraction * - * 08/05/02 KM Texture class redesign (revisited) - *---------------------------------------------------------------------------------------------* - * Functions: * - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - -#pragma once - -#include "always.h" -#include "chunkio.h" -#include "surfaceclass.h" -#include "ww3dformat.h" -#include "wwstring.h" -#include "vector3.h" -#include "texturefilter.h" - -struct IDirect3DBaseTexture8; -struct IDirect3DTexture8; -struct IDirect3DCubeTexture8; -struct IDirect3DVolumeTexture8; - -class DX8Wrapper; -class TextureLoader; -class LoaderThreadClass; -class TextureLoadTaskClass; -class CubeTextureClass; -class VolumeTextureClass; - -class TextureBaseClass : public RefCountClass -{ - friend class TextureLoader; - friend class LoaderThreadClass; - friend class DX8TextureTrackerClass; //(gth) so it can call Poke_Texture, - friend class DX8ZTextureTrackerClass; - -public: - - enum PoolType - { - POOL_DEFAULT=0, - POOL_MANAGED, - POOL_SYSTEMMEM - }; - - enum TexAssetType - { - TEX_REGULAR, - TEX_CUBEMAP, - TEX_VOLUME - }; - - // base constructor for derived classes - TextureBaseClass - ( - unsigned width, - unsigned height, - MipCountType mip_level_count=MIP_LEVELS_ALL, - PoolType pool=POOL_MANAGED, - bool rendertarget=false, - bool reducible=true - ); - - virtual ~TextureBaseClass(); - - virtual TexAssetType Get_Asset_Type() const=0; - - // Names - void Set_Texture_Name(const char * name); - void Set_Full_Path(const char * path) { FullPath = path; } - const StringClass& Get_Texture_Name(void) const { return Name; } - const StringClass& Get_Full_Path(void) const { if (FullPath.Is_Empty ()) return Name; return FullPath; } - - unsigned Get_ID() const { return texture_id; } // Each textrure has a unique id - - // The number of Mip levels in the texture - unsigned int Get_Mip_Level_Count(void) const - { - return MipLevelCount; - } - - // Note! Width and Height may be zero and may change if texture uses mipmaps - int Get_Width() const - { - return Width; - } - int Get_Height() const - { - return Height; - } - - // Time, after which the texture is invalidated if not used. Set to zero to indicate infinite. - // Time is in milliseconds. - void Set_Inactivation_Time(unsigned time) { InactivationTime=time; } - int Get_Inactivation_Time() const { return InactivationTime; } - - // Texture priority affects texture management and caching. - unsigned int Get_Priority(void); - unsigned int Set_Priority(unsigned int priority); // Returns previous priority - - // Debug utility functions for returning the texture memory usage - virtual unsigned Get_Texture_Memory_Usage() const=0; - - bool Is_Initialized() const { return Initialized; } - bool Is_Lightmap() const { return IsLightmap; } - bool Is_Procedural() const { return IsProcedural; } - bool Is_Reducible() const { return IsReducible; } //can texture be reduced in resolution for LOD purposes? - - static int _Get_Total_Locked_Surface_Size(); - static int _Get_Total_Texture_Size(); - static int _Get_Total_Lightmap_Texture_Size(); - static int _Get_Total_Procedural_Texture_Size(); - static int _Get_Total_Locked_Surface_Count(); - static int _Get_Total_Texture_Count(); - static int _Get_Total_Lightmap_Texture_Count(); - static int _Get_Total_Procedural_Texture_Count(); - - virtual void Init()=0; - - // This utility function processes the texture reduction (used during rendering) - void Invalidate(); - - // texture accessors (dx8) - IDirect3DBaseTexture8 *Peek_D3D_Base_Texture() const; - void Set_D3D_Base_Texture(IDirect3DBaseTexture8* tex); - - PoolType Get_Pool() const { return Pool; } - - bool Is_Missing_Texture(); - - // Support for self managed textures - bool Is_Dirty() { WWASSERT(Pool==POOL_DEFAULT); return Dirty; }; - void Set_Dirty() { WWASSERT(Pool==POOL_DEFAULT); Dirty=true; } - void Clean() { Dirty=false; }; - - void Set_HSV_Shift(const Vector3 &hsv_shift); - const Vector3& Get_HSV_Shift() { return HSVShift; } - - bool Is_Compression_Allowed() const { return IsCompressionAllowed; } - - unsigned Get_Reduction() const; - - // Background texture loader will call this when texture has been loaded - virtual void Apply_New_Surface(IDirect3DBaseTexture8* tex, bool initialized, bool disable_auto_invalidation = false)=0; // If the parameter is true, the texture will be flagged as initialised - - MipCountType MipLevelCount; - - // Inactivate textures that haven't been used in a while. Pass zero to use textures' - // own inactive times (default). In urgent need to free up texture memory, try - // calling with relatively small (just few seconds) time override to free up everything - // but the currently used textures. - static void Invalidate_Old_Unused_Textures(unsigned inactive_time_override); - - // Apply this texture's settings into D3D - virtual void Apply(unsigned int stage)=0; - - // Apply a Null texture's settings into D3D - static void Apply_Null(unsigned int stage); - - virtual TextureClass* As_TextureClass() { return NULL; } - virtual CubeTextureClass* As_CubeTextureClass() { return NULL; } - virtual VolumeTextureClass* As_VolumeTextureClass() { return NULL; } - - IDirect3DTexture8* Peek_D3D_Texture() const { return (IDirect3DTexture8*)Peek_D3D_Base_Texture(); } - IDirect3DVolumeTexture8* Peek_D3D_VolumeTexture() const { return (IDirect3DVolumeTexture8*)Peek_D3D_Base_Texture(); } - IDirect3DCubeTexture8* Peek_D3D_CubeTexture() const { return (IDirect3DCubeTexture8*)Peek_D3D_Base_Texture(); } - -protected: - - void Load_Locked_Surface(); - void Poke_Texture(IDirect3DBaseTexture8* tex) { D3DTexture = tex; } - - bool Initialized; - - // For debug purposes the texture sets this true if it is a lightmap texture - bool IsLightmap; - bool IsCompressionAllowed; - bool IsProcedural; - bool IsReducible; - - - unsigned InactivationTime; // In milliseconds - unsigned ExtendedInactivationTime; // This is set by the engine, if needed - unsigned LastInactivationSyncTime; - mutable unsigned LastAccessed; - - // If this is non-zero, the texture will have a hue shift done at the next init (this - // value should only be changed by Set_HSV_Shift() function, which also invalidates the - // texture). - Vector3 HSVShift; - - int Width; - int Height; - -private: - - // Direct3D texture object - IDirect3DBaseTexture8 *D3DTexture; - - // Name - StringClass Name; - StringClass FullPath; - - // Unique id - unsigned texture_id; - - // Support for self-managed textures - - PoolType Pool; - bool Dirty; - - friend class TextureLoadTaskClass; - friend class CubeTextureLoadTaskClass; - friend class VolumeTextureLoadTaskClass; - TextureLoadTaskClass* TextureLoadTask; - TextureLoadTaskClass* ThumbnailLoadTask; - -}; - - -/************************************************************************* -** TextureClass -** -** This is our regular texture class. For legacy reasons it contains some -** information beyond the D3D texture itself, such as texture addressing -** modes. -** -*************************************************************************/ -class TextureClass : public TextureBaseClass -{ - W3DMPO_GLUE(TextureClass) -// friend DX8Wrapper; - -public: - - // Create texture with desired height, width and format. - TextureClass - ( - unsigned width, - unsigned height, - WW3DFormat format, - MipCountType mip_level_count=MIP_LEVELS_ALL, - PoolType pool=POOL_MANAGED, - bool rendertarget=false, - bool allow_reduction=true - ); - - // Create texture from a file. If format is specified the texture is converted to that format. - // Note that the format must be supported by the current device and that a texture can't exist - // in the system with the same name in multiple formats. - TextureClass - ( - const char *name, - const char *full_path=NULL, - MipCountType mip_level_count=MIP_LEVELS_ALL, - WW3DFormat texture_format=WW3D_FORMAT_UNKNOWN, - bool allow_compression=true, - bool allow_reduction=true - ); - - // Create texture from a surface. - TextureClass - ( - SurfaceClass *surface, - MipCountType mip_level_count=MIP_LEVELS_ALL - ); - - TextureClass(IDirect3DBaseTexture8* d3d_texture); - - // defualt constructors for derived classes (cube & vol) - TextureClass - ( - unsigned width, - unsigned height, - MipCountType mip_level_count=MIP_LEVELS_ALL, - PoolType pool=POOL_MANAGED, - bool rendertarget=false, - WW3DFormat format=WW3D_FORMAT_UNKNOWN, - bool allow_reduction=true - ) - : TextureBaseClass(width,height,mip_level_count,pool,rendertarget,allow_reduction), TextureFormat(format), Filter(mip_level_count) { } - - virtual TexAssetType Get_Asset_Type() const { return TEX_REGULAR; } - - virtual void Init(); - - // Background texture loader will call this when texture has been loaded - virtual void Apply_New_Surface(IDirect3DBaseTexture8* tex, bool initialized, bool disable_auto_invalidation = false); // If the parameter is true, the texture will be flagged as initialised - - // Get the surface of one of the mipmap levels (defaults to highest-resolution one) - SurfaceClass *Get_Surface_Level(unsigned int level = 0); - IDirect3DSurface8 *Get_D3D_Surface_Level(unsigned int level = 0); - void Get_Level_Description( SurfaceClass::SurfaceDescription & desc, unsigned int level = 0 ); - - TextureFilterClass& Get_Filter() { return Filter; } - - WW3DFormat Get_Texture_Format() const { return TextureFormat; } - - virtual void Apply(unsigned int stage); - - virtual unsigned Get_Texture_Memory_Usage() const; - - virtual TextureClass* As_TextureClass() { return this; } - -protected: - - WW3DFormat TextureFormat; - - // legacy - TextureFilterClass Filter; -}; - -class ZTextureClass : public TextureBaseClass -{ -public: - // Create a z texture with desired height, width and format - ZTextureClass - ( - unsigned width, - unsigned height, - WW3DZFormat zformat, - MipCountType mip_level_count=MIP_LEVELS_ALL, - PoolType pool=POOL_MANAGED - ); - - WW3DZFormat Get_Texture_Format() const { return DepthStencilTextureFormat; } - - virtual TexAssetType Get_Asset_Type() const { return TEX_REGULAR; } - - virtual void Init() {} - - // Background texture loader will call this when texture has been loaded - virtual void Apply_New_Surface(IDirect3DBaseTexture8* tex, bool initialized, bool disable_auto_invalidation = false); // If the parameter is true, the texture will be flagged as initialised - - virtual void Apply(unsigned int stage); - - IDirect3DSurface8 *Get_D3D_Surface_Level(unsigned int level = 0); - virtual unsigned Get_Texture_Memory_Usage() const; - -private: - - WW3DZFormat DepthStencilTextureFormat; -}; - -class CubeTextureClass : public TextureClass -{ -public: - // Create texture with desired height, width and format. - CubeTextureClass - ( - unsigned width, - unsigned height, - WW3DFormat format, - MipCountType mip_level_count=MIP_LEVELS_ALL, - PoolType pool=POOL_MANAGED, - bool rendertarget=false, - bool allow_reduction=true - ); - - // Create texture from a file. If format is specified the texture is converted to that format. - // Note that the format must be supported by the current device and that a texture can't exist - // in the system with the same name in multiple formats. - CubeTextureClass - ( - const char *name, - const char *full_path=NULL, - MipCountType mip_level_count=MIP_LEVELS_ALL, - WW3DFormat texture_format=WW3D_FORMAT_UNKNOWN, - bool allow_compression=true, - bool allow_reduction=true - ); - - // Create texture from a surface. - CubeTextureClass - ( - SurfaceClass *surface, - MipCountType mip_level_count=MIP_LEVELS_ALL - ); - - CubeTextureClass(IDirect3DBaseTexture8* d3d_texture); - - virtual void Apply_New_Surface(IDirect3DBaseTexture8* tex, bool initialized, bool disable_auto_invalidation = false); // If the parameter is true, the texture will be flagged as initialised - - virtual TexAssetType Get_Asset_Type() const { return TEX_CUBEMAP; } - - virtual CubeTextureClass* As_CubeTextureClass() { return this; } - -}; - -class VolumeTextureClass : public TextureClass -{ -public: - // Create texture with desired height, width and format. - VolumeTextureClass - ( - unsigned width, - unsigned height, - unsigned depth, - WW3DFormat format, - MipCountType mip_level_count=MIP_LEVELS_ALL, - PoolType pool=POOL_MANAGED, - bool rendertarget=false, - bool allow_reduction=true - ); - - // Create texture from a file. If format is specified the texture is converted to that format. - // Note that the format must be supported by the current device and that a texture can't exist - // in the system with the same name in multiple formats. - VolumeTextureClass - ( - const char *name, - const char *full_path=NULL, - MipCountType mip_level_count=MIP_LEVELS_ALL, - WW3DFormat texture_format=WW3D_FORMAT_UNKNOWN, - bool allow_compression=true, - bool allow_reduction=true - ); - - // Create texture from a surface. - VolumeTextureClass - ( - SurfaceClass *surface, - MipCountType mip_level_count=MIP_LEVELS_ALL - ); - - VolumeTextureClass(IDirect3DBaseTexture8* d3d_texture); - - virtual void Apply_New_Surface(IDirect3DBaseTexture8* tex, bool initialized, bool disable_auto_invalidation = false); // If the parameter is true, the texture will be flagged as initialised - - virtual TexAssetType Get_Asset_Type() const { return TEX_VOLUME; } - - virtual VolumeTextureClass* As_VolumeTextureClass() { return this; } - -protected: - - int Depth; -}; - -// Utility functions for loading and saving texture descriptions from/to W3D files -TextureClass *Load_Texture(ChunkLoadClass & cload); -void Save_Texture(TextureClass * texture, ChunkSaveClass & csave); diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/texturefilter.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/texturefilter.cpp deleted file mode 100644 index 690faf2ef46..00000000000 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/texturefilter.cpp +++ /dev/null @@ -1,251 +0,0 @@ -/* -** 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 . -*/ - -/*********************************************************************************************** - *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** - *********************************************************************************************** - * * - * Project Name : WW3D * - * * - * $Archive:: ww3d2/texturefilter.cpp $* - * * - * $Org Author:: Kenny Mitchell $* - * * - * Author : Kenny Mitchell * - * * - * $Modtime:: 08/05/02 1:27p $* - * * - * $Revision:: 1 $* - * * - * 08/05/02 KM Texture filter class abstraction * - *---------------------------------------------------------------------------------------------* - * Functions: * - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - -#include "texturefilter.h" -#include "dx8wrapper.h" - -unsigned _MinTextureFilters[MAX_TEXTURE_STAGES][TextureFilterClass::FILTER_TYPE_COUNT]; -unsigned _MagTextureFilters[MAX_TEXTURE_STAGES][TextureFilterClass::FILTER_TYPE_COUNT]; -unsigned _MipMapFilters[MAX_TEXTURE_STAGES][TextureFilterClass::FILTER_TYPE_COUNT]; - -/************************************************************************* -** TextureFilterClass -*************************************************************************/ -TextureFilterClass::TextureFilterClass(MipCountType mip_level_count) -: TextureMinFilter(FILTER_TYPE_DEFAULT), - TextureMagFilter(FILTER_TYPE_DEFAULT), - UAddressMode(TEXTURE_ADDRESS_REPEAT), - VAddressMode(TEXTURE_ADDRESS_REPEAT) -{ - if (mip_level_count!=MIP_LEVELS_1) - { - MipMapFilter=FILTER_TYPE_DEFAULT; - } - else - { - MipMapFilter=FILTER_TYPE_NONE; - } -} - -//********************************************************************************************** -//! Apply filters (legacy) -/*! -*/ -void TextureFilterClass::Apply(unsigned int stage) -{ - DX8Wrapper::Set_DX8_Texture_Stage_State(stage,D3DTSS_MINFILTER,_MinTextureFilters[stage][TextureMinFilter]); - DX8Wrapper::Set_DX8_Texture_Stage_State(stage,D3DTSS_MAGFILTER,_MagTextureFilters[stage][TextureMagFilter]); - DX8Wrapper::Set_DX8_Texture_Stage_State(stage,D3DTSS_MIPFILTER,_MipMapFilters[stage][MipMapFilter]); - - switch (Get_U_Addr_Mode()) - { - case TEXTURE_ADDRESS_REPEAT: - DX8Wrapper::Set_DX8_Texture_Stage_State(stage, D3DTSS_ADDRESSU, D3DTADDRESS_WRAP); - break; - - case TEXTURE_ADDRESS_CLAMP: - DX8Wrapper::Set_DX8_Texture_Stage_State(stage, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP); - break; - } - - switch (Get_V_Addr_Mode()) - { - case TEXTURE_ADDRESS_REPEAT: - DX8Wrapper::Set_DX8_Texture_Stage_State(stage, D3DTSS_ADDRESSV, D3DTADDRESS_WRAP); - break; - - case TEXTURE_ADDRESS_CLAMP: - DX8Wrapper::Set_DX8_Texture_Stage_State(stage, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP); - break; - } -} - -//********************************************************************************************** -//! Init filters (legacy) -/*! -*/ -void TextureFilterClass::_Init_Filters(TextureFilterMode filter_type) -{ - const D3DCAPS8& dx8caps=DX8Wrapper::Get_Current_Caps()->Get_DX8_Caps(); - -#ifndef _XBOX - _MinTextureFilters[0][FILTER_TYPE_NONE]=D3DTEXF_POINT; - _MagTextureFilters[0][FILTER_TYPE_NONE]=D3DTEXF_POINT; - _MipMapFilters[0][FILTER_TYPE_NONE]=D3DTEXF_NONE; - - _MinTextureFilters[0][FILTER_TYPE_FAST]=D3DTEXF_LINEAR; - _MagTextureFilters[0][FILTER_TYPE_FAST]=D3DTEXF_LINEAR; - _MipMapFilters[0][FILTER_TYPE_FAST]=D3DTEXF_POINT; - - _MagTextureFilters[0][FILTER_TYPE_BEST]=D3DTEXF_POINT; - _MinTextureFilters[0][FILTER_TYPE_BEST]=D3DTEXF_POINT; - _MipMapFilters[0][FILTER_TYPE_BEST]=D3DTEXF_POINT; -#else - _MinTextureFilters[0][FILTER_TYPE_NONE]=D3DTEXF_ANISOTROPIC; - _MagTextureFilters[0][FILTER_TYPE_NONE]=D3DTEXF_ANISOTROPIC; - _MipMapFilters[0][FILTER_TYPE_NONE]=D3DTEXF_LINEAR; - - _MinTextureFilters[0][FILTER_TYPE_FAST]=D3DTEXF_ANISOTROPIC; - _MagTextureFilters[0][FILTER_TYPE_FAST]=D3DTEXF_ANISOTROPIC; - _MipMapFilters[0][FILTER_TYPE_FAST]=D3DTEXF_LINEAR; - - _MagTextureFilters[0][FILTER_TYPE_BEST]=D3DTEXF_ANISOTROPIC; - _MinTextureFilters[0][FILTER_TYPE_BEST]=D3DTEXF_ANISOTROPIC; - _MipMapFilters[0][FILTER_TYPE_BEST]=D3DTEXF_LINEAR; -#endif - -#ifndef _XBOX - if (dx8caps.TextureFilterCaps&D3DPTFILTERCAPS_MAGFLINEAR) _MagTextureFilters[0][FILTER_TYPE_BEST]=D3DTEXF_LINEAR; - if (dx8caps.TextureFilterCaps&D3DPTFILTERCAPS_MINFLINEAR) _MinTextureFilters[0][FILTER_TYPE_BEST]=D3DTEXF_LINEAR; - - // Set anisotropic filtering only if requested and available - if (filter_type==TEXTURE_FILTER_ANISOTROPIC) { - if (dx8caps.TextureFilterCaps&D3DPTFILTERCAPS_MAGFANISOTROPIC) _MagTextureFilters[0][FILTER_TYPE_BEST]=D3DTEXF_ANISOTROPIC; - if (dx8caps.TextureFilterCaps&D3DPTFILTERCAPS_MINFANISOTROPIC) _MinTextureFilters[0][FILTER_TYPE_BEST]=D3DTEXF_ANISOTROPIC; - } - - // Set linear mip filter only if requested trilinear or anisotropic, and linear available - if (filter_type==TEXTURE_FILTER_ANISOTROPIC || filter_type==TEXTURE_FILTER_TRILINEAR) { - if (dx8caps.TextureFilterCaps&D3DPTFILTERCAPS_MIPFLINEAR) _MipMapFilters[0][FILTER_TYPE_BEST]=D3DTEXF_LINEAR; - } -#endif - - // For stages above zero, set best filter to the same as the stage zero, except if anisotropic - int i=1; - for (;i. -*/ - -/*********************************************************************************************** - *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** - *********************************************************************************************** - * * - * Project Name : WW3D * - * * - * $Archive:: ww3d2/texturefilter.h $* - * * - * $Org Author:: Kenny Mitchell $* - * * - * Author : Kenny Mitchell * - * * - * $Modtime:: 08/05/02 1:27p $* - * * - * $Revision:: 1 $* - * * - * 08/05/02 KM Texture filter class abstraction * - *---------------------------------------------------------------------------------------------* - * Functions: * - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - -#pragma once - -#ifndef DX8_WRAPPER_H -//#include "dx8wrapper.h" -#endif - -enum MipCountType -{ - MIP_LEVELS_ALL=0, // generate all mipmap levels down to 1x1 size - MIP_LEVELS_1, // no mipmapping at all (just one mip level) - MIP_LEVELS_2, - MIP_LEVELS_3, - MIP_LEVELS_4, - MIP_LEVELS_5, - MIP_LEVELS_6, - MIP_LEVELS_7, - MIP_LEVELS_8, - MIP_LEVELS_10, - MIP_LEVELS_11, - MIP_LEVELS_12, - MIP_LEVELS_MAX // This isn't to be used (use MIP_LEVELS_ALL instead), it is just an enum for creating static tables etc. -}; - - -// NOTE: Since "texture wrapping" (NOT TEXTURE WRAP MODE - THIS IS -// SOMETHING ELSE) is a global state that affects all texture stages, -// and this class only affects its own stage, we will not worry about -// it for now. Later (probably when we implement world-oriented -// environment maps) we will consider where to put it. - -// This is legacy and should be phased out into wwshade shader states -// keeping as an abstracted class for now to support this transition later -class TextureFilterClass -{ -public: - - enum FilterType - { - FILTER_TYPE_NONE, - FILTER_TYPE_FAST, - FILTER_TYPE_BEST, - FILTER_TYPE_DEFAULT, - FILTER_TYPE_COUNT - }; - - enum TextureFilterMode - { - TEXTURE_FILTER_BILINEAR, - TEXTURE_FILTER_TRILINEAR, - TEXTURE_FILTER_ANISOTROPIC - }; - - enum TxtAddrMode - { - TEXTURE_ADDRESS_REPEAT=0, - TEXTURE_ADDRESS_CLAMP - }; - - TextureFilterClass(MipCountType mip_level_count=MIP_LEVELS_1); - - void Apply(unsigned int stage); - - // Filter and MIPmap settings: - FilterType Get_Min_Filter(void) const { return TextureMinFilter; } - FilterType Get_Mag_Filter(void) const { return TextureMagFilter; } - FilterType Get_Mip_Mapping(void) const { return MipMapFilter; } - void Set_Min_Filter(FilterType filter) { TextureMinFilter=filter; } - void Set_Mag_Filter(FilterType filter) { TextureMagFilter=filter; } - void Set_Mip_Mapping(FilterType mipmap); - - // Texture address mode - TxtAddrMode Get_U_Addr_Mode(void) const { return UAddressMode; } - TxtAddrMode Get_V_Addr_Mode(void) const { return VAddressMode; } - void Set_U_Addr_Mode(TxtAddrMode mode) { UAddressMode=mode; } - void Set_V_Addr_Mode(TxtAddrMode mode) { VAddressMode=mode; } - - // This needs to be called after device has been created - static void _Init_Filters(TextureFilterMode texture_filter); - - static void _Set_Default_Min_Filter(FilterType filter); - static void _Set_Default_Mag_Filter(FilterType filter); - static void _Set_Default_Mip_Filter(FilterType filter); - -private: - // State not contained in the Direct3D texture object: - FilterType TextureMinFilter; - FilterType TextureMagFilter; - FilterType MipMapFilter; - TxtAddrMode UAddressMode; - TxtAddrMode VAddressMode; -}; diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/textureloader.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/textureloader.cpp deleted file mode 100644 index 48f060f10c9..00000000000 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/textureloader.cpp +++ /dev/null @@ -1,2819 +0,0 @@ -/* -** 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 . -*/ - -/*********************************************************************************************** - *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** - *********************************************************************************************** - * * - * Project Name : DX8 Texture Manager * - * * - * $Archive:: /Commando/Code/ww3d2/textureloader.h $* - * * - * Original Author:: vss_sync * - * * - * Author : Kenny Mitchell * - * * - * $Modtime:: 08/05/02 10:03a $* - * * - * $Revision:: 3 $* - * * - * 06/27/02 KM Texture class abstraction * - * 08/05/02 KM Texture class redesign (revisited) - *---------------------------------------------------------------------------------------------* - * Functions: * - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - -#include "textureloader.h" -#include "mutex.h" -#include "thread.h" -#include "wwdebug.h" -#include "texture.h" -#include "ffactory.h" -#include "wwstring.h" -#include "bufffile.h" -#include "ww3d.h" -#include "assetmgr.h" -#include "dx8wrapper.h" -#include "dx8caps.h" -#include "missingtexture.h" -#include "TARGA.h" -#include -#include "wwmemlog.h" -#include "formconv.h" -#include "texturethumbnail.h" -#include "ddsfile.h" -#include "bitmaphandler.h" -#include "wwprofile.h" - -bool TextureLoader::TextureLoadSuspended; -int TextureLoader::TextureInactiveOverrideTime = 0; - -#define USE_MANAGED_TEXTURES - -//////////////////////////////////////////////////////////////////////////////// -// -// TextureLoadTaskListClass implementation -// -//////////////////////////////////////////////////////////////////////////////// - -TextureLoadTaskListClass::TextureLoadTaskListClass(void) -: Root() -{ - Root.Next = Root.Prev = &Root; -} - -void TextureLoadTaskListClass::Push_Front (TextureLoadTaskClass *task) -{ - // task should non-null and not on any list - WWASSERT(task != NULL && task->Next == NULL && task->Prev == NULL); - - // update inserted task to point to list - task->Next = Root.Next; - task->Prev = &Root; - task->List = this; - - // update list to point to inserted task - Root.Next->Prev = task; - Root.Next = task; -} - -void TextureLoadTaskListClass::Push_Back(TextureLoadTaskClass *task) -{ - // task should be non-null and not on any list - WWASSERT(task != NULL && task->Next == NULL && task->Prev == NULL); - - // update inserted task to point to list - task->Next = &Root; - task->Prev = Root.Prev; - task->List = this; - - // update list to point to inserted task - Root.Prev->Next = task; - Root.Prev = task; -} - -TextureLoadTaskClass *TextureLoadTaskListClass::Pop_Front(void) -{ - // exit early if list is empty - if (Is_Empty()) { - return 0; - } - - // otherwise, grab first task and remove it. - TextureLoadTaskClass *task = (TextureLoadTaskClass *)Root.Next; - Remove(task); - return task; - -} - -TextureLoadTaskClass *TextureLoadTaskListClass::Pop_Back(void) -{ - // exit early if list is empty - if (Is_Empty()) { - return 0; - } - - // otherwise, grab last task and remove it. - TextureLoadTaskClass *task = (TextureLoadTaskClass *)Root.Prev; - Remove(task); - return task; -} - -void TextureLoadTaskListClass::Remove(TextureLoadTaskClass *task) -{ - // exit early if task is not on this list. - if (task->List != this) { - return; - } - - // update list to skip task - task->Prev->Next = task->Next; - task->Next->Prev = task->Prev; - - // update task to no longer point at list - task->Prev = 0; - task->Next = 0; - task->List = 0; -} - - -//////////////////////////////////////////////////////////////////////////////// -// -// SynchronizedTextureLoadTaskListClass implementation -// -//////////////////////////////////////////////////////////////////////////////// - -SynchronizedTextureLoadTaskListClass::SynchronizedTextureLoadTaskListClass(void) -: TextureLoadTaskListClass(), - CriticalSection() -{ -} - -void SynchronizedTextureLoadTaskListClass::Push_Front(TextureLoadTaskClass *task) -{ - FastCriticalSectionClass::LockClass lock(CriticalSection); - TextureLoadTaskListClass::Push_Front(task); -} - -void SynchronizedTextureLoadTaskListClass::Push_Back(TextureLoadTaskClass *task) -{ - FastCriticalSectionClass::LockClass lock(CriticalSection); - TextureLoadTaskListClass::Push_Back(task); -} - -TextureLoadTaskClass *SynchronizedTextureLoadTaskListClass::Pop_Front(void) -{ - // this duplicates code inside base class, but saves us an unnecessary lock. - if (Is_Empty()) { - return 0; - } - - FastCriticalSectionClass::LockClass lock(CriticalSection); - return TextureLoadTaskListClass::Pop_Front(); - -} - -TextureLoadTaskClass *SynchronizedTextureLoadTaskListClass::Pop_Back(void) -{ - // this duplicates code inside base class, but saves us an unnecessary lock. - if (Is_Empty()) { - return 0; - } - - FastCriticalSectionClass::LockClass lock(CriticalSection); - return TextureLoadTaskListClass::Pop_Back(); -} - -void SynchronizedTextureLoadTaskListClass::Remove(TextureLoadTaskClass *task) -{ - FastCriticalSectionClass::LockClass lock(CriticalSection); - TextureLoadTaskListClass::Remove(task); -} - - -// Locks - -// To prevent deadlock, threads should acquire locks in the order in which -// they are defined below. No ordering is necessary for the task list locks, -// since one thread can never hold two at once. - -static FastCriticalSectionClass _ForegroundCriticalSection; -static FastCriticalSectionClass _BackgroundCriticalSection; - -// Lists - -static SynchronizedTextureLoadTaskListClass _ForegroundQueue; -static SynchronizedTextureLoadTaskListClass _BackgroundQueue; - -static TextureLoadTaskListClass _TexLoadFreeList; -static TextureLoadTaskListClass _CubeTexLoadFreeList; -static TextureLoadTaskListClass _VolTexLoadFreeList; - - -// The background texture loading thread. -static class LoaderThreadClass : public ThreadClass -{ -public: -#ifdef Exception_Handler - LoaderThreadClass(const char *thread_name = "Texture loader thread") : ThreadClass(thread_name, &Exception_Handler) {} -#else - LoaderThreadClass(const char *thread_name = "Texture loader thread") : ThreadClass(thread_name) {} -#endif - - void Thread_Function(); -} _TextureLoadThread; - - -// TODO: Legacy - remove this call! -IDirect3DTexture8* Load_Compressed_Texture( - const StringClass& filename, - unsigned reduction_factor, - MipCountType mip_level_count, - WW3DFormat dest_format) -{ - // If DDS file isn't available, use TGA file to convert to DDS. - - DDSFileClass dds_file(filename,reduction_factor); - if (!dds_file.Is_Available()) return NULL; - if (!dds_file.Load()) return NULL; - - unsigned width=dds_file.Get_Width(0); - unsigned height=dds_file.Get_Height(0); - unsigned mips=dds_file.Get_Mip_Level_Count(); - - // If format isn't defined get the nearest valid texture format to the compressed file format - // Note that the nearest valid format could be anything, even uncompressed. - if (dest_format==WW3D_FORMAT_UNKNOWN) dest_format=Get_Valid_Texture_Format(dds_file.Get_Format(),true); - - IDirect3DTexture8* d3d_texture = DX8Wrapper::_Create_DX8_Texture - ( - width, - height, - dest_format, - (MipCountType)mips - ); - - for (unsigned level=0;levelGetSurfaceLevel(level/*-reduction_factor*/,&d3d_surface)); - dds_file.Copy_Level_To_Surface(level,d3d_surface); - d3d_surface->Release(); - } - return d3d_texture; -} - -static bool Is_Format_Compressed(WW3DFormat texture_format,bool allow_compression) -{ - // Verify that the user isn't requesting compressed texture without hardware support - - bool compressed=false; - if (texture_format!=WW3D_FORMAT_UNKNOWN) { - if (!DX8Wrapper::Get_Current_Caps()->Support_DXTC() || !allow_compression) { - WWASSERT(texture_format!=WW3D_FORMAT_DXT1); - WWASSERT(texture_format!=WW3D_FORMAT_DXT2); - WWASSERT(texture_format!=WW3D_FORMAT_DXT3); - WWASSERT(texture_format!=WW3D_FORMAT_DXT4); - WWASSERT(texture_format!=WW3D_FORMAT_DXT5); - } - if (texture_format==WW3D_FORMAT_DXT1 || - texture_format==WW3D_FORMAT_DXT2 || - texture_format==WW3D_FORMAT_DXT3 || - texture_format==WW3D_FORMAT_DXT4 || - texture_format==WW3D_FORMAT_DXT5) { - compressed=true; - } - } - - // If hardware supports DXTC compression, load a compressed texture. Proceed only if the texture format hasn't been - // defined as non-compressed. - compressed|=( - texture_format==WW3D_FORMAT_UNKNOWN && - DX8Wrapper::Get_Current_Caps()->Support_DXTC() && - allow_compression); - - return compressed; -} - - -//////////////////////////////////////////////////////////////////////////////// -// -// TextureLoader implementation -// -//////////////////////////////////////////////////////////////////////////////// - -void TextureLoader::Init() -{ - WWASSERT(!_TextureLoadThread.Is_Running()); - - ThumbnailManagerClass::Init(); - - _TextureLoadThread.Execute(); - _TextureLoadThread.Set_Priority(-4); - TextureInactiveOverrideTime = 0; -} - - -void TextureLoader::Deinit() -{ - FastCriticalSectionClass::LockClass lock(_BackgroundCriticalSection); - _TextureLoadThread.Stop(); - - ThumbnailManagerClass::Deinit(); - TextureLoadTaskClass::Delete_Free_Pool(); -} - - -bool TextureLoader::Is_DX8_Thread(void) -{ - return (ThreadClass::_Get_Current_Thread_ID() == DX8Wrapper::_Get_Main_Thread_ID()); -} - - -// ---------------------------------------------------------------------------- -// -// Modify given texture size to nearest valid size on current hardware. -// -// ---------------------------------------------------------------------------- - -void TextureLoader::Validate_Texture_Size -( - unsigned& width, - unsigned& height, - unsigned& depth -) -{ - const D3DCAPS8& dx8caps=DX8Wrapper::Get_Current_Caps()->Get_DX8_Caps(); - - unsigned poweroftwowidth = 1; - while (poweroftwowidth < width) - { - poweroftwowidth <<= 1; - } - - unsigned poweroftwoheight = 1; - while (poweroftwoheight < height) - { - poweroftwoheight <<= 1; - } - - unsigned poweroftwodepth = 1; - while (poweroftwodepth< depth) - { - poweroftwodepth <<= 1; - } - - if (poweroftwowidth>dx8caps.MaxTextureWidth) - { - poweroftwowidth=dx8caps.MaxTextureWidth; - } - if (poweroftwoheight>dx8caps.MaxTextureHeight) - { - poweroftwoheight=dx8caps.MaxTextureHeight; - } - if (poweroftwodepth>dx8caps.MaxVolumeExtent) - { - poweroftwodepth=dx8caps.MaxVolumeExtent; - } - - if (poweroftwowidth>poweroftwoheight) - { - while (poweroftwowidth/poweroftwoheight>8) - { - poweroftwoheight*=2; - } - } - else - { - while (poweroftwoheight/poweroftwowidth>8) - { - poweroftwowidth*=2; - } - } - - width=poweroftwowidth; - height=poweroftwoheight; - depth=poweroftwodepth; -} - -IDirect3DTexture8* TextureLoader::Load_Thumbnail(const StringClass& filename, const Vector3& hsv_shift)//,WW3DFormat texture_format) -{ - WWASSERT(Is_DX8_Thread()); - - ThumbnailClass* thumb=NULL; - thumb=ThumbnailManagerClass::Peek_Thumbnail_Instance_From_Any_Manager(filename); - - // If no thumb is found return a missing texture - if (!thumb) { - return MissingTexture::_Get_Missing_Texture(); - } - - WWASSERT(thumb->Get_Format()==WW3D_FORMAT_A4R4G4B4); - unsigned src_pitch=thumb->Get_Width()*2; // Thumbs are always 16 bits - WW3DFormat dest_format; - WW3DFormat texture_format=WW3D_FORMAT_UNKNOWN; - if (texture_format==WW3D_FORMAT_UNKNOWN) { - dest_format=Get_Valid_Texture_Format(WW3D_FORMAT_A4R4G4B4,false); // no compressed formats please - } - else { - dest_format=Get_Valid_Texture_Format(texture_format,false); // no compressed formats please - WWASSERT(dest_format==texture_format); - } - - IDirect3DTexture8* sysmem_texture = DX8Wrapper::_Create_DX8_Texture( - thumb->Get_Width(), - thumb->Get_Height(), - dest_format, - MIP_LEVELS_ALL, -#ifdef USE_MANAGED_TEXTURES - D3DPOOL_MANAGED); -#else - D3DPOOL_SYSTEMMEM); -#endif - - unsigned level=0; - D3DLOCKED_RECT locked_rects[12]={0}; - WWASSERT(sysmem_texture->GetLevelCount()<=12); - - // Lock all surfaces - for (level=0;levelGetLevelCount();++level) { - DX8_ErrorCode( - sysmem_texture->LockRect( - level, - &locked_rects[level], - NULL, - 0)); - } - - unsigned char* src_surface=thumb->Peek_Bitmap(); - WW3DFormat src_format=thumb->Get_Format(); - unsigned width=thumb->Get_Width(); - unsigned height=thumb->Get_Height(); - - Vector3 hsv=hsv_shift; - for (level=0;levelGetLevelCount()-1;++level) { - BitmapHandlerClass::Copy_Image_Generate_Mipmap( - width, - height, - (unsigned char*)locked_rects[level].pBits, - locked_rects[level].Pitch, - dest_format, - src_surface, - src_pitch, - src_format, - (unsigned char*)locked_rects[level+1].pBits, // mipmap - locked_rects[level+1].Pitch, - hsv); - hsv=Vector3(0.0f,0.0f,0.0f); // Only do the shift for the first level, as the mipmaps are based on it. - - src_format=dest_format; - src_surface=(unsigned char*)locked_rects[level].pBits; - src_pitch=locked_rects[level].Pitch; - width>>=1; - height>>=1; - } - - // Unlock all surfaces - for (level=0;levelGetLevelCount();++level) { - DX8_ErrorCode(sysmem_texture->UnlockRect(level)); - } -#ifdef USE_MANAGED_TEXTURES - return sysmem_texture; -#else - IDirect3DTexture8* d3d_texture = DX8Wrapper::_Create_DX8_Texture( - thumb->Get_Width(), - thumb->Get_Height(), - dest_format, - TextureBaseClass::MIP_LEVELS_ALL, - D3DPOOL_DEFAULT); - DX8CALL(UpdateTexture(sysmem_texture,d3d_texture)); - sysmem_texture->Release(); - - WWDEBUG_SAY(("Created non-managed texture (%s)",filename)); - return d3d_texture; -#endif -} - - -// ---------------------------------------------------------------------------- -// -// Load image to a surface. The function tries to create texture that matches -// targa format. If suitable format is not available, it selects closest matching -// format and performs color space conversion. -// -// ---------------------------------------------------------------------------- -IDirect3DSurface8* TextureLoader::Load_Surface_Immediate( - const StringClass& filename, - WW3DFormat texture_format, - bool allow_compression) -{ - WWASSERT(Is_DX8_Thread()); - - bool compressed=Is_Format_Compressed(texture_format,allow_compression); - - if (compressed) { - IDirect3DTexture8* comp_tex=Load_Compressed_Texture(filename,0,MIP_LEVELS_1,WW3D_FORMAT_UNKNOWN); - if (comp_tex) { - IDirect3DSurface8* d3d_surface=NULL; - DX8_ErrorCode(comp_tex->GetSurfaceLevel(0,&d3d_surface)); - comp_tex->Release(); - return d3d_surface; - } - } - - // Make sure the file can be opened. If not, return missing texture. - Targa targa; - if (TARGA_ERROR_HANDLER(targa.Open(filename, TGA_READMODE),filename)) return MissingTexture::_Create_Missing_Surface(); - - // DX8 uses image upside down compared to TGA - targa.Header.ImageDescriptor ^= TGAIDF_YORIGIN; - - WW3DFormat src_format,dest_format; - unsigned src_bpp=0; - Get_WW3D_Format(dest_format,src_format,src_bpp,targa); - - if (texture_format!=WW3D_FORMAT_UNKNOWN) { - dest_format=texture_format; - } - - // Destination size will be the next power of two square from the larger width and height... - unsigned width, height; - width=targa.Header.Width; - height=targa.Header.Height; - unsigned src_width=targa.Header.Width; - unsigned src_height=targa.Header.Height; - - // NOTE: We load the palette but we do not yet support paletted textures! - char palette[256*4]; - targa.SetPalette(palette); - if (TARGA_ERROR_HANDLER(targa.Load(filename, TGAF_IMAGE, false),filename)) return MissingTexture::_Create_Missing_Surface(); - - unsigned char* src_surface=(unsigned char*)targa.GetImage(); - - // No paletted destination format allowed - unsigned char* converted_surface=NULL; - if (src_format==WW3D_FORMAT_A1R5G5B5 || src_format==WW3D_FORMAT_R5G6B5 || src_format==WW3D_FORMAT_A4R4G4B4 || - src_format==WW3D_FORMAT_P8 || src_format==WW3D_FORMAT_L8 || src_width!=width || src_height!=height) { - converted_surface=W3DNEWARRAY unsigned char[width*height*4]; - dest_format=Get_Valid_Texture_Format(WW3D_FORMAT_A8R8G8B8,false); - BitmapHandlerClass::Copy_Image( - converted_surface, - width, - height, - width*4, - WW3D_FORMAT_A8R8G8B8,//dest_format, - src_surface, - src_width, - src_height, - src_width*src_bpp, - src_format, - (unsigned char*)targa.GetPalette(), - targa.Header.CMapDepth>>3, - false); - src_surface=converted_surface; - src_format=WW3D_FORMAT_A8R8G8B8;//dest_format; - src_width=width; - src_height=height; - src_bpp=Get_Bytes_Per_Pixel(src_format); - } - - unsigned src_pitch=src_width*src_bpp; - - IDirect3DSurface8* d3d_surface = DX8Wrapper::_Create_DX8_Surface(width,height,dest_format); - WWASSERT(d3d_surface); - D3DLOCKED_RECT locked_rect; - DX8_ErrorCode( - d3d_surface->LockRect( - &locked_rect, - NULL, - 0)); - - BitmapHandlerClass::Copy_Image( - (unsigned char*)locked_rect.pBits, - width, - height, - locked_rect.Pitch, - dest_format, - src_surface, - src_width, - src_height, - src_pitch, - src_format, - (unsigned char*)targa.GetPalette(), - targa.Header.CMapDepth>>3, - false); // No mipmap - - DX8_ErrorCode(d3d_surface->UnlockRect()); - - delete[] converted_surface; - - return d3d_surface; -} - - -void TextureLoader::Request_Thumbnail(TextureBaseClass *tc) -{ - // Grab the foreground lock. This prevents the foreground thread - // from retiring any tasks related to this texture. It also - // serializes calls to Request_Thumbnail from multiple threads. - FastCriticalSectionClass::LockClass lock(_ForegroundCriticalSection); - - // Has a Direct3D texture already been loaded? - if (tc->Peek_D3D_Base_Texture()) { - return; - } - - TextureLoadTaskClass *task = tc->ThumbnailLoadTask; - - if (Is_DX8_Thread()) { - // load the thumbnail immediately - TextureLoader::Load_Thumbnail(tc); - - // clear any pending thumbnail load - if (task) { - _ForegroundQueue.Remove(task); - task->Destroy(); - } - - } else { - TextureLoadTaskClass *load_task = tc->TextureLoadTask; - - // if texture is not already loading a thumbnail and there is no - // background load near completion. (a background load waiting - // to be applied will be ready at the same time as a queued thumbnail. - // Why do the extra work?) - if (!task && (!load_task || load_task->Get_State() < TextureLoadTaskClass::STATE_LOAD_MIPMAP)) { - - // create a thumbnail load task and add to foreground queue. - task = TextureLoadTaskClass::Create(tc, TextureLoadTaskClass::TASK_THUMBNAIL, TextureLoadTaskClass::PRIORITY_LOW); - _ForegroundQueue.Push_Back(task); - } - } -} - - -void TextureLoader::Request_Background_Loading(TextureBaseClass *tc) -{ - WWPROFILE(("TextureLoader::Request_Background_Loading()")); - // Grab the foreground lock. This prevents the foreground thread - // from retiring any tasks related to this texture. It also - // serializes calls to Request_Background_Loading from other - // threads. - FastCriticalSectionClass::LockClass foreground_lock(_ForegroundCriticalSection); - - // Has the texture already been loaded? - if (tc->Is_Initialized()) { - return; - } - - TextureLoadTaskClass *task = tc->TextureLoadTask; - - // if texture already has a load task, we don't need to create another one. - if (task) { - return; - } - - task = TextureLoadTaskClass::Create(tc, TextureLoadTaskClass::TASK_LOAD, TextureLoadTaskClass::PRIORITY_LOW); - - if (Is_DX8_Thread()) { - Begin_Load_And_Queue(task); - } else { - _ForegroundQueue.Push_Back(task); - } -} - - -void TextureLoader::Request_Foreground_Loading(TextureBaseClass *tc) -{ - WWPROFILE(("TextureLoader::Request_Foreground_Loading()")); - // Grab the foreground lock. This prevents the foreground thread - // from retiring the load tasks for this texture. It also - // serializes calls to Request_Foreground_Loading from other - // threads. - FastCriticalSectionClass::LockClass foreground_lock(_ForegroundCriticalSection); - - // Has the texture already been loaded? - if (tc->Is_Initialized()) { - return; - } - - TextureLoadTaskClass *task = tc->TextureLoadTask; - TextureLoadTaskClass *task_thumb = tc->ThumbnailLoadTask; - - if (Is_DX8_Thread()) { - - // since we're in the DX8 thread, we can load the entire - // texture right now. - - // if we have a thumbnail task waiting, kill it. - if (task_thumb) { - _ForegroundQueue.Remove(task_thumb); - task_thumb->Destroy(); - } - - if (task) { - // we need to remove the task from any queue, since we're going - // to finish it up right now. - - // halt background thread. After we're holding this lock, - // we know the background thread cannot begin loading - // mipmap levels for this texture. - FastCriticalSectionClass::LockClass background_lock(_BackgroundCriticalSection); - _ForegroundQueue.Remove(task); - _BackgroundQueue.Remove(task); - } else { - // Since the task manages all the state associated with loading - // a texture, we temporarily create one. - task = TextureLoadTaskClass::Create(tc, TextureLoadTaskClass::TASK_LOAD, TextureLoadTaskClass::PRIORITY_HIGH); - } - - // finish loading the task and destroy it. - task->Finish_Load(); - task->Destroy(); - - } else { - // we are not in the DX8 thread. We need to add a high-priority loading - // task to the foreground queue. - - // Grab the background lock. After we're holding this lock, we - // know the background thread cannot begin loading mipmap levels - // for this texture. - FastCriticalSectionClass::LockClass background_lock(_BackgroundCriticalSection); - - // if we have a thumbnail task, we should cancel it. Since we are not - // the foreground thread, we are not allowed to call Destroy(). Instead, - // leave it queued in the completed state so it will be destroyed by Update(). - if (task_thumb) { - task_thumb->Set_State(TextureLoadTaskClass::STATE_COMPLETE); - } - - if (task) { - // if a load task is waiting on the background queue, we need to - // move it to the foreground queue. - if (task->Get_List() == &_BackgroundQueue) { - - // remove task from list - _BackgroundQueue.Remove(task); - - // add to foreground queue. - _ForegroundQueue.Push_Back(task); - } - - // upgrade the task priority - task->Set_Priority(TextureLoadTaskClass::PRIORITY_HIGH); - - } else { - // allocate high priority load task - task = TextureLoadTaskClass::Create(tc, TextureLoadTaskClass::TASK_LOAD, TextureLoadTaskClass::PRIORITY_HIGH); - - // add to back of foreground queue. - _ForegroundQueue.Push_Back(task); - } - } -} - - -void TextureLoader::Flush_Pending_Load_Tasks(void) -{ - // This function can only be called from the main thread. - // (Only the main thread can make the DX8 calls necessary - // to complete texture loading. If we wanted to flush - // the pending tasks from another thread, we'd probably - // want to set a bool that is checked by Update(). - WWASSERT(Is_DX8_Thread()); - - for (;;) { - bool done = false; - - { - // we have no pending load tasks when both queues are empty - // and the background thread is not processing a texture. - - // Grab the background lock. Once we're holding it, we - // know that the background thread is not processing any - // textures. - - // NOTE: It's important that we do only hold on to the background - // lock while we check for completion. Otherwise, we will either - // violate the lock order when we call Update() (which grabs - // the foreground lock) or never give the background thread - // a chance to empty its queue. - FastCriticalSectionClass::LockClass background_lock(_BackgroundCriticalSection); - done = _BackgroundQueue.Is_Empty() && _ForegroundQueue.Is_Empty(); - } - - // exit loop if no entries in list - if (done) { - break; - } - - Update(); - ThreadClass::Switch_Thread(); - } -} - - -// Nework update macro for texture loader. -#pragma warning(disable:4201) // warning C4201: nonstandard extension used : nameless struct/union -#include -#define UPDATE_NETWORK \ - if (network_callback) { \ - unsigned long time2 = timeGetTime(); \ - if (time2 - time > 20) { \ - network_callback(); \ - time = time2; \ - } \ - } \ - - -void TextureLoader::Update(void (*network_callback)(void)) -{ - WWASSERT_PRINT(Is_DX8_Thread(), "TextureLoader::Update must be called from the main thread!"); - - if (TextureLoadSuspended) { - return; - } - - // grab foreground lock to prevent any other thread from - // modifying texture tasks. - FastCriticalSectionClass::LockClass lock(_ForegroundCriticalSection); - - unsigned long time = timeGetTime(); - - // while we have tasks on the foreground queue - while (TextureLoadTaskClass *task = _ForegroundQueue.Pop_Front()) { - UPDATE_NETWORK; - // dispatch to proper task handler - switch (task->Get_Type()) { - case TextureLoadTaskClass::TASK_THUMBNAIL: - Process_Foreground_Thumbnail(task); - break; - - case TextureLoadTaskClass::TASK_LOAD: - Process_Foreground_Load(task); - break; - } - } - - TextureBaseClass::Invalidate_Old_Unused_Textures(TextureInactiveOverrideTime); -} - -void TextureLoader::Suspend_Texture_Load() -{ - WWASSERT_PRINT(Is_DX8_Thread(),"TextureLoader::Suspend_Texture_Load must be called from the main thread!"); - TextureLoadSuspended=true; -} - -void TextureLoader::Continue_Texture_Load() -{ - WWASSERT_PRINT(Is_DX8_Thread(),"TextureLoader::Continue_Texture_Load must be called from the main thread!"); - TextureLoadSuspended=false; -} - -void TextureLoader::Process_Foreground_Thumbnail(TextureLoadTaskClass *task) -{ - switch (task->Get_State()) { - case TextureLoadTaskClass::STATE_NONE: - Load_Thumbnail(task->Peek_Texture()); - FALLTHROUGH; // NOTE: fall-through is intentional - - case TextureLoadTaskClass::STATE_COMPLETE: - task->Destroy(); - break; - } -} - - -void TextureLoader::Process_Foreground_Load(TextureLoadTaskClass *task) -{ - // Is high-priority task? - if (task->Get_Priority() == TextureLoadTaskClass::PRIORITY_HIGH) { - task->Finish_Load(); - task->Destroy(); - return; - } - - // otherwise, must be a low-priority task. - - switch (task->Get_State()) { - case TextureLoadTaskClass::STATE_NONE: - Begin_Load_And_Queue(task); - break; - - case TextureLoadTaskClass::STATE_LOAD_MIPMAP: - task->End_Load(); - task->Destroy(); - break; - } -} - - -void TextureLoader::Begin_Load_And_Queue(TextureLoadTaskClass *task) -{ - // should only be called from the DX8 thread. - WWASSERT(Is_DX8_Thread()); - - if (task->Begin_Load()) { - // add to front of background queue. This means the - // background load thread will service tasks in LIFO - // (last in, first out) order. - - // NOTE: this was how the old code did it, with a - // comment that mentioned good reasons for doing so, - // without actually listing the reasons. I suspect - // it has something to do with visually important textures, - // like those in the foreground, starting their load last. - _BackgroundQueue.Push_Front(task); - } else { - // unable to load. - task->Apply_Missing_Texture(); - task->Destroy(); - } -} - - -void TextureLoader::Load_Thumbnail(TextureBaseClass *tc) -{ - // All D3D operations must run from main thread - WWASSERT(Is_DX8_Thread()); - - // load thumbnail texture - IDirect3DTexture8 *d3d_texture = Load_Thumbnail(tc->Get_Full_Path(),tc->Get_HSV_Shift()); - - // apply thumbnail to texture - if (tc->Get_Asset_Type()==TextureBaseClass::TEX_REGULAR) - { - tc->Apply_New_Surface(d3d_texture, false); - } - - // release our reference to thumbnail texture - d3d_texture->Release(); - d3d_texture = 0; -} - - -void LoaderThreadClass::Thread_Function(void) -{ - while (running) { - // if there are no tasks on the background queue, no need to grab background lock. - if (!_BackgroundQueue.Is_Empty()) { - // Grab background load so other threads know we could be - // loading a texture. - FastCriticalSectionClass::LockClass lock(_BackgroundCriticalSection); - - // try to remove a task from the background queue. This could fail - // if another thread modified the queue between our test above and - // grabbing the lock. - TextureLoadTaskClass* task = _BackgroundQueue.Pop_Front(); - if (task) { - // verify task is in proper state for background processing. - WWASSERT(task->Get_Type() == TextureLoadTaskClass::TASK_LOAD); - WWASSERT(task->Get_State() == TextureLoadTaskClass::STATE_LOAD_BEGUN); - - // load mip map levels and return to foreground queue for final step. - task->Load(); - _ForegroundQueue.Push_Back(task); - } - } - - Switch_Thread(); - } -} - - -//////////////////////////////////////////////////////////////////////////////// -// -// TextureLoaderTaskClass implementation -// -//////////////////////////////////////////////////////////////////////////////// - -TextureLoadTaskClass::TextureLoadTaskClass() -: Texture (0), - D3DTexture (0), - Format (WW3D_FORMAT_UNKNOWN), - Width (0), - Height (0), - MipLevelCount (0), - Reduction (0), - Type (TASK_NONE), - Priority (PRIORITY_LOW), - State (STATE_NONE), - HSVShift (0.0f,0.0f,0.0f) -{ - // because texture load tasks are pooled, the constructor and destructor - // don't need to do much. The work of attaching a task to a texture is - // is done by Init() and Deinit(). - - for (int i = 0; i < MIP_LEVELS_MAX; ++i) { - LockedSurfacePtr[i] = NULL; - LockedSurfacePitch[i] = 0; - } -} - - -TextureLoadTaskClass::~TextureLoadTaskClass(void) -{ - Deinit(); -} - - -TextureLoadTaskClass *TextureLoadTaskClass::Create(TextureBaseClass *tc, TaskType type, PriorityType priority) -{ - // recycle or create a new texture load task with the given type - // and priority, then associate the texture with the task. - - // pull a load task from front of free list - TextureLoadTaskClass *task = NULL; - switch (tc->Get_Asset_Type()) - { - case TextureBaseClass::TEX_REGULAR : task=_TexLoadFreeList.Pop_Front(); break; - case TextureBaseClass::TEX_CUBEMAP : task=_CubeTexLoadFreeList.Pop_Front(); break; - case TextureBaseClass::TEX_VOLUME : task=_VolTexLoadFreeList.Pop_Front(); break; - default : WWASSERT(0); - }; - - // if no tasks on free list, allocate a new task - if (!task) - { - switch (tc->Get_Asset_Type()) - { - case TextureBaseClass::TEX_REGULAR : task=new TextureLoadTaskClass; break; - case TextureBaseClass::TEX_CUBEMAP : task=new CubeTextureLoadTaskClass; break; - case TextureBaseClass::TEX_VOLUME : task=new VolumeTextureLoadTaskClass; break; - default : WWASSERT(0); - } - } - task->Init(tc, type, priority); - return task; -} - - -void TextureLoadTaskClass::Destroy(void) -{ - // detach the task from its texture, and return to free pool. - Deinit(); - _TexLoadFreeList.Push_Front(this); -} - - -void TextureLoadTaskClass::Delete_Free_Pool(void) -{ - // (gth) We should probably just MEMPool these task objects... - while (TextureLoadTaskClass *task = _TexLoadFreeList.Pop_Front()) { - delete task; - } - while (TextureLoadTaskClass *task = _CubeTexLoadFreeList.Pop_Front()) { - delete task; - } - while (TextureLoadTaskClass *task = _VolTexLoadFreeList.Pop_Front()) { - delete task; - } -} - - -void TextureLoadTaskClass::Init(TextureBaseClass* tc, TaskType type, PriorityType priority) -{ - WWASSERT(tc); - - // NOTE: we must be in the main thread to avoid corrupting the texture's refcount. - WWASSERT(TextureLoader::Is_DX8_Thread()); - REF_PTR_SET(Texture, tc); - - // Make sure texture has a filename. - WWASSERT(!Texture->Get_Full_Path().Is_Empty()); - - Type = type; - Priority = priority; - State = STATE_NONE; - - D3DTexture = 0; - - TextureClass* tex=Texture->As_TextureClass(); - - if (tex) - { - Format = tex->Get_Texture_Format(); // don't assume format yet KM - } - else - { - Format = WW3D_FORMAT_UNKNOWN; - } - - Width = 0; - Height = 0; - MipLevelCount = Texture->MipLevelCount; - Reduction = Texture->Get_Reduction(); - HSVShift = Texture->Get_HSV_Shift(); - - - for (int i = 0; i < MIP_LEVELS_MAX; ++i) - { - LockedSurfacePtr[i] = NULL; - LockedSurfacePitch[i] = 0; - } - - switch (Type) - { - case TASK_THUMBNAIL: - WWASSERT(Texture->ThumbnailLoadTask == NULL); - Texture->ThumbnailLoadTask = this; - break; - - case TASK_LOAD: - WWASSERT(Texture->TextureLoadTask == NULL); - Texture->TextureLoadTask = this; - break; - } -} - - -void TextureLoadTaskClass::Deinit() -{ - // task should not be on any list when it is being detached from texture. - WWASSERT(Next == NULL); - WWASSERT(Prev == NULL); - - WWASSERT(D3DTexture == NULL); - - for (int i = 0; i < MIP_LEVELS_MAX; ++i) { - WWASSERT(LockedSurfacePtr[i] == NULL); - } - - if (Texture) { - switch (Type) { - case TASK_THUMBNAIL: - WWASSERT(Texture->ThumbnailLoadTask == this); - Texture->ThumbnailLoadTask = NULL; - break; - - case TASK_LOAD: - WWASSERT(Texture->TextureLoadTask == this); - Texture->TextureLoadTask = NULL; - break; - } - - // NOTE: we must be in main thread to avoid corrupting Texture's refcount. - WWASSERT(TextureLoader::Is_DX8_Thread()); - REF_PTR_RELEASE(Texture); - } -} - - -bool TextureLoadTaskClass::Begin_Load(void) -{ - WWASSERT(TextureLoader::Is_DX8_Thread()); - - bool loaded = false; - - // if allowed, begin a compressed load - if (Texture->Is_Compression_Allowed()) { - loaded = Begin_Compressed_Load(); - } - - // otherwise, begin an uncompressed load - if (!loaded) { - loaded = Begin_Uncompressed_Load(); - } - - // if not loaded, abort. - if (!loaded) { - return false; - } - - // lock surfaces in preparation for copy - Lock_Surfaces(); - - State = STATE_LOAD_BEGUN; - - return true; -} - - -// ---------------------------------------------------------------------------- -// -// Load mipmap levels to a pre-generated and locked texture object based on -// information in load task object. Try loading from a DDS file first and if -// that fails try a TGA. -// -// ---------------------------------------------------------------------------- -bool TextureLoadTaskClass::Load(void) -{ - WWMEMLOG(MEM_TEXTURE); - WWASSERT(Peek_D3D_Texture()); - - bool loaded = false; - - // if allowed, try to load compressed mipmaps - if (Texture->Is_Compression_Allowed()) { - loaded = Load_Compressed_Mipmap(); - } - - // otherwise, load uncompressed mipmaps - if (!loaded) { - loaded = Load_Uncompressed_Mipmap(); - } - - State = STATE_LOAD_MIPMAP; - - return loaded; -} - - -void TextureLoadTaskClass::End_Load(void) -{ - WWASSERT(TextureLoader::Is_DX8_Thread()); - - Unlock_Surfaces(); - Apply(true); - - State = STATE_LOAD_COMPLETE; -} - - -void TextureLoadTaskClass::Finish_Load(void) -{ - switch (State) { - // NOTE: fall-through below is intentional. - - case STATE_NONE: - if (!Begin_Load()) { - Apply_Missing_Texture(); - break; - } - FALLTHROUGH; - - case STATE_LOAD_BEGUN: - Load(); - FALLTHROUGH; - - case STATE_LOAD_MIPMAP: - End_Load(); - FALLTHROUGH; - - default: - break; - } -} - - -void TextureLoadTaskClass::Apply_Missing_Texture(void) -{ - WWASSERT(TextureLoader::Is_DX8_Thread()); - WWASSERT(!D3DTexture); - - D3DTexture = MissingTexture::_Get_Missing_Texture(); - Apply(true); -} - - -void TextureLoadTaskClass::Apply(bool initialize) -{ - WWASSERT(D3DTexture); - - // Verify that none of the mip levels are locked - for (unsigned i=0;iApply_New_Surface(D3DTexture, initialize); - - D3DTexture->Release(); - D3DTexture = NULL; -} - -static bool Get_Texture_Information -( - const char* filename, - unsigned& reduction, - unsigned& w, - unsigned& h, - unsigned& d, - WW3DFormat& format, - unsigned& mip_count, - bool compressed -) -{ - ThumbnailClass* thumb=ThumbnailManagerClass::Peek_Thumbnail_Instance_From_Any_Manager(filename); - - if (!thumb) - { - if (compressed) - { - DDSFileClass dds_file(filename, 0); - if (!dds_file.Is_Available()) return false; - - // Destination size will be the next power of two square from the larger width and height... - w = dds_file.Get_Width(0); - h = dds_file.Get_Height(0); - d = dds_file.Get_Depth(0); - format = dds_file.Get_Format(); - mip_count = dds_file.Get_Mip_Level_Count(); - //Figure out correct reduction - int reqReduction=WW3D::Get_Texture_Reduction(); //requested reduction - - if (reqReduction >= mip_count) - reqReduction=mip_count-1; //leave only the lowest level - - //Clamp reduction - int curReduction=0; - int curWidth=w; - int curHeight=h; - int minDim=WW3D::Get_Texture_Min_Dimension(); - - while (curReduction < reqReduction && curWidth > minDim && curHeight > minDim) - { curWidth >>=1; //keep dividing - curHeight >>=1; - curReduction++; - } - reduction=curReduction; - return true; - } - - Targa targa; - if (TARGA_ERROR_HANDLER(targa.Open(filename, TGA_READMODE), filename)) - { - return false; - } - - unsigned int bpp; - WW3DFormat dest_format; - Get_WW3D_Format(dest_format,format,bpp,targa); - - mip_count = 0; - - //Figure out how many mip levels this texture will occupy - for (int i=targa.Header.Width, j=targa.Header.Height; i > 0 && j > 0; i>>=1, j>>=1) - mip_count++; - - //Figure out correct reduction - int reqReduction=WW3D::Get_Texture_Reduction(); //requested reduction - - if (reqReduction >= mip_count) - reqReduction=mip_count-1; //leave only the lowest level - - //Clamp reduction - int curReduction=0; - int curWidth=targa.Header.Width; - int curHeight=targa.Header.Height; - int minDim=WW3D::Get_Texture_Min_Dimension(); - - while (curReduction < reqReduction && curWidth > minDim && curHeight > minDim) - { curWidth >>=1; //keep dividing - curHeight >>=1; - curReduction++; - } - reduction=curReduction; - - // Destination size will be the next power of two square from the larger width and height... - w = targa.Header.Width; - h = targa.Header.Height; - d = 1; - return true; - } - - if (compressed && - thumb->Get_Original_Texture_Format()!=WW3D_FORMAT_DXT1 && - thumb->Get_Original_Texture_Format()!=WW3D_FORMAT_DXT2 && - thumb->Get_Original_Texture_Format()!=WW3D_FORMAT_DXT3 && - thumb->Get_Original_Texture_Format()!=WW3D_FORMAT_DXT4 && - thumb->Get_Original_Texture_Format()!=WW3D_FORMAT_DXT5) { - return false; - } - - w=thumb->Get_Original_Texture_Width() >> reduction; - h=thumb->Get_Original_Texture_Height() >> reduction; - //d=thumb->Get_Original_Texture_Depth() >> reduction; // need to a volume texture support to thumbnails...maybe - mip_count=thumb->Get_Original_Texture_Mip_Level_Count(); - format=thumb->Get_Original_Texture_Format(); - return true; -} - - -bool TextureLoadTaskClass::Begin_Compressed_Load(void) -{ - unsigned orig_w,orig_h,orig_d,orig_mip_count,reduction; - WW3DFormat orig_format; - if (!Get_Texture_Information - ( - Texture->Get_Full_Path(), - reduction, - orig_w, - orig_h, - orig_d, - orig_format, - orig_mip_count, - true - ) - ) - { - return false; - } - - // Destination size will be the next power of two square from the larger width and height... - unsigned int width = orig_w; - unsigned int height = orig_h; - TextureLoader::Validate_Texture_Size(width, height,orig_d); - - // If the size doesn't match, try and see if texture reduction would help... (mainly for - // cases where loaded texture is larger than hardware limit) - if (width != orig_w || height != orig_h) - { - for (unsigned int i = 1; i < orig_mip_count; ++i) - { - unsigned w=orig_w>>i; - if (w<4) w=4; - unsigned h=orig_h>>i; - if (h<4) h=4; - unsigned tmp_w=w; - unsigned tmp_h=h; - - TextureLoader::Validate_Texture_Size(w,h,orig_d); - - if (w == tmp_w && h == tmp_h) - { - Reduction += i; - width = w; - height = h; - break; - } - } - } - - Width = width; - Height = height; - Format = Get_Valid_Texture_Format(orig_format, Texture->Is_Compression_Allowed()); - Reduction = reduction; - - - if (!Texture->Is_Reducible() || Texture->MipLevelCount == MIP_LEVELS_1) - Reduction = 0; //app doesn't want this texture to ever be reduced. - else - //Make sure we don't reduce below the level requested by the app - if (Texture->MipLevelCount != MIP_LEVELS_ALL && (Texture->MipLevelCount - Reduction) < 1) - Reduction = Texture->MipLevelCount - 1; - - //Another sanity check - if (Reduction >= orig_mip_count) - Reduction = 0; //should not be possible to get here, but check just in case. - - unsigned int mip_level_count = Get_Mip_Level_Count(); - int reducedWidth=Width; - int reducedHeight=Height; - - // If texture wants all mip levels, take as many as the file contains (not necessarily all) - // Otherwise take as many mip levels as the texture wants, not to exceed the count in file... - if (!mip_level_count) - { - reducedWidth >>= Reduction; - reducedHeight >>= Reduction; - mip_level_count = orig_mip_count-Reduction;//dds_file.Get_Mip_Level_Count(); - if (mip_level_count < 1) - mip_level_count = 1; //sanity check to make sure something gets loaded. - } - else - { - if (mip_level_count > orig_mip_count) - { //dds_file.Get_Mip_Level_Count()) { - mip_level_count = orig_mip_count;//dds_file.Get_Mip_Level_Count(); - } - - if (Reduction) - { reducedWidth >>= Reduction; - reducedHeight >>= Reduction; - mip_level_count -= Reduction; //reduced requested number by those removed. - } - } - - // Once more, verify that the mip level count is correct (in case it was changed here it might not - // match the size...well actually it doesn't have to match but it can't be bigger than the size) - unsigned int max_mip_level_count = 1; - unsigned int w = 4; - unsigned int h = 4; - - while (w < Width && h < Height) - { - w += w; - h += h; - max_mip_level_count++; - } - - if (mip_level_count > max_mip_level_count) - { - mip_level_count = max_mip_level_count; - } - - D3DTexture = DX8Wrapper::_Create_DX8_Texture - ( - reducedWidth, - reducedHeight, - Format, - (MipCountType)mip_level_count, -#ifdef USE_MANAGED_TEXTURES - D3DPOOL_MANAGED -#else - D3DPOOL_SYSTEMMEM -#endif - ); - - MipLevelCount = mip_level_count; - - return true; -} - -bool TextureLoadTaskClass::Begin_Uncompressed_Load(void) -{ - unsigned width,height,depth,orig_mip_count,reduction; - WW3DFormat orig_format; - if (!Get_Texture_Information - ( - Texture->Get_Full_Path(), - reduction, - width, - height, - depth, - orig_format, - orig_mip_count, - false - ) - ) - { - return false; - } - - WW3DFormat src_format=orig_format; - WW3DFormat dest_format=src_format; - dest_format=Get_Valid_Texture_Format(dest_format,false); // No compressed destination format if reading from targa... - - if ( src_format != WW3D_FORMAT_A8R8G8B8 - && src_format != WW3D_FORMAT_R8G8B8 - && src_format != WW3D_FORMAT_X8R8G8B8 ) - { - WWDEBUG_SAY(("Invalid TGA format used in %s - only 24 and 32 bit formats should be used!", Texture->Get_Full_Path().str())); - } - - // Destination size will be the next power of two square from the larger width and height... - unsigned ow = width; - unsigned oh = height; - TextureLoader::Validate_Texture_Size(width, height,depth); - if (width != ow || height != oh) - { - WWDEBUG_SAY(("Invalid texture size, scaling required. Texture: %s, size: %d x %d -> %d x %d", Texture->Get_Full_Path().str(), ow, oh, width, height)); - } - - Width = width; - Height = height; - Reduction = reduction; - - if (!Texture->Is_Reducible() || Texture->MipLevelCount == MIP_LEVELS_1) - Reduction = 0; //app doesn't want this texture to ever be reduced. - else - //Make sure we don't reduce below the level requested by the app - if (Texture->MipLevelCount != MIP_LEVELS_ALL && (Texture->MipLevelCount - Reduction) < 1) - Reduction = Texture->MipLevelCount - 1; - - //Another sanity check - if (Reduction >= orig_mip_count) - Reduction = 0; //should not be possible to get here, but check just in case. - - if (Format == WW3D_FORMAT_UNKNOWN) - { - Format=dest_format; - // Format = Get_Valid_Texture_Format(dest_format, false); validated above - } - else - { - Format = Get_Valid_Texture_Format(Format, false); - } - - int reducedWidth=Width; - int reducedHeight=Height; - int reducedMipCount=Texture->MipLevelCount; - - if (Reduction) - { //we don't care about specific levels so reduce them if needed. - reducedWidth >>= Reduction; - reducedHeight >>= Reduction; - if (reducedMipCount != MIP_LEVELS_ALL) - reducedMipCount -= Reduction; - } - - D3DTexture = DX8Wrapper::_Create_DX8_Texture - ( - reducedWidth, - reducedHeight, - Format, - (MipCountType)reducedMipCount, -#ifdef USE_MANAGED_TEXTURES - D3DPOOL_MANAGED -#else - D3DPOOL_SYSTEMMEM -#endif - ); - - return true; -} - -/* -bool TextureLoadTaskClass::Begin_Compressed_Load(void) -{ - DDSFileClass dds_file(Texture->Get_Full_Path(), Get_Reduction()); - if (!dds_file.Is_Available()) { - return false; - } - - // Destination size will be the next power of two square from the larger width and height... - unsigned int width = dds_file.Get_Width(0); - unsigned int height = dds_file.Get_Height(0); - TextureLoader::Validate_Texture_Size(width, height); - - // If the size doesn't match, try and see if texture reduction would help... (mainly for - // cases where loaded texture is larger than hardware limit) - if (width != dds_file.Get_Width(0) || height != dds_file.Get_Height(0)) { - for (unsigned int i = 1; i < dds_file.Get_Mip_Level_Count(); ++i) { - unsigned int w = dds_file.Get_Width(i); - unsigned int h = dds_file.Get_Height(i); - TextureLoader::Validate_Texture_Size(w,h); - - if (w == dds_file.Get_Width(i) && h == dds_file.Get_Height(i)) { - Reduction += i; - width = w; - height = h; - break; - } - } - } - - Width = width; - Height = height; - Format = Get_Valid_Texture_Format(dds_file.Get_Format(), Texture->Is_Compression_Allowed()); - - unsigned int mip_level_count = Get_Mip_Level_Count(); - - // If texture wants all mip levels, take as many as the file contains (not necessarily all) - // Otherwise take as many mip levels as the texture wants, not to exceed the count in file... - if (!mip_level_count) { - mip_level_count = dds_file.Get_Mip_Level_Count(); - } else if (mip_level_count > dds_file.Get_Mip_Level_Count()) { - mip_level_count = dds_file.Get_Mip_Level_Count(); - } - - // Once more, verify that the mip level count is correct (in case it was changed here it might not - // match the size...well actually it doesn't have to match but it can't be bigger than the size) - unsigned int max_mip_level_count = 1; - unsigned int w = 4; - unsigned int h = 4; - - while (w < Width && h < Height) { - w += w; - h += h; - max_mip_level_count++; - } - - if (mip_level_count > max_mip_level_count) { - mip_level_count = max_mip_level_count; - } - - D3DTexture = DX8Wrapper::_Create_DX8_Texture( - Width, - Height, - Format, - (TextureBaseClass::MipCountType)mip_level_count, -#ifdef USE_MANAGED_TEXTURES - D3DPOOL_MANAGED); -#else - D3DPOOL_SYSTEMMEM); -#endif - MipLevelCount = mip_level_count; - return true; -} - - -bool TextureLoadTaskClass::Begin_Uncompressed_Load(void) -{ - Targa targa; - if (TARGA_ERROR_HANDLER(targa.Open(Texture->Get_Full_Path(), TGA_READMODE), Texture->Get_Full_Path())) { - return false; - } - - unsigned int bpp; - WW3DFormat src_format, dest_format; - Get_WW3D_Format(dest_format,src_format,bpp,targa); - - if ( src_format != WW3D_FORMAT_A8R8G8B8 - && src_format != WW3D_FORMAT_R8G8B8 - && src_format != WW3D_FORMAT_X8R8G8B8) { - WWDEBUG_SAY(("Invalid TGA format used in %s - only 24 and 32 bit formats should be used!", Texture->Get_Full_Path())); - } - - // Destination size will be the next power of two square from the larger width and height... - unsigned width=targa.Header.Width, height=targa.Header.Height; - int ReductionFactor=Get_Reduction(); - int MipLevels=0; - - //Figure out how many mip levels this texture will occupy - for (int i=width, j=height; i > 0 && j > 0; i>>=1, j>>=1) - MipLevels++; - - //Adjust the reduction factor to keep textures above some minimum dimensions - if (MipLevels <= WW3D::Get_Texture_Min_Mip_Levels()) - ReductionFactor=0; - else - { int mipToDrop=MipLevels-WW3D::Get_Texture_Min_Mip_Levels(); - if (ReductionFactor >= mipToDrop) - ReductionFactor=mipToDrop; - } - - width=targa.Header.Width>>ReductionFactor; - height=targa.Header.Height>>ReductionFactor; - unsigned ow = width; - unsigned oh = height; - TextureLoader::Validate_Texture_Size(width, height); - if (width != ow || height != oh) { - WWDEBUG_SAY(("Invalid texture size, scaling required. Texture: %s, size: %d x %d -> %d x %d", Texture->Get_Full_Path(), ow, oh, width, height)); - } - - Width = width; - Height = height; - - // changed because format was being read from previous loading task?! KJM - Format=dest_format; - //if (Format == WW3D_FORMAT_UNKNOWN) { - // Format = Get_Valid_Texture_Format(dest_format, false); - //} else { - // Format = Get_Valid_Texture_Format(Format, false); - //} - - D3DTexture = DX8Wrapper::_Create_DX8_Texture - ( - Width, - Height, - Format, - Texture->MipLevelCount, -#ifdef USE_MANAGED_TEXTURES - D3DPOOL_MANAGED); -#else - D3DPOOL_SYSTEMMEM); -#endif - return true; -} -*/ - -void TextureLoadTaskClass::Lock_Surfaces(void) -{ - MipLevelCount = D3DTexture->GetLevelCount(); - - for (unsigned int i = 0; i < MipLevelCount; ++i) - { - D3DLOCKED_RECT locked_rect; - DX8_ErrorCode - ( - Peek_D3D_Texture()->LockRect - ( - i, - &locked_rect, - NULL, - 0 - ) - ); - LockedSurfacePtr[i] = (unsigned char *)locked_rect.pBits; - LockedSurfacePitch[i] = locked_rect.Pitch; - } -} - - -void TextureLoadTaskClass::Unlock_Surfaces(void) -{ - for (unsigned int i = 0; i < MipLevelCount; ++i) - { - if (LockedSurfacePtr[i]) - { - WWASSERT(ThreadClass::_Get_Current_Thread_ID() == DX8Wrapper::_Get_Main_Thread_ID()); - DX8_ErrorCode(Peek_D3D_Texture()->UnlockRect(i)); - } - LockedSurfacePtr[i] = NULL; - } - -#ifndef USE_MANAGED_TEXTURES - IDirect3DTexture8* tex = DX8Wrapper::_Create_DX8_Texture(Width, Height, Format, Texture->MipLevelCount,D3DPOOL_DEFAULT); - DX8CALL(UpdateTexture(Peek_D3D_Texture(),tex)); - Peek_D3D_Texture()->Release(); - D3DTexture=tex; - WWDEBUG_SAY(("Created non-managed texture (%s)",Texture->Get_Full_Path())); -#endif - -} - - -bool TextureLoadTaskClass::Load_Compressed_Mipmap(void) -{ - DDSFileClass dds_file(Texture->Get_Full_Path(), Get_Reduction()); - - // if we can't load from file, indicate rror. - if (!dds_file.Is_Available() || !dds_file.Load()) - { - return false; - } - - // regular 2d texture - unsigned int width = Get_Width(); - unsigned int height = Get_Height(); - - if (Reduction) - { for (unsigned int level = 0; level < Reduction; ++level) { - width >>= 1; - height >>= 1; - } - } - - for (unsigned int level = 0; level < Get_Mip_Level_Count(); ++level) - { - WWASSERT(width && height); - dds_file.Copy_Level_To_Surface - ( - level, - Get_Format(), - width, - height, - Get_Locked_Surface_Ptr(level), - Get_Locked_Surface_Pitch(level), - HSVShift - ); - - width >>= 1; - height >>= 1; - } - - return true; -} - - -bool TextureLoadTaskClass::Load_Uncompressed_Mipmap(void) -{ - if (!Get_Mip_Level_Count()) - { - return false; - } - - Targa targa; - if (TARGA_ERROR_HANDLER(targa.Open(Texture->Get_Full_Path(), TGA_READMODE), Texture->Get_Full_Path())) { - return false; - } - - // DX8 uses image upside down compared to TGA - targa.Header.ImageDescriptor ^= TGAIDF_YORIGIN; - - WW3DFormat src_format; - WW3DFormat dest_format; - unsigned int src_bpp = 0; - Get_WW3D_Format(dest_format,src_format,src_bpp,targa); - if (src_format==WW3D_FORMAT_UNKNOWN) return false; - - dest_format = Get_Format(); // Texture can be requested in different format than the most obvious from the TGA - - char palette[256*4]; - targa.SetPalette(palette); - - unsigned int src_width = targa.Header.Width; - unsigned int src_height = targa.Header.Height; - unsigned int width = Get_Width(); - unsigned int height = Get_Height(); - - // NOTE: We load the palette but we do not yet support paletted textures! - if (TARGA_ERROR_HANDLER(targa.Load(Texture->Get_Full_Path(), TGAF_IMAGE, false), Texture->Get_Full_Path())) { - return false; - } - - unsigned char * src_surface = (unsigned char*)targa.GetImage(); - unsigned char * converted_surface = NULL; - - // No paletted format allowed when generating mipmaps - Vector3 hsv_shift=HSVShift; - if ( src_format == WW3D_FORMAT_A1R5G5B5 - || src_format == WW3D_FORMAT_R5G6B5 - || src_format == WW3D_FORMAT_A4R4G4B4 - || src_format == WW3D_FORMAT_P8 - || src_format == WW3D_FORMAT_L8 - || src_width != width - || src_height != height) { - - converted_surface = new unsigned char[width*height*4]; - dest_format = Get_Valid_Texture_Format(WW3D_FORMAT_A8R8G8B8, false); - - BitmapHandlerClass::Copy_Image( - converted_surface, - width, - height, - width*4, - WW3D_FORMAT_A8R8G8B8, //dest_format, - src_surface, - src_width, - src_height, - src_width*src_bpp, - src_format, - (unsigned char*)targa.GetPalette(), - targa.Header.CMapDepth>>3, - false, - hsv_shift); - hsv_shift=Vector3(0.0f,0.0f,0.0f); - - src_surface = converted_surface; - src_format = WW3D_FORMAT_A8R8G8B8; //dest_format; - src_width = width; - src_height = height; - src_bpp = Get_Bytes_Per_Pixel(src_format); - } - - unsigned src_pitch = src_width * src_bpp; - - if (Reduction) - { //texture needs to be reduced so allocate storage for full-sized version. - unsigned char * destination_surface = new unsigned char[width*height*4]; - //generate upper mip-levels that will be dropped in final texture - for (unsigned int level = 0; level < Reduction; ++level) { - BitmapHandlerClass::Copy_Image( - (unsigned char *)destination_surface, - width, - height, - src_pitch, - Get_Format(), - src_surface, - src_width, - src_height, - src_pitch, - src_format, - NULL, - 0, - true, - hsv_shift); - - width >>= 1; - height >>= 1; - src_width >>= 1; - src_height >>= 1; - } - delete [] destination_surface; - } - - for (unsigned int level = 0; level < Get_Mip_Level_Count(); ++level) { - WWASSERT(Get_Locked_Surface_Ptr(level)); - BitmapHandlerClass::Copy_Image( - Get_Locked_Surface_Ptr(level), - width, - height, - Get_Locked_Surface_Pitch(level), - Get_Format(), - src_surface, - src_width, - src_height, - src_pitch, - src_format, - NULL, - 0, - true, - hsv_shift); - hsv_shift=Vector3(0.0f,0.0f,0.0f); - - width >>= 1; - height >>= 1; - src_width >>= 1; - src_height >>= 1; - - if (!width || !height || !src_width || !src_height) { - break; - } - } - - delete[] converted_surface; - - return true; -} - - -unsigned char * TextureLoadTaskClass::Get_Locked_Surface_Ptr(unsigned int level) -{ - WWASSERT(levelGet_Full_Path().Is_Empty()); - - Type = type; - Priority = priority; - State = STATE_NONE; - - D3DTexture = 0; - - CubeTextureClass* tex=Texture->As_CubeTextureClass(); - - if (tex) - { - Format = tex->Get_Texture_Format(); // don't assume format yet KM - } - else - { - Format = WW3D_FORMAT_UNKNOWN; - } - - Width = 0; - Height = 0; - MipLevelCount = Texture->MipLevelCount; - Reduction = Texture->Get_Reduction(); - HSVShift = Texture->Get_HSV_Shift(); - - - for (int f=0; f<6; f++) - { - for (int i = 0; i < MIP_LEVELS_MAX; ++i) - { - LockedCubeSurfacePtr[f][i] = NULL; - LockedCubeSurfacePitch[f][i] = 0; - } - } - - switch (Type) - { - case TASK_THUMBNAIL: - WWASSERT(Texture->ThumbnailLoadTask == NULL); - Texture->ThumbnailLoadTask = this; - break; - - case TASK_LOAD: - WWASSERT(Texture->TextureLoadTask == NULL); - Texture->TextureLoadTask = this; - break; - } -} - - -void CubeTextureLoadTaskClass::Deinit() -{ - // task should not be on any list when it is being detached from texture. - WWASSERT(Next == NULL); - WWASSERT(Prev == NULL); - - WWASSERT(D3DTexture == NULL); - - for (int f=0; f<6; f++) - { - for (int i = 0; i < MIP_LEVELS_MAX; ++i) - { - WWASSERT(LockedCubeSurfacePtr[f][i] == NULL); - } - } - - if (Texture) - { - switch (Type) - { - case TASK_THUMBNAIL: - WWASSERT(Texture->ThumbnailLoadTask == this); - Texture->ThumbnailLoadTask = NULL; - break; - - case TASK_LOAD: - WWASSERT(Texture->TextureLoadTask == this); - Texture->TextureLoadTask = NULL; - break; - } - - // NOTE: we must be in main thread to avoid corrupting Texture's refcount. - WWASSERT(TextureLoader::Is_DX8_Thread()); - REF_PTR_RELEASE(Texture); - } -} - -void CubeTextureLoadTaskClass::Lock_Surfaces(void) -{ - for (unsigned int f=0; f<6; f++) - { - for (unsigned int i=0; iLockRect - ( - (D3DCUBEMAP_FACES)f, - i, - &locked_rect, - NULL, - 0 - ) - ); - LockedCubeSurfacePtr[f][i] = (unsigned char *)locked_rect.pBits; - LockedCubeSurfacePitch[f][i]= locked_rect.Pitch; - } - } -} - -void CubeTextureLoadTaskClass::Unlock_Surfaces(void) -{ - for (unsigned int f=0; f<6; f++) - { - for (unsigned int i = 0; i < MipLevelCount; ++i) - { - if (LockedCubeSurfacePtr[f][i]) - { - WWASSERT(ThreadClass::_Get_Current_Thread_ID() == DX8Wrapper::_Get_Main_Thread_ID()); - DX8_ErrorCode - ( - Peek_D3D_Cube_Texture()->UnlockRect((D3DCUBEMAP_FACES)f,i) - ); - } - LockedCubeSurfacePtr[f][i] = NULL; - } - } - -#ifndef USE_MANAGED_TEXTURES - IDirect3DCubeTexture8* tex = DX8Wrapper::_Create_DX8_Cube_Texture - ( - Width, - Height, - Format, - Texture->MipLevelCount, - D3DPOOL_DEFAULT - ); - DX8CALL(UpdateTexture(Peek_D3D_Volume_Texture(),tex)); - Peek_D3D_Volume_Texture()->Release(); - D3DTexture=tex; - WWDEBUG_SAY(("Created non-managed texture (%s)",Texture->Get_Full_Path())); -#endif - -} - - - -bool CubeTextureLoadTaskClass::Begin_Compressed_Load() -{ - unsigned orig_w,orig_h,orig_d,orig_mip_count,reduction; - WW3DFormat orig_format; - if (!Get_Texture_Information - ( - Texture->Get_Full_Path(), - reduction, - orig_w, - orig_h, - orig_d, - orig_format, - orig_mip_count, - true - ) - ) - { - return false; - } - - // Destination size will be the next power of two square from the larger width and height... - unsigned int width = orig_w; - unsigned int height = orig_h; - TextureLoader::Validate_Texture_Size(width, height,orig_d); - - // If the size doesn't match, try and see if texture reduction would help... (mainly for - // cases where loaded texture is larger than hardware limit) - if (width != orig_w || height != orig_h) - { - for (unsigned int i = 1; i < orig_mip_count; ++i) - { - unsigned w=orig_w>>i; - if (w<4) w=4; - unsigned h=orig_h>>i; - if (h<4) h=4; - unsigned tmp_w=w; - unsigned tmp_h=h; - - TextureLoader::Validate_Texture_Size(w,h,orig_d); - - if (w == tmp_w && h == tmp_h) - { - Reduction += i; - width = w; - height = h; - break; - } - } - } - - Width = width; - Height = height; - Format = Get_Valid_Texture_Format(orig_format, Texture->Is_Compression_Allowed()); - - unsigned int mip_level_count = Get_Mip_Level_Count(); - - // If texture wants all mip levels, take as many as the file contains (not necessarily all) - // Otherwise take as many mip levels as the texture wants, not to exceed the count in file... - if (!mip_level_count) - { - mip_level_count = orig_mip_count;//dds_file.Get_Mip_Level_Count(); - } - else if (mip_level_count > orig_mip_count) - {//dds_file.Get_Mip_Level_Count()) { - mip_level_count = orig_mip_count;//dds_file.Get_Mip_Level_Count(); - } - - // Once more, verify that the mip level count is correct (in case it was changed here it might not - // match the size...well actually it doesn't have to match but it can't be bigger than the size) - unsigned int max_mip_level_count = 1; - unsigned int w = 4; - unsigned int h = 4; - - while (w < Width && h < Height) - { - w += w; - h += h; - max_mip_level_count++; - } - - if (mip_level_count > max_mip_level_count) - { - mip_level_count = max_mip_level_count; - } - - D3DTexture = DX8Wrapper::_Create_DX8_Cube_Texture - ( - Width, - Height, - Format, - (MipCountType)mip_level_count, -#ifdef USE_MANAGED_TEXTURES - D3DPOOL_MANAGED -#else - D3DPOOL_SYSTEMMEM -#endif - ); - - MipLevelCount = mip_level_count; - return true; -} - -bool CubeTextureLoadTaskClass::Begin_Uncompressed_Load(void) -{ - unsigned width,height,depth,orig_mip_count,reduction; - WW3DFormat orig_format; - if (!Get_Texture_Information - ( - Texture->Get_Full_Path(), - reduction, - width, - height, - depth, - orig_format, - orig_mip_count, - false - ) - ) - { - return false; - } - - WW3DFormat src_format=orig_format; - WW3DFormat dest_format=src_format; - dest_format=Get_Valid_Texture_Format(dest_format,false); // No compressed destination format if reading from targa... - - if ( src_format != WW3D_FORMAT_A8R8G8B8 - && src_format != WW3D_FORMAT_R8G8B8 - && src_format != WW3D_FORMAT_X8R8G8B8 ) - { - WWDEBUG_SAY(("Invalid TGA format used in %s - only 24 and 32 bit formats should be used!", Texture->Get_Full_Path().str())); - } - - // Destination size will be the next power of two square from the larger width and height... - unsigned ow = width; - unsigned oh = height; - TextureLoader::Validate_Texture_Size(width, height,depth); - if (width != ow || height != oh) - { - WWDEBUG_SAY(("Invalid texture size, scaling required. Texture: %s, size: %d x %d -> %d x %d", Texture->Get_Full_Path().str(), ow, oh, width, height)); - } - - Width = width; - Height = height; - - if (Format == WW3D_FORMAT_UNKNOWN) - { - Format=dest_format; - } - else - { - Format = Get_Valid_Texture_Format(Format, false); - } - - D3DTexture = DX8Wrapper::_Create_DX8_Cube_Texture - ( - Width, - Height, - Format, - Texture->MipLevelCount, -#ifdef USE_MANAGED_TEXTURES - D3DPOOL_MANAGED -#else - D3DPOOL_SYSTEMMEM -#endif - ); - - return true; -} - -bool CubeTextureLoadTaskClass::Load_Compressed_Mipmap(void) -{ - DDSFileClass dds_file(Texture->Get_Full_Path(), Get_Reduction()); - - // if we can't load from file, indicate rror. - if (!dds_file.Is_Available() || !dds_file.Load()) - { - return false; - } - - // load cube map faces - for (unsigned int face=0; face<6; face++) - { - unsigned int width = Get_Width(); - unsigned int height = Get_Height(); - - for (unsigned int level=0; level>=1; - height>>=1; - } - } - - return true; -} - -unsigned char* CubeTextureLoadTaskClass::Get_Locked_CubeMap_Surface_Pointer(unsigned int face, unsigned int level) -{ - WWASSERT(face<6 && levelGet_Full_Path().Is_Empty()); - - Type = type; - Priority = priority; - State = STATE_NONE; - - D3DTexture = 0; - - VolumeTextureClass* tex=Texture->As_VolumeTextureClass(); - - if (tex) - { - Format = tex->Get_Texture_Format(); // don't assume format yet KM - } - else - { - Format = WW3D_FORMAT_UNKNOWN; - } - - Width = 0; - Height = 0; - Depth = 0; - MipLevelCount = Texture->MipLevelCount; - Reduction = Texture->Get_Reduction(); - HSVShift = Texture->Get_HSV_Shift(); - - - for (int i = 0; i < MIP_LEVELS_MAX; ++i) - { - LockedSurfacePtr[i] = NULL; - LockedSurfacePitch[i] = 0; - LockedSurfaceSlicePitch[i] = 0; - } - - switch (Type) - { - case TASK_THUMBNAIL: - WWASSERT(Texture->ThumbnailLoadTask == NULL); - Texture->ThumbnailLoadTask = this; - break; - - case TASK_LOAD: - WWASSERT(Texture->TextureLoadTask == NULL); - Texture->TextureLoadTask = this; - break; - } -} - -void VolumeTextureLoadTaskClass::Lock_Surfaces() -{ - for (unsigned int i=0; iLockBox - ( - i, - &locked_box, - NULL, - 0 - ) - ); - LockedSurfacePtr[i] = (unsigned char *)locked_box.pBits; - LockedSurfacePitch[i] = locked_box.RowPitch; - LockedSurfaceSlicePitch[i] = locked_box.SlicePitch; - } -} - - -void VolumeTextureLoadTaskClass::Unlock_Surfaces() -{ - for (unsigned int i = 0; i < MipLevelCount; ++i) - { - if (LockedSurfacePtr[i]) - { - WWASSERT(ThreadClass::_Get_Current_Thread_ID() == DX8Wrapper::_Get_Main_Thread_ID()); - DX8_ErrorCode - ( - Peek_D3D_Volume_Texture()->UnlockBox(i) - ); - } - LockedSurfacePtr[i] = NULL; - } - -#ifndef USE_MANAGED_TEXTURES - IDirect3DTexture8* tex = DX8Wrapper::_Create_DX8_Volume_Texture(Width, Height, Depth, Format, Texture->MipLevelCount,D3DPOOL_DEFAULT); - DX8CALL(UpdateTexture(Peek_D3D_Volume_Texture(),tex)); - Peek_D3D_Volume_Texture()->Release(); - D3DTexture=tex; - WWDEBUG_SAY(("Created non-managed texture (%s)",Texture->Get_Full_Path())); -#endif - -} - - - -bool VolumeTextureLoadTaskClass::Begin_Compressed_Load() -{ - unsigned orig_w,orig_h,orig_d,orig_mip_count,reduction; - WW3DFormat orig_format; - if (!Get_Texture_Information - ( - Texture->Get_Full_Path(), - reduction, - orig_w, - orig_h, - orig_d, - orig_format, - orig_mip_count, - true - ) - ) - { - return false; - } - - // Destination size will be the next power of two square from the larger width and height... - unsigned int width = orig_w; - unsigned int height = orig_h; - unsigned int depth = orig_d; - TextureLoader::Validate_Texture_Size(width, height, depth); - - // If the size doesn't match, try and see if texture reduction would help... (mainly for - // cases where loaded texture is larger than hardware limit) - if (width != orig_w || height != orig_h || depth != orig_d) - { - for (unsigned int i = 1; i < orig_mip_count; ++i) - { - unsigned w=orig_w>>i; - if (w<4) w=4; - unsigned h=orig_h>>i; - if (h<4) h=4; - unsigned d=orig_d>>i; - if (d<1) d=1; - unsigned tmp_w=w; - unsigned tmp_h=h; - unsigned tmp_d=d; - - TextureLoader::Validate_Texture_Size(w,h,d); - - if (w == tmp_w && h == tmp_h && d== tmp_d) - { - Reduction += i; - width = w; - height = h; - depth = d; - break; - } - } - } - - Width = width; - Height = height; - Depth = depth; - Format = Get_Valid_Texture_Format(orig_format, Texture->Is_Compression_Allowed()); - - unsigned int mip_level_count = Get_Mip_Level_Count(); - - // If texture wants all mip levels, take as many as the file contains (not necessarily all) - // Otherwise take as many mip levels as the texture wants, not to exceed the count in file... - if (!mip_level_count) - { - mip_level_count = orig_mip_count;//dds_file.Get_Mip_Level_Count(); - } - else if (mip_level_count > orig_mip_count) - {//dds_file.Get_Mip_Level_Count()) { - mip_level_count = orig_mip_count;//dds_file.Get_Mip_Level_Count(); - } - - // Once more, verify that the mip level count is correct (in case it was changed here it might not - // match the size...well actually it doesn't have to match but it can't be bigger than the size) - unsigned int max_mip_level_count = 1; - unsigned int w = 4; - unsigned int h = 4; - - while (w < Width && h < Height) - { - w += w; - h += h; - max_mip_level_count++; - } - if (mip_level_count > max_mip_level_count) - { - mip_level_count = max_mip_level_count; - } - - D3DTexture = DX8Wrapper::_Create_DX8_Volume_Texture - ( - Width, - Height, - Depth, - Format, - (MipCountType)mip_level_count, -#ifdef USE_MANAGED_TEXTURES - D3DPOOL_MANAGED -#else - D3DPOOL_SYSTEMMEM -#endif - ); - - MipLevelCount = mip_level_count; - return true; -} - -bool VolumeTextureLoadTaskClass::Begin_Uncompressed_Load(void) -{ - unsigned width,height,depth,orig_mip_count,reduction; - WW3DFormat orig_format; - if (!Get_Texture_Information - ( - Texture->Get_Full_Path(), - reduction, - width, - height, - depth, - orig_format, - orig_mip_count, - false - ) - ) - { - return false; - } - - WW3DFormat src_format=orig_format; - WW3DFormat dest_format=src_format; - dest_format=Get_Valid_Texture_Format(dest_format,false); // No compressed destination format if reading from targa... - - if ( src_format != WW3D_FORMAT_A8R8G8B8 - && src_format != WW3D_FORMAT_R8G8B8 - && src_format != WW3D_FORMAT_X8R8G8B8 ) - { - WWDEBUG_SAY(("Invalid TGA format used in %s - only 24 and 32 bit formats should be used!", Texture->Get_Full_Path().str())); - } - - // Destination size will be the next power of two square from the larger width and height... - unsigned ow = width; - unsigned oh = height; - unsigned od = depth; - TextureLoader::Validate_Texture_Size(width, height, depth); - if (width != ow || height != oh || depth != od) - { - WWDEBUG_SAY(("Invalid texture size, scaling required. Texture: %s, size: %d x %d -> %d x %d", Texture->Get_Full_Path().str(), ow, oh, width, height)); - } - - Width = width; - Height = height; - Depth = depth; - - if (Format == WW3D_FORMAT_UNKNOWN) - { - Format=dest_format; - } - else - { - Format = Get_Valid_Texture_Format(Format, false); - } - - D3DTexture = DX8Wrapper::_Create_DX8_Volume_Texture - ( - Width, - Height, - Depth, - Format, - Texture->MipLevelCount, -#ifdef USE_MANAGED_TEXTURES - D3DPOOL_MANAGED -#else - D3DPOOL_SYSTEMMEM -#endif - ); - - return true; -} - -bool VolumeTextureLoadTaskClass::Load_Compressed_Mipmap(void) -{ - DDSFileClass dds_file(Texture->Get_Full_Path(), Get_Reduction()); - - // if we can't load from file, indicate rror. - if (!dds_file.Is_Available() || !dds_file.Load()) - { - return false; - } - - // load volume - unsigned int depth=dds_file.Get_Depth(0); - unsigned int width=Get_Width(); - unsigned int height=Get_Height(); - - WWASSERT(width && height && depth); - - for (unsigned int level=0; level>=1; - height>>=1; - depth>>=1; - } - - return true; -} - -unsigned char* VolumeTextureLoadTaskClass::Get_Locked_Volume_Pointer(unsigned int level) -{ - WWASSERT(level. -*/ - -/*********************************************************************************************** - *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** - *********************************************************************************************** - * * - * Project Name : DX8 Texture Manager * - * * - * $Archive:: /Commando/Code/ww3d2/textureloader.h $* - * * - * Original Author:: vss_sync * - * * - * Author : Kenny Mitchell * - * * - * $Modtime:: 06/27/02 1:27p $* - * * - * $Revision:: 2 $* - * * - * 06/27/02 KM Texture class abstraction * - *---------------------------------------------------------------------------------------------* - * Functions: * - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - -#pragma once - -#include "always.h" -#include "texture.h" - -class StringClass; -struct IDirect3DTexture8; -class TextureLoadTaskClass; - -class TextureLoader -{ -public: - static void Init(void); - static void Deinit(void); - - // Modify given texture size to nearest valid size on current hardware. - static void Validate_Texture_Size(unsigned& width, unsigned& height, unsigned& depth); - - static IDirect3DTexture8 * Load_Thumbnail( - const StringClass& filename,const Vector3& hsv_shift); -// WW3DFormat texture_format); // Pass WW3D_FORMAT_UNKNOWN if you don't care - - static IDirect3DSurface8 * Load_Surface_Immediate( - const StringClass& filename, - WW3DFormat surface_format, // Pass WW3D_FORMAT_UNKNOWN if you don't care - bool allow_compression); - - static void Request_Thumbnail(TextureBaseClass* tc); - - // Adds a loading task to the system. The task if processed in a separate - // thread as soon as possible. The task will appear in finished tasks list - // when it's been completed. The texture will be refreshed on the next - // update call after appearing to the finished tasks list. - static void Request_Background_Loading(TextureBaseClass* tc); - - // Textures can only be created and locked by the main thread so this function sends a request to the texture - // handling system to load the texture immediatelly next time it enters the main thread. If this function - // is called from the main thread the texture is loaded immediatelly. - static void Request_Foreground_Loading(TextureBaseClass* tc); - - static void Flush_Pending_Load_Tasks(void); - static void Update(void(*network_callback)(void) = NULL); - - // returns true if current thread of execution is allowed to make DX8 calls. - static bool Is_DX8_Thread(void); - - static void Suspend_Texture_Load(); - static void Continue_Texture_Load(); - - static void Set_Texture_Inactive_Override_Time(int time_ms) {TextureInactiveOverrideTime = time_ms;} - -private: - static void Process_Foreground_Load (TextureLoadTaskClass *task); - static void Process_Foreground_Thumbnail (TextureLoadTaskClass *task); - - static void Begin_Load_And_Queue (TextureLoadTaskClass *task); - static void Load_Thumbnail (TextureBaseClass *tc); - - static bool TextureLoadSuspended; - - // The time in ms before a texture is thrown out. - // The default is zero. The scripted movies set this to reduce texture stalls in movies. - static int TextureInactiveOverrideTime; -}; - -class TextureLoadTaskListNodeClass -{ - friend class TextureLoadTaskListClass; - - public: - TextureLoadTaskListNodeClass(void) : Next(0), Prev(0) { } - - TextureLoadTaskListClass *Get_List(void) { return List; } - - TextureLoadTaskListNodeClass *Next; - TextureLoadTaskListNodeClass *Prev; - TextureLoadTaskListClass * List; -}; - - -class TextureLoadTaskListClass -{ - // This class implements an unsynchronized, double-linked list of TextureLoadTaskClass - // objects, using an embedded list node. - - public: - TextureLoadTaskListClass(void); - - // Returns true if list is empty, false otherwise. - bool Is_Empty (void) const { return (Root.Next == &Root); } - - // Add a task to beginning of list - void Push_Front (TextureLoadTaskClass *task); - - // Add a task to end of list - void Push_Back (TextureLoadTaskClass *task); - - // Remove and return a task from beginning of list, or NULL if list is empty. - TextureLoadTaskClass * Pop_Front (void); - - // Remove and return a task from end of list, or NULL if list is empty - TextureLoadTaskClass * Pop_Back (void); - - // Remove specified task from list, if present - void Remove (TextureLoadTaskClass *task); - - private: - // This list is implemented using a sentinel node. - TextureLoadTaskListNodeClass Root; -}; - - -class SynchronizedTextureLoadTaskListClass : public TextureLoadTaskListClass -{ - // This class added thread-safety to the basic TextureLoadTaskListClass. - - public: - SynchronizedTextureLoadTaskListClass(void); - - // See comments above for description of member functions. - void Push_Front (TextureLoadTaskClass *task); - void Push_Back (TextureLoadTaskClass *task); - TextureLoadTaskClass * Pop_Front (void); - TextureLoadTaskClass * Pop_Back (void); - void Remove (TextureLoadTaskClass *task); - - private: - FastCriticalSectionClass CriticalSection; -}; - -/* -** (gth) The allocation system we're using for TextureLoadTaskClass has gotten a little -** complicated since Kenny added the new task types for Cube and Volume textures. The -** ::Destroy member is used to return a task to the pool now and must be over-ridden in -** each derived class to put the task back into the correct free list. -*/ - - -class TextureLoadTaskClass : public TextureLoadTaskListNodeClass -{ - public: - enum TaskType { - TASK_NONE, - TASK_THUMBNAIL, - TASK_LOAD, - }; - - enum PriorityType { - PRIORITY_LOW, - PRIORITY_HIGH, - }; - - enum StateType { - STATE_NONE, - - STATE_LOAD_BEGUN, - STATE_LOAD_MIPMAP, - STATE_LOAD_COMPLETE, - - STATE_COMPLETE, - }; - - - TextureLoadTaskClass(void); - ~TextureLoadTaskClass(void); - - static TextureLoadTaskClass * Create (TextureBaseClass *tc, TaskType type, PriorityType priority); - static void Delete_Free_Pool (void); - - virtual void Destroy (void); - virtual void Init (TextureBaseClass *tc, TaskType type, PriorityType priority); - virtual void Deinit (void); - - TaskType Get_Type (void) const { return Type; } - PriorityType Get_Priority (void) const { return Priority; } - StateType Get_State (void) const { return State; } - - WW3DFormat Get_Format (void) const { return Format; } - unsigned int Get_Width (void) const { return Width; } - unsigned int Get_Height (void) const { return Height; } - unsigned int Get_Mip_Level_Count (void) const { return MipLevelCount; } - unsigned int Get_Reduction (void) const { return Reduction; } - - unsigned char * Get_Locked_Surface_Ptr (unsigned int level); - unsigned int Get_Locked_Surface_Pitch(unsigned int level) const; - - TextureBaseClass * Peek_Texture (void) { return Texture; } - IDirect3DTexture8 * Peek_D3D_Texture (void) { return (IDirect3DTexture8*)D3DTexture; } - - void Set_Type (TaskType t) { Type = t; } - void Set_Priority (PriorityType p) { Priority = p; } - void Set_State (StateType s) { State = s; } - - bool Begin_Load (void); - bool Load (void); - void End_Load (void); - void Finish_Load (void); - void Apply_Missing_Texture (void); - - protected: - virtual bool Begin_Compressed_Load (void); - virtual bool Begin_Uncompressed_Load (void); - - virtual bool Load_Compressed_Mipmap (void); - virtual bool Load_Uncompressed_Mipmap(void); - - virtual void Lock_Surfaces (void); - virtual void Unlock_Surfaces (void); - - void Apply (bool initialize); - - TextureBaseClass* Texture; - IDirect3DBaseTexture8* D3DTexture; - WW3DFormat Format; - - unsigned int Width; - unsigned int Height; - unsigned int MipLevelCount; - unsigned int Reduction; - Vector3 HSVShift; - - unsigned char * LockedSurfacePtr[MIP_LEVELS_MAX]; - unsigned int LockedSurfacePitch[MIP_LEVELS_MAX]; - - TaskType Type; - PriorityType Priority; - StateType State; -}; - -class CubeTextureLoadTaskClass : public TextureLoadTaskClass -{ -public: - CubeTextureLoadTaskClass(); - - virtual void Destroy (void); - virtual void Init (TextureBaseClass *tc, TaskType type, PriorityType priority); - virtual void Deinit (void); - -protected: - virtual bool Begin_Compressed_Load (void); - virtual bool Begin_Uncompressed_Load (void); - - virtual bool Load_Compressed_Mipmap (void); -// virtual bool Load_Uncompressed_Mipmap(void); - - virtual void Lock_Surfaces (void); - virtual void Unlock_Surfaces (void); - -private: - unsigned char* Get_Locked_CubeMap_Surface_Pointer(unsigned int face, unsigned int level); - unsigned int Get_Locked_CubeMap_Surface_Pitch(unsigned int face, unsigned int level) const; - - IDirect3DCubeTexture8* Peek_D3D_Cube_Texture(void) { return (IDirect3DCubeTexture8*)D3DTexture; } - - unsigned char* LockedCubeSurfacePtr[6][MIP_LEVELS_MAX]; - unsigned int LockedCubeSurfacePitch[6][MIP_LEVELS_MAX]; -}; - -class VolumeTextureLoadTaskClass : public TextureLoadTaskClass -{ -public: - VolumeTextureLoadTaskClass(); - - virtual void Destroy (void); - virtual void Init (TextureBaseClass *tc, TaskType type, PriorityType priority); - -protected: - virtual bool Begin_Compressed_Load (void); - virtual bool Begin_Uncompressed_Load (void); - - virtual bool Load_Compressed_Mipmap (void); -// virtual bool Load_Uncompressed_Mipmap(void); - - virtual void Lock_Surfaces (void); - virtual void Unlock_Surfaces (void); - -private: - unsigned char* Get_Locked_Volume_Pointer(unsigned int level); - unsigned int Get_Locked_Volume_Row_Pitch(unsigned int level); - unsigned int Get_Locked_Volume_Slice_Pitch(unsigned int level); - - IDirect3DVolumeTexture8* Peek_D3D_Volume_Texture(void) { return (IDirect3DVolumeTexture8*)D3DTexture; } - - unsigned int LockedSurfaceSlicePitch[MIP_LEVELS_MAX]; - - unsigned int Depth; -}; diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/texturethumbnail.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/texturethumbnail.cpp deleted file mode 100644 index 24d385fbf2f..00000000000 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/texturethumbnail.cpp +++ /dev/null @@ -1,410 +0,0 @@ -/* -** 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 . -*/ - -#include "texturethumbnail.h" -#include "hashtemplate.h" -#include "missingtexture.h" -#include "TARGA.h" -#include "ww3dformat.h" -#include "ddsfile.h" -#include "textureloader.h" -#include "bitmaphandler.h" -#include "ffactory.h" -#include "RAWFILE.h" -#include "wwprofile.h" -#include - -static DLListClass ThumbnailManagerList; -static ThumbnailManagerClass* GlobalThumbnailManager; -bool ThumbnailManagerClass::CreateThumbnailIfNotFound=false; - -static void Create_Hash_Name(StringClass& name, const StringClass& thumb_name) -{ - name=thumb_name; - int len=name.Get_Length(); - WWASSERT(!stricmp(&name[len-4],".tga") || !stricmp(&name[len-4],".dds")); - name[len-4]='\0'; - _strlwr(name.Peek_Buffer()); -} - - /* file_auto_ptr my_tga_file(_TheFileFactory,filename); - if (my_tga_file->Is_Available()) { - my_tga_file->Open(); - unsigned size=my_tga_file->Size(); - char* tga_memory=new char[size]; - my_tga_file->Read(tga_memory,size); - my_tga_file->Close(); - - StringClass pth("data\\"); - pth+=filename; - RawFileClass tmp_tga_file(pth); - tmp_tga_file.Create(); - tmp_tga_file.Write(tga_memory,size); - tmp_tga_file.Close(); - delete[] tga_memory; - - } -*/ - - -ThumbnailClass::ThumbnailClass( - ThumbnailManagerClass* manager, - const char* name, - unsigned char* bitmap, - unsigned w, - unsigned h, - unsigned original_w, - unsigned original_h, - unsigned original_mip_level_count, - WW3DFormat original_format, - bool allocated, - unsigned long date_time) - : - Manager(manager), - Name(name), - Bitmap(bitmap), - Allocated(allocated), - Width(w), - Height(h), - OriginalTextureWidth(original_w), - OriginalTextureHeight(original_h), - OriginalTextureMipLevelCount(original_mip_level_count), - OriginalTextureFormat(original_format), - DateTime(date_time) -{ - Manager->Insert_To_Hash(this); -} - -// ---------------------------------------------------------------------------- -// -// Load texture and generate mipmap levels if requested. The function tries -// to create texture that matches targa format. If suitable format is not -// available, it selects closest matching format and performs color space -// conversion. -// -// ---------------------------------------------------------------------------- - -ThumbnailClass::ThumbnailClass(ThumbnailManagerClass* manager, const StringClass& filename) - : - Manager(manager), - Bitmap(0), - Name(filename), - Allocated(false), - Width(0), - Height(0), - OriginalTextureWidth(0), - OriginalTextureHeight(0), - OriginalTextureMipLevelCount(0), - OriginalTextureFormat(WW3D_FORMAT_UNKNOWN), - DateTime(0) -{ - WWPROFILE(("ThumbnailClass::ThumbnailClass")); - unsigned reduction_factor=3; - - // First, try loading image from a DDS file - DDSFileClass dds_file(filename,reduction_factor); - if (dds_file.Is_Available() && dds_file.Load()) { - DateTime=dds_file.Get_Date_Time(); - - int len=Name.Get_Length(); - WWASSERT(len>4); - Name[len-3]='d'; - Name[len-2]='d'; - Name[len-1]='s'; - - unsigned level=0; - while (dds_file.Get_Width(level)>32 || dds_file.Get_Height(level)>32) { - if (level>=dds_file.Get_Mip_Level_Count()) break; - level++; - } - - OriginalTextureWidth=dds_file.Get_Full_Width(); - OriginalTextureHeight=dds_file.Get_Full_Height(); - OriginalTextureFormat=dds_file.Get_Format(); - OriginalTextureMipLevelCount=dds_file.Get_Mip_Level_Count(); - Width=dds_file.Get_Width(0); - Height=dds_file.Get_Height(0); - Bitmap=W3DNEWARRAY unsigned char[Width*Height*2]; - Allocated=true; - dds_file.Copy_Level_To_Surface( - 0, // Level - WW3D_FORMAT_A4R4G4B4, - Width, - Height, - Bitmap, - Width*2, - Vector3(0.0f,0.0f,0.0f));// We don't want to HSV-shift here - } - // If DDS file can't be used try loading from TGA - else { - // Make sure the file can be opened. If not, return missing texture. - Targa targa; - if (TARGA_ERROR_HANDLER(targa.Open(filename,TGA_READMODE),filename)) return; - - // DX8 uses image upside down compared to TGA - targa.Header.ImageDescriptor ^= TGAIDF_YORIGIN; - - WW3DFormat src_format,dest_format; - unsigned src_bpp=0; - Get_WW3D_Format(src_format,src_bpp,targa); - if (src_format==WW3D_FORMAT_UNKNOWN) { - WWDEBUG_SAY(("Unknown texture format for %s",filename.str())); - return; - } - - // Destination size will be the next power of two square from the larger width and height... - OriginalTextureWidth=targa.Header.Width; - OriginalTextureHeight=targa.Header.Height; - OriginalTextureFormat=src_format; - Width=targa.Header.Width>>reduction_factor; - Height=targa.Header.Height>>reduction_factor; - OriginalTextureMipLevelCount=1; - unsigned iw=1; - unsigned ih=1; - while (iw32 || Height>32) { - reduction_factor++; - Width>>=2; - Height>>=2; - } - - unsigned poweroftwowidth = 1; - while (poweroftwowidth < Width) { - poweroftwowidth <<= 1; - } - - unsigned poweroftwoheight = 1; - while (poweroftwoheight < Height) { - poweroftwoheight <<= 1; - } - - Width=poweroftwowidth; - Height=poweroftwoheight; - - unsigned src_width=targa.Header.Width; - unsigned src_height=targa.Header.Height; - - // NOTE: We load the palette but we do not yet support paletted textures! - char palette[256*4]; - targa.SetPalette(palette); - if (TARGA_ERROR_HANDLER(targa.Load(filename, TGAF_IMAGE, false),filename)) return; - - // Get time stamp from the tga file - { - file_auto_ptr my_tga_file(_TheFileFactory,filename); - WWASSERT(my_tga_file->Is_Available()); - my_tga_file->Open(); - DateTime=my_tga_file->Get_Date_Time(); - my_tga_file->Close(); - } - - unsigned char* src_surface=(unsigned char*)targa.GetImage(); - - int len=Name.Get_Length(); - WWASSERT(len>4); - Name[len-3]='t'; - Name[len-2]='g'; - Name[len-1]='a'; - - Bitmap=W3DNEWARRAY unsigned char[Width*Height*2]; - Allocated=true; - - dest_format=WW3D_FORMAT_A8R8G8B8; - BitmapHandlerClass::Copy_Image( - Bitmap, - Width, - Height, - Width*2, - WW3D_FORMAT_A4R4G4B4, - src_surface, - src_width, - src_height, - src_width*src_bpp, - src_format, - (unsigned char*)targa.GetPalette(), - targa.Header.CMapDepth>>3, - false); - } - - Manager->Insert_To_Hash(this); -} - -ThumbnailClass::~ThumbnailClass() -{ - if (Allocated) delete[] Bitmap; - Manager->Remove_From_Hash(this); -} - - -// ---------------------------------------------------------------------------- -ThumbnailManagerClass::ThumbnailManagerClass(const char* thumbnail_filename) - : - ThumbnailMemory(NULL), - ThumbnailFileName(thumbnail_filename), - PerTextureTimeStampUsed(false), - Changed(false), - DateTime(0) -{ -} - -// ---------------------------------------------------------------------------- -ThumbnailManagerClass::~ThumbnailManagerClass() -{ - HashTemplateIterator ite(ThumbnailHash); - ite.First(); - while (!ite.Is_Done()) { - ThumbnailClass* thumb=ite.Peek_Value(); - delete thumb; - ite.First(); - } - - delete[] ThumbnailMemory; - ThumbnailMemory=NULL; -} - -// ---------------------------------------------------------------------------- -ThumbnailManagerClass* ThumbnailManagerClass::Peek_Thumbnail_Manager(const char* thumbnail_filename) -{ - ThumbnailManagerClass* man=ThumbnailManagerList.Head(); - while (man) { - if (man->ThumbnailFileName==thumbnail_filename) return man; - man=man->Succ(); - } - if (GlobalThumbnailManager && - GlobalThumbnailManager->ThumbnailFileName==thumbnail_filename) return GlobalThumbnailManager; - return NULL; -} - -// ---------------------------------------------------------------------------- -void ThumbnailManagerClass::Add_Thumbnail_Manager(const char* thumbnail_filename) -{ - // First loop over all thumbnail managers to see if we already have this one created. This isn't - // supposed to be called often at all and there are usually just couple managers alive, - // so we'll do pure string compares here... - - // Must NOT add global manager with this function - WWASSERT(stricmp(thumbnail_filename,GLOBAL_THUMBNAIL_MANAGER_FILENAME)); - - ThumbnailManagerClass* man=Peek_Thumbnail_Manager(thumbnail_filename); - if (man) return; - - // Not found, create and add to the list. - man=new ThumbnailManagerClass(thumbnail_filename); - ThumbnailManagerList.Add_Tail(man); -} -// ---------------------------------------------------------------------------- -void ThumbnailManagerClass::Remove_Thumbnail_Manager(const char* thumbnail_filename) -{ - ThumbnailManagerClass* man=ThumbnailManagerList.Head(); - while (man) { - if (man->ThumbnailFileName==thumbnail_filename) { - delete man; - return; - } - man=man->Succ(); - } - if (GlobalThumbnailManager && - GlobalThumbnailManager->ThumbnailFileName==thumbnail_filename) { - delete GlobalThumbnailManager; - GlobalThumbnailManager=NULL; - } -} -// ---------------------------------------------------------------------------- -ThumbnailClass* ThumbnailManagerClass::Peek_Thumbnail_Instance(const StringClass& name) -{ - - return Get_From_Hash(name); -} - -ThumbnailClass* ThumbnailManagerClass::Peek_Thumbnail_Instance_From_Any_Manager(const StringClass& filename) -{ - WWPROFILE(("Peek_Thumbnail_Instance_From_Any_Manager")); - ThumbnailManagerClass* thumb_man=ThumbnailManagerList.Head(); - while (thumb_man) { - ThumbnailClass* thumb=thumb_man->Peek_Thumbnail_Instance(filename); - if (thumb) return thumb; - thumb_man=thumb_man->Succ(); - } - - if (GlobalThumbnailManager) { - ThumbnailClass* thumb=GlobalThumbnailManager->Peek_Thumbnail_Instance(filename); - if (thumb) return thumb; - } - -// If thumbnail is not found, see if we can find a texture. It is possible that the texture is outside of -// a mix file and didn't get included in any thumbnail database based on a mixfile. If so, we'll add it to -// our global thumbnail database. - if (Is_Thumbnail_Created_If_Not_Found()) { - if (GlobalThumbnailManager) { - ThumbnailClass* thumb=new ThumbnailClass(GlobalThumbnailManager,filename); - if (!thumb->Peek_Bitmap()) { - delete thumb; - thumb=NULL; - } - return thumb; - } - } - - return NULL; -} - - -void ThumbnailManagerClass::Insert_To_Hash(ThumbnailClass* thumb) -{ - Changed=true; - StringClass hash_name(0,true); - Create_Hash_Name(hash_name,thumb->Get_Name()); - ThumbnailHash.Insert(hash_name,thumb); -} - -ThumbnailClass* ThumbnailManagerClass::Get_From_Hash(const StringClass& name) -{ - StringClass hash_name(0,true); - Create_Hash_Name(hash_name,name); - return ThumbnailHash.Get(hash_name); -} - -void ThumbnailManagerClass::Remove_From_Hash(ThumbnailClass* thumb) -{ - Changed=true; - StringClass hash_name(0,true); - Create_Hash_Name(hash_name,thumb->Get_Name()); - ThumbnailHash.Remove(hash_name); -} - -void ThumbnailManagerClass::Init() -{ - WWASSERT(GlobalThumbnailManager == NULL); - GlobalThumbnailManager=new ThumbnailManagerClass(GLOBAL_THUMBNAIL_MANAGER_FILENAME); - GlobalThumbnailManager->Enable_Per_Texture_Time_Stamp(true); -} - -void ThumbnailManagerClass::Deinit() -{ - while (ThumbnailManagerClass* man=ThumbnailManagerList.Head()) { - delete man; - } - - delete GlobalThumbnailManager; - GlobalThumbnailManager=NULL; -} diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/texturethumbnail.h b/Generals/Code/Libraries/Source/WWVegas/WW3D2/texturethumbnail.h deleted file mode 100644 index 4d740af636e..00000000000 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/texturethumbnail.h +++ /dev/null @@ -1,124 +0,0 @@ -/* -** 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 . -*/ - -// 08/07/02 KM Texture class redesign (revisited) - -#pragma once - -#include "always.h" -#include "wwstring.h" -#include "hashtemplate.h" -#include "dllist.h" -#include "ww3dformat.h" - -#define GLOBAL_THUMBNAIL_MANAGER_FILENAME "global.th6" - -class ThumbnailManagerClass; - -// ---------------------------------------------------------------------------- - -class ThumbnailClass -{ - friend ThumbnailManagerClass; - - StringClass Name; - unsigned char* Bitmap; - unsigned Width; - unsigned Height; - unsigned OriginalTextureWidth; - unsigned OriginalTextureHeight; - unsigned OriginalTextureMipLevelCount; - WW3DFormat OriginalTextureFormat; - unsigned long DateTime; - bool Allocated; // if true, destructor will free the memory - ThumbnailManagerClass* Manager; - - ThumbnailClass( - ThumbnailManagerClass* manager, - const char* name, - unsigned char* bitmap, - unsigned w, - unsigned h, - unsigned original_w, - unsigned original_h, - unsigned original_mip_level_count, - WW3DFormat original_format, - bool allocated, - unsigned long date_time); - ThumbnailClass( - ThumbnailManagerClass* manager, - const StringClass& filename); - ~ThumbnailClass(); -public: - - unsigned char* Peek_Bitmap() { return Bitmap; } - WW3DFormat Get_Format() { return WW3D_FORMAT_A4R4G4B4; } - unsigned Get_Width() const { return Width; } - unsigned Get_Height() const { return Height; } - unsigned Get_Original_Texture_Width() const { return OriginalTextureWidth; } - unsigned Get_Original_Texture_Height() const { return OriginalTextureHeight; } - unsigned Get_Original_Texture_Mip_Level_Count() const { return OriginalTextureMipLevelCount; } - WW3DFormat Get_Original_Texture_Format() const { return OriginalTextureFormat; } - unsigned long Get_Date_Time() const { return DateTime; } - const StringClass& Get_Name() const { return Name; } - -}; - -// ---------------------------------------------------------------------------- - -class ThumbnailManagerClass : public DLNodeClass -{ - W3DMPO_GLUE(ThumbnailManagerClass); - - friend ThumbnailClass; - - static bool CreateThumbnailIfNotFound; - bool PerTextureTimeStampUsed; - StringClass ThumbnailFileName; - HashTemplateClass ThumbnailHash; - unsigned char* ThumbnailMemory; - bool Changed; - unsigned long DateTime; - - ThumbnailManagerClass(const char* thumbnail_filename); - ~ThumbnailManagerClass(); - - void Remove_From_Hash(ThumbnailClass* thumb); - void Insert_To_Hash(ThumbnailClass* thumb); - ThumbnailClass* Get_From_Hash(const StringClass& name); - -public: - ThumbnailClass* Peek_Thumbnail_Instance(const StringClass& name); - - static void Add_Thumbnail_Manager(const char* thumbnail_filename); - static void Remove_Thumbnail_Manager(const char* thumbnail_filename); - static ThumbnailManagerClass* Peek_Thumbnail_Manager(const char* thumbnail_filename); - - static ThumbnailClass* Peek_Thumbnail_Instance_From_Any_Manager(const StringClass& name); - - static bool Is_Thumbnail_Created_If_Not_Found() { return CreateThumbnailIfNotFound; } - static void Create_Thumbnail_If_Not_Found(bool create) { CreateThumbnailIfNotFound=create; } - - bool Is_Per_Texture_Time_Stamp_Used() const { return PerTextureTimeStampUsed; } - void Enable_Per_Texture_Time_Stamp(bool enable) { PerTextureTimeStampUsed=enable; } - - static void Init(); - static void Deinit(); -}; - -// ---------------------------------------------------------------------------- diff --git a/GeneralsMD/Code/GameEngine/CMakeLists.txt b/GeneralsMD/Code/GameEngine/CMakeLists.txt index b77b4292e52..065d37a8fb3 100644 --- a/GeneralsMD/Code/GameEngine/CMakeLists.txt +++ b/GeneralsMD/Code/GameEngine/CMakeLists.txt @@ -225,7 +225,7 @@ set(GAMEENGINE_SRC Include/GameClient/TerrainVisual.h # Include/GameClient/VideoPlayer.h # Include/GameClient/View.h - Include/GameClient/Water.h +# Include/GameClient/Water.h Include/GameClient/WindowLayout.h # Include/GameClient/WindowVideoManager.h Include/GameClient/WindowXlat.h @@ -825,7 +825,7 @@ set(GAMEENGINE_SRC # Source/GameClient/VideoPlayer.cpp # Source/GameClient/VideoStream.cpp # Source/GameClient/View.cpp - Source/GameClient/Water.cpp +# Source/GameClient/Water.cpp Source/GameLogic/AI/AI.cpp Source/GameLogic/AI/AIDock.cpp Source/GameLogic/AI/AIGroup.cpp diff --git a/GeneralsMD/Code/GameEngineDevice/CMakeLists.txt b/GeneralsMD/Code/GameEngineDevice/CMakeLists.txt index e1bb05cdb10..c96e1f0b278 100644 --- a/GeneralsMD/Code/GameEngineDevice/CMakeLists.txt +++ b/GeneralsMD/Code/GameEngineDevice/CMakeLists.txt @@ -13,7 +13,7 @@ set(GAMEENGINEDEVICE_SRC Include/W3DDevice/GameClient/Module/W3DDebrisDraw.h Include/W3DDevice/GameClient/Module/W3DDefaultDraw.h Include/W3DDevice/GameClient/Module/W3DDependencyModelDraw.h - Include/W3DDevice/GameClient/Module/W3DLaserDraw.h +# Include/W3DDevice/GameClient/Module/W3DLaserDraw.h Include/W3DDevice/GameClient/Module/W3DModelDraw.h Include/W3DDevice/GameClient/Module/W3DOverlordAircraftDraw.h Include/W3DDevice/GameClient/Module/W3DOverlordTankDraw.h @@ -73,8 +73,8 @@ set(GAMEENGINEDEVICE_SRC # Include/W3DDevice/GameClient/W3DVideoBuffer.h # Include/W3DDevice/GameClient/W3DView.h Include/W3DDevice/GameClient/W3DVolumetricShadow.h - Include/W3DDevice/GameClient/W3DWater.h - Include/W3DDevice/GameClient/W3DWaterTracks.h +# Include/W3DDevice/GameClient/W3DWater.h +# Include/W3DDevice/GameClient/W3DWaterTracks.h Include/W3DDevice/GameClient/W3DWaypointBuffer.h Include/W3DDevice/GameClient/W3DWebBrowser.h Include/W3DDevice/GameClient/WorldHeightMap.h @@ -102,7 +102,7 @@ set(GAMEENGINEDEVICE_SRC Source/W3DDevice/GameClient/Drawable/Draw/W3DDebrisDraw.cpp Source/W3DDevice/GameClient/Drawable/Draw/W3DDefaultDraw.cpp Source/W3DDevice/GameClient/Drawable/Draw/W3DDependencyModelDraw.cpp - Source/W3DDevice/GameClient/Drawable/Draw/W3DLaserDraw.cpp +# Source/W3DDevice/GameClient/Drawable/Draw/W3DLaserDraw.cpp Source/W3DDevice/GameClient/Drawable/Draw/W3DModelDraw.cpp Source/W3DDevice/GameClient/Drawable/Draw/W3DOverlordAircraftDraw.cpp Source/W3DDevice/GameClient/Drawable/Draw/W3DOverlordTankDraw.cpp @@ -176,8 +176,8 @@ set(GAMEENGINEDEVICE_SRC # Source/W3DDevice/GameClient/W3DView.cpp Source/W3DDevice/GameClient/W3dWaypointBuffer.cpp Source/W3DDevice/GameClient/W3DWebBrowser.cpp - Source/W3DDevice/GameClient/Water/W3DWater.cpp - Source/W3DDevice/GameClient/Water/W3DWaterTracks.cpp +# Source/W3DDevice/GameClient/Water/W3DWater.cpp +# Source/W3DDevice/GameClient/Water/W3DWaterTracks.cpp Source/W3DDevice/GameClient/WorldHeightMap.cpp Source/W3DDevice/GameLogic/W3DGameLogic.cpp Source/W3DDevice/GameLogic/W3DGhostObject.cpp diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt index eb4e80cee01..13f5bc1ef6e 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt @@ -15,8 +15,8 @@ set(WW3D2_SRC #assetstatus.h #bitmaphandler.cpp #bitmaphandler.h - bmp2d.cpp - bmp2d.h + #bmp2d.cpp + #bmp2d.h boxrobj.cpp boxrobj.h #bwrender.cpp @@ -56,8 +56,8 @@ set(WW3D2_SRC dx8renderer.h dx8rendererdebugger.cpp dx8rendererdebugger.h - dx8texman.cpp - dx8texman.h + #dx8texman.cpp + #dx8texman.h dx8vertexbuffer.cpp dx8vertexbuffer.h #dx8webbrowser.cpp @@ -108,8 +108,8 @@ set(WW3D2_SRC mapper.h #matinfo.cpp #matinfo.h - matpass.cpp - matpass.h + #matpass.cpp + #matpass.h matrixmapper.cpp matrixmapper.h mesh.cpp @@ -200,18 +200,18 @@ set(WW3D2_SRC #stripoptimizer.h #surfaceclass.cpp #surfaceclass.h - texproject.cpp - texproject.h + #texproject.cpp + #texproject.h #textdraw.cpp #textdraw.h - texture.cpp - texture.h - texturefilter.cpp - texturefilter.h - textureloader.cpp - textureloader.h - texturethumbnail.cpp - texturethumbnail.h + #texture.cpp + #texture.h + #texturefilter.cpp + #texturefilter.h + #textureloader.cpp + #textureloader.h + #texturethumbnail.cpp + #texturethumbnail.h vertmaterial.cpp vertmaterial.h #visrasterizer.cpp diff --git a/scripts/cpp/unify_move_files.py b/scripts/cpp/unify_move_files.py index 6d401ef28f2..42ec8582a26 100644 --- a/scripts/cpp/unify_move_files.py +++ b/scripts/cpp/unify_move_files.py @@ -190,6 +190,34 @@ def main(): #unify_file(Game.ZEROHOUR, "GameEngineDevice/Include/W3DDevice/GameClient/W3DView.h", Game.CORE, "GameEngineDevice/Include/W3DDevice/GameClient/W3DView.h") #unify_file(Game.ZEROHOUR, "GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp", Game.CORE, "GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp") + #unify_file(Game.ZEROHOUR, "Libraries/Source/WWVegas/WW3D2/bmp2d.cpp", Game.CORE, "Libraries/Source/WWVegas/WW3D2/bmp2d.cpp") + #unify_file(Game.ZEROHOUR, "Libraries/Source/WWVegas/WW3D2/bmp2d.h", Game.CORE, "Libraries/Source/WWVegas/WW3D2/bmp2d.h") + #unify_file(Game.ZEROHOUR, "Libraries/Source/WWVegas/WW3D2/dx8texman.cpp", Game.CORE, "Libraries/Source/WWVegas/WW3D2/dx8texman.cpp") + #unify_file(Game.ZEROHOUR, "Libraries/Source/WWVegas/WW3D2/dx8texman.h", Game.CORE, "Libraries/Source/WWVegas/WW3D2/dx8texman.h") + #unify_file(Game.ZEROHOUR, "Libraries/Source/WWVegas/WW3D2/matpass.cpp", Game.CORE, "Libraries/Source/WWVegas/WW3D2/matpass.cpp") + #unify_file(Game.ZEROHOUR, "Libraries/Source/WWVegas/WW3D2/matpass.h", Game.CORE, "Libraries/Source/WWVegas/WW3D2/matpass.h") + #unify_file(Game.ZEROHOUR, "Libraries/Source/WWVegas/WW3D2/texproject.cpp", Game.CORE, "Libraries/Source/WWVegas/WW3D2/texproject.cpp") + #unify_file(Game.ZEROHOUR, "Libraries/Source/WWVegas/WW3D2/texproject.h", Game.CORE, "Libraries/Source/WWVegas/WW3D2/texproject.h") + #unify_file(Game.ZEROHOUR, "Libraries/Source/WWVegas/WW3D2/texture.cpp", Game.CORE, "Libraries/Source/WWVegas/WW3D2/texture.cpp") + #unify_file(Game.ZEROHOUR, "Libraries/Source/WWVegas/WW3D2/texture.h", Game.CORE, "Libraries/Source/WWVegas/WW3D2/texture.h") + #unify_file(Game.ZEROHOUR, "Libraries/Source/WWVegas/WW3D2/texturefilter.cpp", Game.CORE, "Libraries/Source/WWVegas/WW3D2/texturefilter.cpp") + #unify_file(Game.ZEROHOUR, "Libraries/Source/WWVegas/WW3D2/texturefilter.h", Game.CORE, "Libraries/Source/WWVegas/WW3D2/texturefilter.h") + #unify_file(Game.ZEROHOUR, "Libraries/Source/WWVegas/WW3D2/textureloader.cpp", Game.CORE, "Libraries/Source/WWVegas/WW3D2/textureloader.cpp") + #unify_file(Game.ZEROHOUR, "Libraries/Source/WWVegas/WW3D2/textureloader.h", Game.CORE, "Libraries/Source/WWVegas/WW3D2/textureloader.h") + #unify_file(Game.ZEROHOUR, "Libraries/Source/WWVegas/WW3D2/texturethumbnail.cpp", Game.CORE, "Libraries/Source/WWVegas/WW3D2/texturethumbnail.cpp") + #unify_file(Game.ZEROHOUR, "Libraries/Source/WWVegas/WW3D2/texturethumbnail.h", Game.CORE, "Libraries/Source/WWVegas/WW3D2/texturethumbnail.h") + + #unify_file(Game.ZEROHOUR, "GameEngine/Include/GameClient/Water.h", Game.CORE, "GameEngine/Include/GameClient/Water.h") + #unify_file(Game.ZEROHOUR, "GameEngine/Source/GameClient/Water.cpp", Game.CORE, "GameEngine/Source/GameClient/Water.cpp") + #unify_file(Game.ZEROHOUR, "GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DLaserDraw.h", Game.CORE, "GameEngineDevice/Include/W3DDevice/GameClient/Module/W3DLaserDraw.h") + #unify_file(Game.ZEROHOUR, "GameEngineDevice/Include/W3DDevice/GameClient/W3DWater.h", Game.CORE, "GameEngineDevice/Include/W3DDevice/GameClient/W3DWater.h") + #unify_file(Game.ZEROHOUR, "GameEngineDevice/Include/W3DDevice/GameClient/W3DWaterTracks.h", Game.CORE, "GameEngineDevice/Include/W3DDevice/GameClient/W3DWaterTracks.h") + #unify_file(Game.ZEROHOUR, "GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DLaserDraw.cpp", Game.CORE, "GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DLaserDraw.cpp") + #unify_file(Game.ZEROHOUR, "GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWater.cpp", Game.CORE, "GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWater.cpp") + #unify_file(Game.ZEROHOUR, "GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWaterTracks.cpp", Game.CORE, "GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWaterTracks.cpp") + #unify_file(Game.ZEROHOUR, "GameEngineDevice/Source/W3DDevice/GameClient/Water/wave.nvp", Game.CORE, "GameEngineDevice/Source/W3DDevice/GameClient/Water/wave.nvp") + #unify_file(Game.ZEROHOUR, "GameEngineDevice/Source/W3DDevice/GameClient/Water/wave.nvv", Game.CORE, "GameEngineDevice/Source/W3DDevice/GameClient/Water/wave.nvv") + return