From fe6bf526f5ddb5cc9a751ea22f6851ec34c99ac4 Mon Sep 17 00:00:00 2001 From: ryan-de-boer Date: Tue, 29 Jul 2025 18:28:46 +0800 Subject: [PATCH 01/20] gitignore visual studio output folders --- .gitignore | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index e5e550b48da..814dcc1b7ff 100644 --- a/.gitignore +++ b/.gitignore @@ -55,4 +55,7 @@ cmake-build-*/ ## Ninja .ninja_deps .ninja_log -build.ninja \ No newline at end of file +build.ninja + +out/build/x64-debug +out/build/x86-debug From c4649ba6044c47b8474f38582495c4e275365cd0 Mon Sep 17 00:00:00 2001 From: ryan-de-boer Date: Tue, 29 Jul 2025 18:29:53 +0800 Subject: [PATCH 02/20] Get version of CMake consistant with my VS2022 install --- CMakeLists.txt | 2 +- CMakePresets.json | 4 ++-- Generals/CMakeLists.txt | 2 +- GeneralsMD/CMakeLists.txt | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d2b41feab51..2ab485d0d47 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.25) +cmake_minimum_required(VERSION 3.24) # Use packagename_ROOT for FindPackage. if(POLICY CMP0074) diff --git a/CMakePresets.json b/CMakePresets.json index 51610bf95ca..31a76dfffec 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -1,8 +1,8 @@ { - "version": 6, + "version": 4, "cmakeMinimumRequired": { "major": 3, - "minor": 25, + "minor": 24, "patch": 0 }, "configurePresets": [ diff --git a/Generals/CMakeLists.txt b/Generals/CMakeLists.txt index 7953714f5a9..785a9aa1a6d 100644 --- a/Generals/CMakeLists.txt +++ b/Generals/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.25) +cmake_minimum_required(VERSION 3.24) project(g_generals LANGUAGES C CXX) diff --git a/GeneralsMD/CMakeLists.txt b/GeneralsMD/CMakeLists.txt index d7d20ea93a6..cb8e5ef4bbf 100644 --- a/GeneralsMD/CMakeLists.txt +++ b/GeneralsMD/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.25) +cmake_minimum_required(VERSION 3.24) project(z_generals LANGUAGES C CXX) From 15d5770648fc55c1718008028fb52fb4e9f9808f Mon Sep 17 00:00:00 2001 From: ryan-de-boer Date: Wed, 30 Jul 2025 22:45:27 +0800 Subject: [PATCH 03/20] Modify CMakePresets.json to work with my VS2022 --- CMakePresets.json | 133 +--------------------------------------------- 1 file changed, 1 insertion(+), 132 deletions(-) diff --git a/CMakePresets.json b/CMakePresets.json index 31a76dfffec..3f69d2c556f 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -212,137 +212,6 @@ "description": "Build Unix 32bit VCPKG Release", "configuration": "Release" } - ], - "workflowPresets": [ - { - "name": "vc6", - "steps": [ - { - "type": "configure", - "name": "vc6" - }, - { - "type": "build", - "name": "vc6" - } - ] - }, - { - "name": "vc6-debug", - "steps": [ - { - "type": "configure", - "name": "vc6-debug" - }, - { - "type": "build", - "name": "vc6-debug" - } - ] - }, - { - "name": "vc6-profile", - "steps": [ - { - "type": "configure", - "name": "vc6-profile" - }, - { - "type": "build", - "name": "vc6-profile" - } - ] - }, - { - "name": "win32", - "steps": [ - { - "type": "configure", - "name": "win32" - }, - { - "type": "build", - "name": "win32" - } - ] - }, - { - "name": "win32-profile", - "steps": [ - { - "type": "configure", - "name": "win32-profile" - }, - { - "type": "build", - "name": "win32-profile" - } - ] - }, - { - "name": "win32-debug", - "steps": [ - { - "type": "configure", - "name": "win32-debug" - }, - { - "type": "build", - "name": "win32-debug" - } - ] - }, - { - "name": "win32-vcpkg", - "steps": [ - { - "type": "configure", - "name": "win32-vcpkg" - }, - { - "type": "build", - "name": "win32-vcpkg" - } - ] - }, - { - "name": "win32-vcpkg-profile", - "steps": [ - { - "type": "configure", - "name": "win32-vcpkg-profile" - }, - { - "type": "build", - "name": "win32-vcpkg-profile" - } - ] - }, - { - "name": "win32-vcpkg-debug", - "steps": [ - { - "type": "configure", - "name": "win32-vcpkg-debug" - }, - { - "type": "build", - "name": "win32-vcpkg-debug" - } - ] - }, - { - "name": "unix", - "steps": [ - { - "type": "configure", - "name": "unix" - }, - { - "type": "build", - "name": "unix" - } - ] - } ] + } \ No newline at end of file From 44245d27417c9f4a699b2d26eefcc9b5d2f68c22 Mon Sep 17 00:00:00 2001 From: ryan-de-boer Date: Wed, 30 Jul 2025 22:46:34 +0800 Subject: [PATCH 04/20] Get two dx8 renderers to reuse one function --- .../Common/Graphics/DX8/dx8wrapper_common.h | 77 +++++++++++++ .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 105 ++++++------------ .../Source/WWVegas/WW3D2/dx8wrapper.h | 4 + .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 79 +------------ 4 files changed, 116 insertions(+), 149 deletions(-) create mode 100644 Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h diff --git a/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h b/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h new file mode 100644 index 00000000000..8df2850e336 --- /dev/null +++ b/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h @@ -0,0 +1,77 @@ +bool DX8Wrapper::Init(void* hwnd, bool lite) +{ + WWASSERT(!IsInitted); + + // zero memory + memset(Textures, 0, sizeof(IDirect3DBaseTexture8*) * MAX_TEXTURE_STAGES); + memset(RenderStates, 0, sizeof(unsigned) * 256); + memset(TextureStageStates, 0, sizeof(unsigned) * 32 * MAX_TEXTURE_STAGES); + 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! + */ + _Hwnd = (HWND)hwnd; + _MainThreadID = ThreadClass::_Get_Current_Thread_ID(); + WWDEBUG_SAY(("DX8Wrapper main thread: 0x%x", _MainThreadID)); + CurRenderDevice = -1; + ResolutionWidth = DEFAULT_RESOLUTION_WIDTH; + ResolutionHeight = DEFAULT_RESOLUTION_HEIGHT; + // Initialize Render2DClass Screen Resolution + Render2DClass::Set_Screen_Resolution(RectClass(0, 0, ResolutionWidth, ResolutionHeight)); + BitDepth = DEFAULT_BIT_DEPTH; + IsWindowed = false; + DX8Wrapper_IsWindowed = false; + + for (int light = 0; light < 4; ++light) CurrentDX8LightEnables[light] = false; + + ::ZeroMemory(&old_world, sizeof(D3DMATRIX)); + ::ZeroMemory(&old_view, sizeof(D3DMATRIX)); + ::ZeroMemory(&old_prj, sizeof(D3DMATRIX)); + + //old_vertex_shader; TODO + //old_sr_shader; + //current_shader; + + //world_identity; + //CurrentFogColor; + + D3DInterface = NULL; + D3DDevice = NULL; + + WWDEBUG_SAY(("Reset DX8Wrapper statistics")); + Reset_Statistics(); + + Invalidate_Cached_Render_States(); + + if (!lite) { + D3D8Lib = LoadLibrary("D3D8.DLL"); + + if (D3D8Lib == NULL) return false; // Return false at this point if init failed + + Direct3DCreate8Ptr = (Direct3DCreate8Type)GetProcAddress(D3D8Lib, "Direct3DCreate8"); + if (Direct3DCreate8Ptr == NULL) return false; + + /* + ** Create the D3D interface object + */ + WWDEBUG_SAY(("Create Direct3D8")); + D3DInterface = Direct3DCreate8Ptr(D3D_SDK_VERSION); // TODO: handle failure cases... + if (D3DInterface == NULL) { + return(false); + } + IsInitted = true; + + /* + ** Enumerate the available devices + */ + WWDEBUG_SAY(("Enumerate devices")); + Enumerate_Devices(); + WWDEBUG_SAY(("DX8Wrapper Init completed")); + } + + return(true); +} diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 002b71a4e11..0957296c84d 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -82,6 +82,38 @@ #include "bound.h" #include "dx8webbrowser.h" +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; +}; + const int DEFAULT_RESOLUTION_WIDTH = 640; const int DEFAULT_RESOLUTION_HEIGHT = 480; @@ -125,6 +157,7 @@ Vector4 DX8Wrapper::Pixel_Shader_Constants[MAX_PIXEL_SHADER_CONSTANTS]; LightEnvironmentClass* DX8Wrapper::Light_Environment = NULL; RenderInfoClass* DX8Wrapper::Render_Info = NULL; +ZTextureClass* DX8Wrapper::Shadow_Map[MAX_SHADOW_MAPS]; DWORD DX8Wrapper::Vertex_Processing_Behavior = 0; Vector3 DX8Wrapper::Ambient_Color; // shader system additions KJM ^ @@ -257,77 +290,7 @@ void MoveRectIntoOtherRect(const RECT& inner, const RECT& outer, int* x, int* y) *y += dy; } - -bool DX8Wrapper::Init(void * hwnd, bool lite) -{ - WWASSERT(!IsInitted); - - memset(Vertex_Shader_Constants,0,sizeof(Vector4)*MAX_VERTEX_SHADER_CONSTANTS); - memset(Pixel_Shader_Constants,0,sizeof(Vector4)*MAX_PIXEL_SHADER_CONSTANTS); - /* - ** Initialize all variables! - */ - _Hwnd = (HWND)hwnd; - _MainThreadID=ThreadClass::_Get_Current_Thread_ID(); - WWDEBUG_SAY(("DX8Wrapper main thread: 0x%x",_MainThreadID)); - CurRenderDevice = -1; - ResolutionWidth = DEFAULT_RESOLUTION_WIDTH; - ResolutionHeight = DEFAULT_RESOLUTION_HEIGHT; - // Initialize Render2DClass Screen Resolution - Render2DClass::Set_Screen_Resolution( RectClass( 0, 0, ResolutionWidth, ResolutionHeight ) ); - BitDepth = DEFAULT_BIT_DEPTH; - IsWindowed = false; - DX8Wrapper_IsWindowed = false; - - for (int light=0;light<4;++light) CurrentDX8LightEnables[light]=false; - - ::ZeroMemory(&old_world, sizeof(D3DMATRIX)); - ::ZeroMemory(&old_view, sizeof(D3DMATRIX)); - ::ZeroMemory(&old_prj, sizeof(D3DMATRIX)); - - //old_vertex_shader; TODO - //old_sr_shader; - //current_shader; - - //world_identity; - //CurrentFogColor; - - D3DInterface = NULL; - D3DDevice = NULL; - - WWDEBUG_SAY(("Reset DX8Wrapper statistics")); - Reset_Statistics(); - - Invalidate_Cached_Render_States(); - - if (!lite) { - D3D8Lib = LoadLibrary("D3D8.DLL"); - - if (D3D8Lib == NULL) return false; // Return false at this point if init failed - - Direct3DCreate8Ptr = (Direct3DCreate8Type) GetProcAddress(D3D8Lib, "Direct3DCreate8"); - if (Direct3DCreate8Ptr == NULL) return false; - - /* - ** Create the D3D interface object - */ - WWDEBUG_SAY(("Create Direct3D8")); - D3DInterface = Direct3DCreate8Ptr(D3D_SDK_VERSION); // TODO: handle failure cases... - if (D3DInterface == NULL) { - return(false); - } - IsInitted = true; - - /* - ** Enumerate the available devices - */ - WWDEBUG_SAY(("Enumerate devices")); - Enumerate_Devices(); - WWDEBUG_SAY(("DX8Wrapper Init completed")); - } - - return(true); -} +#include "../../Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h" void DX8Wrapper::Shutdown(void) { diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h index 3956b85fc90..73febc738a7 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h @@ -100,6 +100,8 @@ class TextureClass; class LightClass; class SurfaceClass; +class ZTextureClass; + #define DX8_RECORD_MATRIX_CHANGE() matrix_changes++ #define DX8_RECORD_MATERIAL_CHANGE() material_changes++ #define DX8_RECORD_VERTEX_BUFFER_CHANGE() vertex_buffer_changes++ @@ -459,6 +461,8 @@ class DX8Wrapper static void Set_Vertex_Shader_Constant(int reg, const void* data, int count); static void Set_Pixel_Shader_Constant(int reg, const void* data, int count); + static ZTextureClass* Shadow_Map[MAX_SHADOW_MAPS]; + static DWORD Get_Vertex_Processing_Behavior() { return Vertex_Processing_Behavior; } // Needed by scene lighting class diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 9b6584693f5..3d5bc9c7623 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -269,84 +269,7 @@ void MoveRectIntoOtherRect(const RECT& inner, const RECT& outer, int* x, int* y) *y += dy; } - -bool DX8Wrapper::Init(void * hwnd, bool lite) -{ - WWASSERT(!IsInitted); - - // zero memory - memset(Textures,0,sizeof(IDirect3DBaseTexture8*)*MAX_TEXTURE_STAGES); - memset(RenderStates,0,sizeof(unsigned)*256); - memset(TextureStageStates,0,sizeof(unsigned)*32*MAX_TEXTURE_STAGES); - 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! - */ - _Hwnd = (HWND)hwnd; - _MainThreadID=ThreadClass::_Get_Current_Thread_ID(); - WWDEBUG_SAY(("DX8Wrapper main thread: 0x%x",_MainThreadID)); - CurRenderDevice = -1; - ResolutionWidth = DEFAULT_RESOLUTION_WIDTH; - ResolutionHeight = DEFAULT_RESOLUTION_HEIGHT; - // Initialize Render2DClass Screen Resolution - Render2DClass::Set_Screen_Resolution( RectClass( 0, 0, ResolutionWidth, ResolutionHeight ) ); - BitDepth = DEFAULT_BIT_DEPTH; - IsWindowed = false; - DX8Wrapper_IsWindowed = false; - - for (int light=0;light<4;++light) CurrentDX8LightEnables[light]=false; - - ::ZeroMemory(&old_world, sizeof(D3DMATRIX)); - ::ZeroMemory(&old_view, sizeof(D3DMATRIX)); - ::ZeroMemory(&old_prj, sizeof(D3DMATRIX)); - - //old_vertex_shader; TODO - //old_sr_shader; - //current_shader; - - //world_identity; - //CurrentFogColor; - - D3DInterface = NULL; - D3DDevice = NULL; - - WWDEBUG_SAY(("Reset DX8Wrapper statistics")); - Reset_Statistics(); - - Invalidate_Cached_Render_States(); - - if (!lite) { - D3D8Lib = LoadLibrary("D3D8.DLL"); - - if (D3D8Lib == NULL) return false; // Return false at this point if init failed - - Direct3DCreate8Ptr = (Direct3DCreate8Type) GetProcAddress(D3D8Lib, "Direct3DCreate8"); - if (Direct3DCreate8Ptr == NULL) return false; - - /* - ** Create the D3D interface object - */ - WWDEBUG_SAY(("Create Direct3D8")); - D3DInterface = Direct3DCreate8Ptr(D3D_SDK_VERSION); // TODO: handle failure cases... - if (D3DInterface == NULL) { - return(false); - } - IsInitted = true; - - /* - ** Enumerate the available devices - */ - WWDEBUG_SAY(("Enumerate devices")); - Enumerate_Devices(); - WWDEBUG_SAY(("DX8Wrapper Init completed")); - } - - return(true); -} +#include "../../Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h" void DX8Wrapper::Shutdown(void) { From dac4caf0e5aba64cb7713b66c0a66add0a968e47 Mon Sep 17 00:00:00 2001 From: ryan-de-boer Date: Fri, 1 Aug 2025 12:45:26 +0800 Subject: [PATCH 05/20] Workaround to get world builder running --- Generals/Code/GameEngine/Source/Common/System/Debug.cpp | 4 ++-- Generals/Code/GameEngine/Source/GameClient/GameText.cpp | 1 + GeneralsMD/Code/GameEngine/Source/Common/System/Debug.cpp | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Generals/Code/GameEngine/Source/Common/System/Debug.cpp b/Generals/Code/GameEngine/Source/Common/System/Debug.cpp index ee67d5b7089..ba6ebbffe86 100644 --- a/Generals/Code/GameEngine/Source/Common/System/Debug.cpp +++ b/Generals/Code/GameEngine/Source/Common/System/Debug.cpp @@ -427,8 +427,8 @@ void DebugLog(const char *format, ...) ScopedCriticalSection scopedCriticalSection(TheDebugLogCriticalSection); #endif - if (theDebugFlags == 0) - MessageBoxWrapper("DebugLog - Debug not inited properly", "", MB_OK|MB_TASKMODAL); +// if (theDebugFlags == 0) +// MessageBoxWrapper("DebugLog - Debug not inited properly", "", MB_OK|MB_TASKMODAL); prepBuffer(theBuffer); diff --git a/Generals/Code/GameEngine/Source/GameClient/GameText.cpp b/Generals/Code/GameEngine/Source/GameClient/GameText.cpp index d3e91019cc9..226a1bb0c74 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GameText.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GameText.cpp @@ -1475,6 +1475,7 @@ Char GameTextManager::readChar( File *file ) void GameTextManager::updateWindowTitle() { // TheSuperHackers @tweak Now prints product and version information in the Window title. + return; DEBUG_ASSERTCRASH(TheVersion != NULL, ("TheVersion is NULL")); diff --git a/GeneralsMD/Code/GameEngine/Source/Common/System/Debug.cpp b/GeneralsMD/Code/GameEngine/Source/Common/System/Debug.cpp index df047cdce45..310f8ab51bd 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/System/Debug.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/System/Debug.cpp @@ -428,8 +428,8 @@ void DebugLog(const char *format, ...) ScopedCriticalSection scopedCriticalSection(TheDebugLogCriticalSection); #endif - if (theDebugFlags == 0) - MessageBoxWrapper("DebugLog - Debug not inited properly", "", MB_OK|MB_TASKMODAL); +// if (theDebugFlags == 0) +// MessageBoxWrapper("DebugLog - Debug not inited properly", "", MB_OK|MB_TASKMODAL); prepBuffer(theBuffer); From bd088456861c511e0d8942300c4381cf87716be9 Mon Sep 17 00:00:00 2001 From: ryan-de-boer Date: Fri, 1 Aug 2025 12:47:55 +0800 Subject: [PATCH 06/20] Shared Shutdown and Do_Onetime_Device_Dependent_Inits --- .../Common/Graphics/DX8/dx8wrapper_common.h | 69 ++++++++++++++++++ .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 67 +---------------- .../Libraries/Source/WWVegas/WW3D2/shdlib.h | 73 +++++++++++++++++++ .../Source/WWVegas/WW3D2/texturefilter.cpp | 6 +- .../Source/WWVegas/WW3D2/texturefilter.h | 3 +- .../Libraries/Source/WWVegas/WW3D2/ww3d.cpp | 2 +- .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 66 ----------------- 7 files changed, 152 insertions(+), 134 deletions(-) create mode 100644 Generals/Code/Libraries/Source/WWVegas/WW3D2/shdlib.h diff --git a/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h b/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h index 8df2850e336..9f924ac3869 100644 --- a/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h +++ b/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h @@ -75,3 +75,72 @@ bool DX8Wrapper::Init(void* hwnd, bool lite) return(true); } + +void DX8Wrapper::Shutdown(void) +{ + if (D3DDevice) { + + Set_Render_Target((IDirect3DSurface8*)NULL); + Release_Device(); + } + + if (D3DInterface) { + D3DInterface->Release(); + D3DInterface = NULL; + + } + + if (CurrentCaps) + { + int max = CurrentCaps->Get_Max_Textures_Per_Pass(); + for (int i = 0; i < max; i++) + { + if (Textures[i]) + { + Textures[i]->Release(); + Textures[i] = NULL; + } + } + } + + if (D3DInterface) { + UINT newRefCount = D3DInterface->Release(); + D3DInterface = NULL; + } + + if (D3D8Lib) { + FreeLibrary(D3D8Lib); + D3D8Lib = NULL; + } + + _RenderDeviceNameTable.Clear(); // note - Delete_All() resizes the vector, causing a reallocation. Clear is better. jba. + _RenderDeviceShortNameTable.Clear(); + _RenderDeviceDescriptionTable.Clear(); + + DX8Caps::Shutdown(); + IsInitted = false; // 010803 srj +} + +void DX8Wrapper::Do_Onetime_Device_Dependent_Inits(void) +{ + /* + ** Set Global render states (some of which depend on caps) + */ + Compute_Caps(D3DFormat_To_WW3DFormat(DisplayFormat)); + + /* + ** Initalize any other subsystems inside of WW3D + */ + MissingTexture::_Init(); + TextureFilterClass::_Init_Filters((TextureFilterClass::TextureFilterMode)WW3D::Get_Texture_Filter()); + TheDX8MeshRenderer.Init(); + SHD_INIT; + BoxRenderObjClass::Init(); + VertexMaterialClass::Init(); + PointGroupClass::_Init(); // This needs the VertexMaterialClass to be initted + ShatterSystem::Init(); + TextureLoader::Init(); + + Set_Default_Global_Render_States(); +} + diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 0957296c84d..f8e14c2d4d0 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -82,6 +82,8 @@ #include "bound.h" #include "dx8webbrowser.h" +#include "shdlib.h" + class ZTextureClass : public TextureBaseClass { public: @@ -292,72 +294,7 @@ void MoveRectIntoOtherRect(const RECT& inner, const RECT& outer, int* x, int* y) #include "../../Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h" -void DX8Wrapper::Shutdown(void) -{ - if (D3DDevice) { - - Set_Render_Target ((IDirect3DSurface8 *)NULL); - Release_Device(); - } - - if (D3DInterface) { - D3DInterface->Release(); - D3DInterface=NULL; - - } - - if (CurrentCaps) - { - int max=CurrentCaps->Get_Max_Textures_Per_Pass(); - for (int i = 0; i < max; i++) - { - if (Textures[i]) - { - Textures[i]->Release(); - Textures[i] = NULL; - } - } - } - if (D3DInterface) { - UINT newRefCount=D3DInterface->Release(); - D3DInterface=NULL; - } - - if (D3D8Lib) { - FreeLibrary(D3D8Lib); - D3D8Lib = NULL; - } - - _RenderDeviceNameTable.Clear(); // note - Delete_All() resizes the vector, causing a reallocation. Clear is better. jba. - _RenderDeviceShortNameTable.Clear(); - _RenderDeviceDescriptionTable.Clear(); - - DX8Caps::Shutdown(); - IsInitted = false; // 010803 srj -} - -void DX8Wrapper::Do_Onetime_Device_Dependent_Inits(void) -{ - /* - ** Set Global render states (some of which depend on caps) - */ - Compute_Caps(D3DFormat_To_WW3DFormat(DisplayFormat)); - - /* - ** Initalize any other subsystems inside of WW3D - */ - MissingTexture::_Init(); - TextureFilterClass::_Init_Filters(); - TheDX8MeshRenderer.Init(); - BoxRenderObjClass::Init(); - VertexMaterialClass::Init(); - PointGroupClass::_Init(); // This needs the VertexMaterialClass to be initted - ShatterSystem::Init(); - TextureLoader::Init(); - - Set_Default_Global_Render_States(); -} inline DWORD F2DW(float f) { return *((unsigned*)&f); } void DX8Wrapper::Set_Default_Global_Render_States(void) diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/shdlib.h b/Generals/Code/Libraries/Source/WWVegas/WW3D2/shdlib.h new file mode 100644 index 00000000000..6601f691810 --- /dev/null +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/shdlib.h @@ -0,0 +1,73 @@ +/* +** Command & Conquer Generals Zero Hour(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/wwshade/shdlib.h $* + * + * Org Author:: Kenny Mitchell + * * + * $Author:: Kenny_m + * + * $Modtime:: 07/01/02 9:58p $* + * * + * $Revision:: 1 $* + * * + *---------------------------------------------------------------------------------------------* + * Functions: * + * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +#ifndef SHDLIB_H +#define SHDLIB_H + +// TheSuperHackers @compile Removes the unused WWShade code. (#596) +// If there is a desire to revive this, then the WWShade library needs to be re-added. + +#ifdef USE_WWSHADE + +extern void SHD_Init(); +extern void SHD_Shutdown(); +extern void SHD_Init_Shaders(); +extern void SHD_Shutdown_Shaders(); +extern void SHD_Flush(); +extern void SHD_Register_Loader(); + +#define SHD_INIT SHD_Init() +#define SHD_SHUTDOWN SHD_Shutdown() +#define SHD_INIT_SHADERS SHD_Init_Shaders() +#define SHD_SHUTDOWN_SHADERS SHD_Shutdown_Shaders() +#define SHD_FLUSH SHD_Flush() +#define SHD_REG_LOADER SHD_Register_Loader() + +#else // USE_WWSHADE + +#define SHD_INIT +#define SHD_SHUTDOWN +#define SHD_INIT_SHADERS +#define SHD_SHUTDOWN_SHADERS +#define SHD_FLUSH +#define SHD_REG_LOADER + +#endif // USE_WWSHADE + + +#endif // SHDLIB_H \ No newline at end of file diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/texturefilter.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/texturefilter.cpp index d3b11bbe351..c8c7c0700f4 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/texturefilter.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/texturefilter.cpp @@ -101,7 +101,11 @@ void TextureFilterClass::Apply(unsigned int stage) //! Init filters (legacy) /*! */ -void TextureFilterClass::_Init_Filters(void) +void TextureFilterClass::_Init_Filters() +{ + _Init_Filters((TextureFilterClass::TextureFilterMode)WW3D::Get_Texture_Filter()); +} +void TextureFilterClass::_Init_Filters(TextureFilterMode texture_filter) { const D3DCAPS8& dx8caps=DX8Wrapper::Get_Current_Caps()->Get_DX8_Caps(); diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/texturefilter.h b/Generals/Code/Libraries/Source/WWVegas/WW3D2/texturefilter.h index a4e07d84f79..8177a202f2e 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/texturefilter.h +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/texturefilter.h @@ -115,7 +115,8 @@ class TextureFilterClass void Set_V_Addr_Mode(TxtAddrMode mode) { VAddressMode=mode; } // This needs to be called after device has been created - static void _Init_Filters(void); + static void _Init_Filters(TextureFilterMode texture_filter); + static void _Init_Filters(); static void _Set_Default_Min_Filter(FilterType filter); static void _Set_Default_Mag_Filter(FilterType filter); diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp index b01f96be44a..f030af2a0a8 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp @@ -778,7 +778,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); } diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 3d5bc9c7623..d9c429cc1d6 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -271,73 +271,7 @@ void MoveRectIntoOtherRect(const RECT& inner, const RECT& outer, int* x, int* y) #include "../../Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h" -void DX8Wrapper::Shutdown(void) -{ - if (D3DDevice) { - - Set_Render_Target ((IDirect3DSurface8 *)NULL); - Release_Device(); - } - - if (D3DInterface) { - D3DInterface->Release(); - D3DInterface=NULL; - - } - - if (CurrentCaps) - { - int max=CurrentCaps->Get_Max_Textures_Per_Pass(); - for (int i = 0; i < max; i++) - { - if (Textures[i]) - { - Textures[i]->Release(); - Textures[i] = NULL; - } - } - } - if (D3DInterface) { - UINT newRefCount=D3DInterface->Release(); - D3DInterface=NULL; - } - - if (D3D8Lib) { - FreeLibrary(D3D8Lib); - D3D8Lib = NULL; - } - - _RenderDeviceNameTable.Clear(); // note - Delete_All() resizes the vector, causing a reallocation. Clear is better. jba. - _RenderDeviceShortNameTable.Clear(); - _RenderDeviceDescriptionTable.Clear(); - - DX8Caps::Shutdown(); - IsInitted = false; // 010803 srj -} - -void DX8Wrapper::Do_Onetime_Device_Dependent_Inits(void) -{ - /* - ** Set Global render states (some of which depend on caps) - */ - Compute_Caps(D3DFormat_To_WW3DFormat(DisplayFormat)); - - /* - ** Initalize any other subsystems inside of WW3D - */ - MissingTexture::_Init(); - TextureFilterClass::_Init_Filters((TextureFilterClass::TextureFilterMode)WW3D::Get_Texture_Filter()); - TheDX8MeshRenderer.Init(); - SHD_INIT; - BoxRenderObjClass::Init(); - VertexMaterialClass::Init(); - PointGroupClass::_Init(); // This needs the VertexMaterialClass to be initted - ShatterSystem::Init(); - TextureLoader::Init(); - - Set_Default_Global_Render_States(); -} inline DWORD F2DW(float f) { return *((unsigned*)&f); } void DX8Wrapper::Set_Default_Global_Render_States(void) From 113c08978834324db4ff968148df74228c23c349 Mon Sep 17 00:00:00 2001 From: ryan-de-boer Date: Fri, 1 Aug 2025 13:53:06 +0800 Subject: [PATCH 07/20] Unify Do_Onetime_Device_Dependent_Shutdowns and MAX_VERTEX_STREAMS --- .../Common/Graphics/DX8/dx8wrapper_common.h | 108 ++++++ .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 312 +++++++----------- .../Source/WWVegas/WW3D2/dx8wrapper.h | 124 ++++--- .../Source/WWVegas/WW3D2/sortingrenderer.cpp | 40 ++- .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 106 ------ 5 files changed, 330 insertions(+), 360 deletions(-) diff --git a/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h b/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h index 9f924ac3869..2a303d9c0ab 100644 --- a/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h +++ b/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h @@ -144,3 +144,111 @@ void DX8Wrapper::Do_Onetime_Device_Dependent_Inits(void) Set_Default_Global_Render_States(); } +inline DWORD F2DW(float f) { return *((unsigned*)&f); } +void DX8Wrapper::Set_Default_Global_Render_States(void) +{ + DX8_THREAD_ASSERT(); + const D3DCAPS8& caps = Get_Current_Caps()->Get_DX8_Caps(); + + Set_DX8_Render_State(D3DRS_RANGEFOGENABLE, (caps.RasterCaps & D3DPRASTERCAPS_FOGRANGE) ? TRUE : FALSE); + Set_DX8_Render_State(D3DRS_FOGTABLEMODE, D3DFOG_NONE); + Set_DX8_Render_State(D3DRS_FOGVERTEXMODE, D3DFOG_LINEAR); + Set_DX8_Render_State(D3DRS_SPECULARMATERIALSOURCE, D3DMCS_MATERIAL); + Set_DX8_Render_State(D3DRS_COLORVERTEX, TRUE); + Set_DX8_Render_State(D3DRS_ZBIAS, 0); + Set_DX8_Texture_Stage_State(1, D3DTSS_BUMPENVLSCALE, F2DW(1.0f)); + Set_DX8_Texture_Stage_State(1, D3DTSS_BUMPENVLOFFSET, F2DW(0.0f)); + Set_DX8_Texture_Stage_State(0, D3DTSS_BUMPENVMAT00, F2DW(1.0f)); + Set_DX8_Texture_Stage_State(0, D3DTSS_BUMPENVMAT01, F2DW(0.0f)); + Set_DX8_Texture_Stage_State(0, D3DTSS_BUMPENVMAT10, F2DW(0.0f)); + Set_DX8_Texture_Stage_State(0, D3DTSS_BUMPENVMAT11, F2DW(1.0f)); + + // Set_DX8_Render_State(D3DRS_CULLMODE, D3DCULL_CW); + // Set dither mode here? +} + +//MW: I added this for 'Generals'. +bool DX8Wrapper::Validate_Device(void) +{ + DWORD numPasses = 0; + HRESULT hRes; + + hRes = _Get_D3D_Device8()->ValidateDevice(&numPasses); + + return (hRes == D3D_OK); +} + +void DX8Wrapper::Invalidate_Cached_Render_States(void) +{ + render_state_changed = 0; + + int a; + for (a = 0; a < sizeof(RenderStates) / sizeof(unsigned); ++a) { + RenderStates[a] = 0x12345678; + } + for (a = 0; a < MAX_TEXTURE_STAGES; ++a) + { + for (int b = 0; b < 32; b++) + { + TextureStageStates[a][b] = 0x12345678; + } + //Need to explicitly set texture to NULL, otherwise app will not be able to + //set it to null because of redundant state checker. MW + if (_Get_D3D_Device8()) + _Get_D3D_Device8()->SetTexture(a, NULL); + if (Textures[a] != NULL) { + Textures[a]->Release(); + } + Textures[a] = NULL; + } + + ShaderClass::Invalidate(); + + //Need to explicitly set render_state texture pointers to NULL. MW + Release_Render_State(); + + // (gth) clear the matrix shadows too + for (int i = 0; i < D3DTS_WORLD + 1; i++) { + DX8Transforms[i][0].Set(0, 0, 0, 0); + DX8Transforms[i][1].Set(0, 0, 0, 0); + DX8Transforms[i][2].Set(0, 0, 0, 0); + DX8Transforms[i][3].Set(0, 0, 0, 0); + } + +} + +void DX8Wrapper::Do_Onetime_Device_Dependent_Shutdowns(void) +{ + /* + ** Shutdown ww3d systems + */ + int i; + for (i = 0; i < MAX_VERTEX_STREAMS; ++i) { + if (render_state.vertex_buffers[i]) render_state.vertex_buffers[i]->Release_Engine_Ref(); + REF_PTR_RELEASE(render_state.vertex_buffers[i]); + } + if (render_state.index_buffer) render_state.index_buffer->Release_Engine_Ref(); + REF_PTR_RELEASE(render_state.index_buffer); + REF_PTR_RELEASE(render_state.material); + for (i = 0; i < CurrentCaps->Get_Max_Textures_Per_Pass(); ++i) REF_PTR_RELEASE(render_state.Textures[i]); + + + TextureLoader::Deinit(); + SortingRendererClass::Deinit(); + DynamicVBAccessClass::_Deinit(); + DynamicIBAccessClass::_Deinit(); + ShatterSystem::Shutdown(); + PointGroupClass::_Shutdown(); + VertexMaterialClass::Shutdown(); + BoxRenderObjClass::Shutdown(); + SHD_SHUTDOWN; + TheDX8MeshRenderer.Shutdown(); + MissingTexture::_Deinit(); + + if (CurrentCaps) { + delete CurrentCaps; + CurrentCaps = NULL; + } + +} + diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index f8e14c2d4d0..ad592922009 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -296,110 +296,6 @@ void MoveRectIntoOtherRect(const RECT& inner, const RECT& outer, int* x, int* y) -inline DWORD F2DW(float f) { return *((unsigned*)&f); } -void DX8Wrapper::Set_Default_Global_Render_States(void) -{ - DX8_THREAD_ASSERT(); - const D3DCAPS8 &caps = Get_Current_Caps()->Get_DX8_Caps(); - - Set_DX8_Render_State(D3DRS_RANGEFOGENABLE, (caps.RasterCaps & D3DPRASTERCAPS_FOGRANGE) ? TRUE : FALSE); - Set_DX8_Render_State(D3DRS_FOGTABLEMODE, D3DFOG_NONE); - Set_DX8_Render_State(D3DRS_FOGVERTEXMODE, D3DFOG_LINEAR); - Set_DX8_Render_State(D3DRS_SPECULARMATERIALSOURCE, D3DMCS_MATERIAL); - Set_DX8_Render_State(D3DRS_COLORVERTEX, TRUE); - Set_DX8_Render_State(D3DRS_ZBIAS,0); - Set_DX8_Texture_Stage_State(1, D3DTSS_BUMPENVLSCALE, F2DW(1.0f)); - Set_DX8_Texture_Stage_State(1, D3DTSS_BUMPENVLOFFSET, F2DW(0.0f)); - Set_DX8_Texture_Stage_State(0, D3DTSS_BUMPENVMAT00,F2DW(1.0f)); - Set_DX8_Texture_Stage_State(0, D3DTSS_BUMPENVMAT01,F2DW(0.0f)); - Set_DX8_Texture_Stage_State(0, D3DTSS_BUMPENVMAT10,F2DW(0.0f)); - Set_DX8_Texture_Stage_State(0, D3DTSS_BUMPENVMAT11,F2DW(1.0f)); - -// Set_DX8_Render_State(D3DRS_CULLMODE, D3DCULL_CW); - // Set dither mode here? -} - -//MW: I added this for 'Generals'. -bool DX8Wrapper::Validate_Device(void) -{ DWORD numPasses=0; - HRESULT hRes; - - hRes=_Get_D3D_Device8()->ValidateDevice(&numPasses); - - return (hRes == D3D_OK); -} - -void DX8Wrapper::Invalidate_Cached_Render_States(void) -{ - render_state_changed=0; - - int a; - for (a=0;aSetTexture(a,NULL); - if (Textures[a] != NULL) { - Textures[a]->Release(); - } - Textures[a]=NULL; - } - - ShaderClass::Invalidate(); - - //Need to explicitly set render_state texture pointers to NULL. MW - Release_Render_State(); - - // (gth) clear the matrix shadows too - for (int i=0; iRelease_Engine_Ref(); - REF_PTR_RELEASE(render_state.vertex_buffer); - if (render_state.index_buffer) render_state.index_buffer->Release_Engine_Ref(); - REF_PTR_RELEASE(render_state.index_buffer); - REF_PTR_RELEASE(render_state.material); - for (i=0;iGet_Max_Textures_Per_Pass();++i) REF_PTR_RELEASE(render_state.Textures[i]); - - - TextureLoader::Deinit(); - SortingRendererClass::Deinit(); - DynamicVBAccessClass::_Deinit(); - DynamicIBAccessClass::_Deinit(); - ShatterSystem::Shutdown(); - PointGroupClass::_Shutdown(); - VertexMaterialClass::Shutdown(); - BoxRenderObjClass::Shutdown(); - TheDX8MeshRenderer.Shutdown(); - MissingTexture::_Deinit(); - - if (CurrentCaps) { - delete CurrentCaps; - CurrentCaps=NULL; - } - -} - bool DX8Wrapper::Create_Device(void) { @@ -529,20 +425,23 @@ void DX8Wrapper::Release_Device(void) { if (D3DDevice) { - for (int a=0;aRelease_Engine_Ref(); - REF_PTR_RELEASE(render_state.vertex_buffer); + for (unsigned i = 0; i < MAX_VERTEX_STREAMS; ++i) + { + if (render_state.vertex_buffers[i]) render_state.vertex_buffers[i]->Release_Engine_Ref(); + REF_PTR_RELEASE(render_state.vertex_buffers[i]); + } if (render_state.index_buffer) render_state.index_buffer->Release_Engine_Ref(); REF_PTR_RELEASE(render_state.index_buffer); @@ -556,7 +455,7 @@ void DX8Wrapper::Release_Device(void) */ D3DDevice->Release(); - D3DDevice=NULL; + D3DDevice = NULL; } } @@ -1613,22 +1512,22 @@ void DX8Wrapper::Set_Viewport(CONST D3DVIEWPORT8* pViewport) // // ---------------------------------------------------------------------------- -void DX8Wrapper::Set_Vertex_Buffer(const VertexBufferClass* vb) +void DX8Wrapper::Set_Vertex_Buffer(const VertexBufferClass* vb, unsigned stream) { - render_state.vba_offset=0; - render_state.vba_count=0; - if (render_state.vertex_buffer) { - render_state.vertex_buffer->Release_Engine_Ref(); + render_state.vba_offset = 0; + render_state.vba_count = 0; + if (render_state.vertex_buffers[stream]) { + render_state.vertex_buffers[stream]->Release_Engine_Ref(); } - REF_PTR_SET(render_state.vertex_buffer,const_cast(vb)); + REF_PTR_SET(render_state.vertex_buffers[stream], const_cast(vb)); if (vb) { vb->Add_Engine_Ref(); - render_state.vertex_buffer_type=vb->Type(); + render_state.vertex_buffer_types[stream] = vb->Type(); } else { - render_state.index_buffer_type=BUFFER_TYPE_INVALID; + render_state.vertex_buffer_types[stream] = BUFFER_TYPE_INVALID; } - render_state_changed|=VERTEX_BUFFER_CHANGED; + render_state_changed |= VERTEX_BUFFER_CHANGED; } // ---------------------------------------------------------------------------- @@ -1665,16 +1564,20 @@ void DX8Wrapper::Set_Index_Buffer(const IndexBufferClass* ib,unsigned short inde void DX8Wrapper::Set_Vertex_Buffer(const DynamicVBAccessClass& vba_) { - if (render_state.vertex_buffer) render_state.vertex_buffer->Release_Engine_Ref(); + // Release all streams (only one stream allowed in the legacy pipeline) + for (int i = 1; i < MAX_VERTEX_STREAMS; ++i) { + DX8Wrapper::Set_Vertex_Buffer(NULL, i); + } - DynamicVBAccessClass& vba=const_cast(vba_); - render_state.vertex_buffer_type=vba.Get_Type(); - render_state.vba_offset=vba.VertexBufferOffset; - render_state.vba_count=vba.Get_Vertex_Count(); - REF_PTR_SET(render_state.vertex_buffer,vba.VertexBuffer); - render_state.vertex_buffer->Add_Engine_Ref(); - render_state_changed|=VERTEX_BUFFER_CHANGED; - render_state_changed|=INDEX_BUFFER_CHANGED; // vba_offset changes so index buffer needs to be reset as well. + if (render_state.vertex_buffers[0]) render_state.vertex_buffers[0]->Release_Engine_Ref(); + DynamicVBAccessClass& vba = const_cast(vba_); + render_state.vertex_buffer_types[0] = vba.Get_Type(); + render_state.vba_offset = vba.VertexBufferOffset; + render_state.vba_count = vba.Get_Vertex_Count(); + REF_PTR_SET(render_state.vertex_buffers[0], vba.VertexBuffer); + render_state.vertex_buffers[0]->Add_Engine_Ref(); + render_state_changed |= VERTEX_BUFFER_CHANGED; + render_state_changed |= INDEX_BUFFER_CHANGED; // vba_offset changes so index buffer needs to be reset as well. } // ---------------------------------------------------------------------------- @@ -1710,22 +1613,22 @@ void DX8Wrapper::Draw_Sorting_IB_VB( unsigned short min_vertex_index, unsigned short vertex_count) { - WWASSERT(render_state.vertex_buffer_type==BUFFER_TYPE_SORTING || render_state.vertex_buffer_type==BUFFER_TYPE_DYNAMIC_SORTING); - WWASSERT(render_state.index_buffer_type==BUFFER_TYPE_SORTING || render_state.index_buffer_type==BUFFER_TYPE_DYNAMIC_SORTING); + WWASSERT(render_state.vertex_buffer_types[0] == BUFFER_TYPE_SORTING || render_state.vertex_buffer_types[0] == BUFFER_TYPE_DYNAMIC_SORTING); + WWASSERT(render_state.index_buffer_type == BUFFER_TYPE_SORTING || render_state.index_buffer_type == BUFFER_TYPE_DYNAMIC_SORTING); // Fill dynamic vertex buffer with sorting vertex buffer vertices - DynamicVBAccessClass dyn_vb_access(BUFFER_TYPE_DYNAMIC_DX8,dynamic_fvf_type,vertex_count); + DynamicVBAccessClass dyn_vb_access(BUFFER_TYPE_DYNAMIC_DX8, dynamic_fvf_type, vertex_count); { DynamicVBAccessClass::WriteLockClass lock(&dyn_vb_access); - VertexFormatXYZNDUV2* src = static_cast(render_state.vertex_buffer)->VertexBuffer; - VertexFormatXYZNDUV2* dest= lock.Get_Formatted_Vertex_Array(); + VertexFormatXYZNDUV2* src = static_cast(render_state.vertex_buffers[0])->VertexBuffer; + VertexFormatXYZNDUV2* dest = lock.Get_Formatted_Vertex_Array(); src += render_state.vba_offset + render_state.index_base_offset + min_vertex_index; - unsigned size = dyn_vb_access.FVF_Info().Get_FVF_Size()*vertex_count/sizeof(unsigned); - unsigned *dest_u =(unsigned*) dest; - unsigned *src_u = (unsigned*) src; + unsigned size = dyn_vb_access.FVF_Info().Get_FVF_Size() * vertex_count / sizeof(unsigned); + unsigned* dest_u = (unsigned*)dest; + unsigned* src_u = (unsigned*)src; - for (unsigned i=0;i(dyn_vb_access.VertexBuffer)->Get_DX8_Vertex_Buffer(), dyn_vb_access.FVF_Info().Get_FVF_Size())); - DX8CALL(SetVertexShader(dyn_vb_access.FVF_Info().Get_FVF())); + // If using FVF format VB, set the FVF as vertex shader (may not be needed here KM) + unsigned fvf = dyn_vb_access.FVF_Info().Get_FVF(); + if (fvf != 0) { + DX8CALL(SetVertexShader(fvf)); + } DX8_RECORD_VERTEX_BUFFER_CHANGE(); - unsigned index_count=0; + unsigned index_count = 0; switch (primitive_type) { - case D3DPT_TRIANGLELIST: index_count=polygon_count*3; break; - case D3DPT_TRIANGLESTRIP: index_count=polygon_count+2; break; - case D3DPT_TRIANGLEFAN: index_count=polygon_count+2; break; + case D3DPT_TRIANGLELIST: index_count = polygon_count * 3; break; + case D3DPT_TRIANGLESTRIP: index_count = polygon_count + 2; break; + case D3DPT_TRIANGLEFAN: index_count = polygon_count + 2; break; default: WWASSERT(0); break; // Unsupported primitive type } // Fill dynamic index buffer with sorting index buffer vertices - DynamicIBAccessClass dyn_ib_access(BUFFER_TYPE_DYNAMIC_DX8,index_count); + DynamicIBAccessClass dyn_ib_access(BUFFER_TYPE_DYNAMIC_DX8, index_count); { DynamicIBAccessClass::WriteLockClass lock(&dyn_ib_access); - unsigned short* dest=lock.Get_Index_Array(); - unsigned short* src=NULL; - src=static_cast(render_state.index_buffer)->index_buffer; - src+=render_state.iba_offset+start_index; + unsigned short* dest = lock.Get_Index_Array(); + unsigned short* src = NULL; + src = static_cast(render_state.index_buffer)->index_buffer; + src += render_state.iba_offset + start_index; - for (unsigned short i=0;iGet_Vertex_Count()-render_state.index_base_offset-render_state.vba_offset-min_vertex_index; + vertex_count = render_state.vertex_buffers[0]->Get_Vertex_Count() - render_state.index_base_offset - render_state.vba_offset - min_vertex_index; break; case BUFFER_TYPE_DYNAMIC_DX8: case BUFFER_TYPE_DYNAMIC_SORTING: - vertex_count=render_state.vba_count; + vertex_count = render_state.vba_count; break; } } - switch (render_state.vertex_buffer_type) { + switch (render_state.vertex_buffer_types[0]) { case BUFFER_TYPE_DX8: case BUFFER_TYPE_DYNAMIC_DX8: switch (render_state.index_buffer_type) { case BUFFER_TYPE_DX8: case BUFFER_TYPE_DYNAMIC_DX8: - { -/* if ((start_index+render_state.iba_offset+polygon_count*3) > render_state.index_buffer->Get_Index_Count()) - { WWASSERT_PRINT(0,"OVERFLOWING INDEX BUFFER"); - ///@todo: MUST FIND OUT WHY THIS HAPPENS WITH LOTS OF PARTICLES ON BIG FIGHT! -MW - break; - }*/ - DX8_RECORD_RENDER(polygon_count,vertex_count,render_state.shader); - DX8_RECORD_DRAW_CALLS(); - DX8CALL(DrawIndexedPrimitive( - (D3DPRIMITIVETYPE)primitive_type, - min_vertex_index, - vertex_count, - start_index+render_state.iba_offset, - polygon_count)); - } - break; + { + /* if ((start_index+render_state.iba_offset+polygon_count*3) > render_state.index_buffer->Get_Index_Count()) + { WWASSERT_PRINT(0,"OVERFLOWING INDEX BUFFER"); + ///@todo: MUST FIND OUT WHY THIS HAPPENS WITH LOTS OF PARTICLES ON BIG FIGHT! -MW + break; + }*/ + DX8_RECORD_RENDER(polygon_count, vertex_count, render_state.shader); + DX8_RECORD_DRAW_CALLS(); + DX8CALL(DrawIndexedPrimitive( + (D3DPRIMITIVETYPE)primitive_type, + min_vertex_index, + vertex_count, + start_index + render_state.iba_offset, + polygon_count)); + } + break; case BUFFER_TYPE_SORTING: case BUFFER_TYPE_DYNAMIC_SORTING: - WWASSERT_PRINT(0,"VB and IB must of same type (sorting or dx8)"); + WWASSERT_PRINT(0, "VB and IB must of same type (sorting or dx8)"); break; case BUFFER_TYPE_INVALID: WWASSERT(0); @@ -1903,11 +1810,11 @@ void DX8Wrapper::Draw( switch (render_state.index_buffer_type) { case BUFFER_TYPE_DX8: case BUFFER_TYPE_DYNAMIC_DX8: - WWASSERT_PRINT(0,"VB and IB must of same type (sorting or dx8)"); + WWASSERT_PRINT(0, "VB and IB must of same type (sorting or dx8)"); break; case BUFFER_TYPE_SORTING: case BUFFER_TYPE_DYNAMIC_SORTING: - Draw_Sorting_IB_VB(primitive_type,start_index,polygon_count,min_vertex_index,vertex_count); + Draw_Sorting_IB_VB(primitive_type, start_index, polygon_count, min_vertex_index, vertex_count); break; case BUFFER_TYPE_INVALID: WWASSERT(0); @@ -2059,28 +1966,37 @@ void DX8Wrapper::Apply_Render_State_Changes() SNAPSHOT_SAY(("DX8 - apply view matrix")); _Set_DX8_Transform(D3DTS_VIEW,render_state.view); } - if (render_state_changed&VERTEX_BUFFER_CHANGED) { + if (render_state_changed & VERTEX_BUFFER_CHANGED) { SNAPSHOT_SAY(("DX8 - apply vb change")); - if (render_state.vertex_buffer) { - switch (render_state.vertex_buffer_type) {//->Type()) { - case BUFFER_TYPE_DX8: - case BUFFER_TYPE_DYNAMIC_DX8: - DX8CALL(SetStreamSource( - 0, - static_cast(render_state.vertex_buffer)->Get_DX8_Vertex_Buffer(), - render_state.vertex_buffer->FVF_Info().Get_FVF_Size())); + for (i = 0; i < MAX_VERTEX_STREAMS; ++i) { + if (render_state.vertex_buffers[i]) { + switch (render_state.vertex_buffer_types[i]) {//->Type()) { + case BUFFER_TYPE_DX8: + case BUFFER_TYPE_DYNAMIC_DX8: + DX8CALL(SetStreamSource( + i, + static_cast(render_state.vertex_buffers[i])->Get_DX8_Vertex_Buffer(), + render_state.vertex_buffers[i]->FVF_Info().Get_FVF_Size())); + DX8_RECORD_VERTEX_BUFFER_CHANGE(); + { + // If the VB format is FVF, set the FVF as a vertex shader + unsigned fvf = render_state.vertex_buffers[i]->FVF_Info().Get_FVF(); + if (fvf != 0) { + Set_Vertex_Shader(fvf); + } + } + break; + case BUFFER_TYPE_SORTING: + case BUFFER_TYPE_DYNAMIC_SORTING: + break; + default: + WWASSERT(0); + } + } + else { + DX8CALL(SetStreamSource(i, NULL, 0)); DX8_RECORD_VERTEX_BUFFER_CHANGE(); - DX8CALL(SetVertexShader(render_state.vertex_buffer->FVF_Info().Get_FVF())); - break; - case BUFFER_TYPE_SORTING: - case BUFFER_TYPE_DYNAMIC_SORTING: - break; - default: - WWASSERT(0); } - } else { - DX8CALL(SetStreamSource(0,NULL,0)); - DX8_RECORD_VERTEX_BUFFER_CHANGE(); } } if (render_state_changed&INDEX_BUFFER_CHANGED) { diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h index 73febc738a7..f3af7a9f259 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h @@ -180,14 +180,15 @@ struct RenderStateStruct TextureBaseClass * Textures[MAX_TEXTURE_STAGES]; D3DLIGHT8 Lights[4]; bool LightEnable[4]; + //unsigned lightsHash; Matrix4x4 world; Matrix4x4 view; - unsigned vertex_buffer_type; + unsigned vertex_buffer_types[MAX_VERTEX_STREAMS]; unsigned index_buffer_type; unsigned short vba_offset; unsigned short vba_count; unsigned short iba_offset; - VertexBufferClass* vertex_buffer; + VertexBufferClass* vertex_buffers[MAX_VERTEX_STREAMS]; IndexBufferClass* index_buffer; unsigned short index_base_offset; @@ -280,7 +281,7 @@ class DX8Wrapper static void Set_Viewport(CONST D3DVIEWPORT8* pViewport); - static void Set_Vertex_Buffer(const VertexBufferClass* vb); + static void Set_Vertex_Buffer(const VertexBufferClass* vb, unsigned stream = 0); static void Set_Vertex_Buffer(const DynamicVBAccessClass& vba); static void Set_Index_Buffer(const IndexBufferClass* ib,unsigned short index_base_offset); static void Set_Index_Buffer(const DynamicIBAccessClass& iba,unsigned short index_base_offset); @@ -1255,94 +1256,137 @@ WWINLINE bool DX8Wrapper::Is_Light_Enabled(unsigned index) WWINLINE void DX8Wrapper::Set_Render_State(const RenderStateStruct& state) { + int i; + if (render_state.index_buffer) { render_state.index_buffer->Release_Engine_Ref(); } - if (render_state.vertex_buffer) { - render_state.vertex_buffer->Release_Engine_Ref(); + for (i = 0; i < MAX_VERTEX_STREAMS; ++i) + { + if (render_state.vertex_buffers[i]) + { + render_state.vertex_buffers[i]->Release_Engine_Ref(); + } } - render_state=state; - render_state_changed=0xffffffff; + render_state = state; + render_state_changed = 0xffffffff; if (render_state.index_buffer) { render_state.index_buffer->Add_Engine_Ref(); } - if (render_state.vertex_buffer) { - render_state.vertex_buffer->Add_Engine_Ref(); + for (i = 0; i < MAX_VERTEX_STREAMS; ++i) + { + if (render_state.vertex_buffers[i]) + { + render_state.vertex_buffers[i]->Add_Engine_Ref(); + } } } WWINLINE void DX8Wrapper::Release_Render_State() -{ +{ + int i; + if (render_state.index_buffer) { render_state.index_buffer->Release_Engine_Ref(); } - if (render_state.vertex_buffer) { - render_state.vertex_buffer->Release_Engine_Ref(); + for (i = 0; i < MAX_VERTEX_STREAMS; ++i) { + if (render_state.vertex_buffers[i]) { + render_state.vertex_buffers[i]->Release_Engine_Ref(); + } } - REF_PTR_RELEASE(render_state.vertex_buffer); + for (i = 0; i < MAX_VERTEX_STREAMS; ++i) { + REF_PTR_RELEASE(render_state.vertex_buffers[i]); + } REF_PTR_RELEASE(render_state.index_buffer); REF_PTR_RELEASE(render_state.material); - for (unsigned i=0;i bool SortingRendererClass::_EnableTriangleDraw=true; unsigned DEFAULT_SORTING_POLY_COUNT = 16384; // (count * 3) must be less than 65536 @@ -347,7 +348,7 @@ void SortingRendererClass::Insert_Triangles( state->min_vertex_index=min_vertex_index; state->vertex_count=vertex_count; - SortingVertexBufferClass* vertex_buffer=static_cast(state->sorting_state.vertex_buffer); + SortingVertexBufferClass* vertex_buffer=static_cast(state->sorting_state.vertex_buffers[0]); WWASSERT(vertex_buffer); WWASSERT(state->vertex_count<=vertex_buffer->Get_Vertex_Count()); @@ -421,10 +422,12 @@ void SortingRendererClass::Insert_Triangles( void Release_Refs(SortingNodeStruct* state) { int i; - REF_PTR_RELEASE(state->sorting_state.vertex_buffer); + for (i = 0; i < MAX_VERTEX_STREAMS; ++i) { + REF_PTR_RELEASE(state->sorting_state.vertex_buffers[i]); + } REF_PTR_RELEASE(state->sorting_state.index_buffer); REF_PTR_RELEASE(state->sorting_state.material); - for (i=0;iGet_Max_Textures_Per_Pass();++i) + for (i = 0; i < DX8Wrapper::Get_Current_Caps()->Get_Max_Textures_Per_Pass(); ++i) { REF_PTR_RELEASE(state->sorting_state.Textures[i]); } @@ -544,7 +547,7 @@ void SortingRendererClass::Flush_Sorting_Pool() float* vertex_z_array=Get_Vertex_Z_Array(state->vertex_count); VertexFormatXYZNDUV2* src_verts=NULL; - SortingVertexBufferClass* vertex_buffer=static_cast(state->sorting_state.vertex_buffer); + SortingVertexBufferClass* vertex_buffer=static_cast(state->sorting_state.vertex_buffers[0]); WWASSERT(vertex_buffer); src_verts=vertex_buffer->VertexBuffer; WWASSERT(src_verts); @@ -696,42 +699,47 @@ void SortingRendererClass::Flush_Sorting_Pool() void SortingRendererClass::Flush() { + WWPROFILE("SortingRenderer::Flush"); Matrix4x4 old_view; Matrix4x4 old_world; - DX8Wrapper::Get_Transform(D3DTS_VIEW,old_view); - DX8Wrapper::Get_Transform(D3DTS_WORLD,old_world); + DX8Wrapper::Get_Transform(D3DTS_VIEW, old_view); + DX8Wrapper::Get_Transform(D3DTS_WORLD, old_world); - while (SortingNodeStruct* state=sorted_list.Head()) { + while (SortingNodeStruct* state = sorted_list.Head()) { state->Remove(); - - if ((state->sorting_state.index_buffer_type==BUFFER_TYPE_SORTING || state->sorting_state.index_buffer_type==BUFFER_TYPE_DYNAMIC_SORTING) && - (state->sorting_state.vertex_buffer_type==BUFFER_TYPE_SORTING || state->sorting_state.vertex_buffer_type==BUFFER_TYPE_DYNAMIC_SORTING)) { + + if ((state->sorting_state.index_buffer_type == BUFFER_TYPE_SORTING || state->sorting_state.index_buffer_type == BUFFER_TYPE_DYNAMIC_SORTING) && + (state->sorting_state.vertex_buffer_types[0] == BUFFER_TYPE_SORTING || state->sorting_state.vertex_buffer_types[0] == BUFFER_TYPE_DYNAMIC_SORTING)) { Insert_To_Sorting_Pool(state); } else { DX8Wrapper::Set_Render_State(state->sorting_state); - DX8Wrapper::Draw_Triangles(state->start_index,state->polygon_count,state->min_vertex_index,state->vertex_count); + DX8Wrapper::Draw_Triangles(state->start_index, state->polygon_count, state->min_vertex_index, state->vertex_count); DX8Wrapper::Release_Render_State(); Release_Refs(state); clean_list.Add_Head(state); } } + bool old_enable = DX8Wrapper::_Is_Triangle_Draw_Enabled(); + DX8Wrapper::_Enable_Triangle_Draw(_EnableTriangleDraw); Flush_Sorting_Pool(); + DX8Wrapper::_Enable_Triangle_Draw(old_enable); - DX8Wrapper::Set_Index_Buffer(0,0); + DX8Wrapper::Set_Index_Buffer(0, 0); DX8Wrapper::Set_Vertex_Buffer(0); - total_sorting_vertices=0; + total_sorting_vertices = 0; DynamicIBAccessClass::_Reset(false); DynamicVBAccessClass::_Reset(false); - DX8Wrapper::Set_Transform(D3DTS_VIEW,old_view); - DX8Wrapper::Set_Transform(D3DTS_WORLD,old_world); + DX8Wrapper::Set_Transform(D3DTS_VIEW, old_view); + DX8Wrapper::Set_Transform(D3DTS_WORLD, old_world); } + // ---------------------------------------------------------------------------- void SortingRendererClass::Deinit() @@ -811,7 +819,7 @@ void SortingRendererClass::Insert_VolumeParticle( state->polygon_count=polygon_count * layerCount;//THIS IS VOLUME_PARTICLE SPECIFIC state->vertex_count=vertex_count * layerCount;//THIS IS VOLUME_PARTICLE SPECIFIC - SortingVertexBufferClass* vertex_buffer=static_cast(state->sorting_state.vertex_buffer); + SortingVertexBufferClass* vertex_buffer=static_cast(state->sorting_state.vertex_buffers[0]); WWASSERT(vertex_buffer); WWASSERT(state->vertex_count<=vertex_buffer->Get_Vertex_Count()); diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index d9c429cc1d6..503c270675c 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -273,112 +273,6 @@ void MoveRectIntoOtherRect(const RECT& inner, const RECT& outer, int* x, int* y) -inline DWORD F2DW(float f) { return *((unsigned*)&f); } -void DX8Wrapper::Set_Default_Global_Render_States(void) -{ - DX8_THREAD_ASSERT(); - const D3DCAPS8 &caps = Get_Current_Caps()->Get_DX8_Caps(); - - Set_DX8_Render_State(D3DRS_RANGEFOGENABLE, (caps.RasterCaps & D3DPRASTERCAPS_FOGRANGE) ? TRUE : FALSE); - Set_DX8_Render_State(D3DRS_FOGTABLEMODE, D3DFOG_NONE); - Set_DX8_Render_State(D3DRS_FOGVERTEXMODE, D3DFOG_LINEAR); - Set_DX8_Render_State(D3DRS_SPECULARMATERIALSOURCE, D3DMCS_MATERIAL); - Set_DX8_Render_State(D3DRS_COLORVERTEX, TRUE); - Set_DX8_Render_State(D3DRS_ZBIAS,0); - Set_DX8_Texture_Stage_State(1, D3DTSS_BUMPENVLSCALE, F2DW(1.0f)); - Set_DX8_Texture_Stage_State(1, D3DTSS_BUMPENVLOFFSET, F2DW(0.0f)); - Set_DX8_Texture_Stage_State(0, D3DTSS_BUMPENVMAT00,F2DW(1.0f)); - Set_DX8_Texture_Stage_State(0, D3DTSS_BUMPENVMAT01,F2DW(0.0f)); - Set_DX8_Texture_Stage_State(0, D3DTSS_BUMPENVMAT10,F2DW(0.0f)); - Set_DX8_Texture_Stage_State(0, D3DTSS_BUMPENVMAT11,F2DW(1.0f)); - -// Set_DX8_Render_State(D3DRS_CULLMODE, D3DCULL_CW); - // Set dither mode here? -} - -//MW: I added this for 'Generals'. -bool DX8Wrapper::Validate_Device(void) -{ DWORD numPasses=0; - HRESULT hRes; - - hRes=_Get_D3D_Device8()->ValidateDevice(&numPasses); - - return (hRes == D3D_OK); -} - -void DX8Wrapper::Invalidate_Cached_Render_States(void) -{ - render_state_changed=0; - - int a; - for (a=0;aSetTexture(a,NULL); - if (Textures[a] != NULL) { - Textures[a]->Release(); - } - Textures[a]=NULL; - } - - ShaderClass::Invalidate(); - - //Need to explicitly set render_state texture pointers to NULL. MW - Release_Render_State(); - - // (gth) clear the matrix shadows too - for (int i=0; iRelease_Engine_Ref(); - REF_PTR_RELEASE(render_state.vertex_buffers[i]); - } - if (render_state.index_buffer) render_state.index_buffer->Release_Engine_Ref(); - REF_PTR_RELEASE(render_state.index_buffer); - REF_PTR_RELEASE(render_state.material); - for (i=0;iGet_Max_Textures_Per_Pass();++i) REF_PTR_RELEASE(render_state.Textures[i]); - - - TextureLoader::Deinit(); - SortingRendererClass::Deinit(); - DynamicVBAccessClass::_Deinit(); - DynamicIBAccessClass::_Deinit(); - ShatterSystem::Shutdown(); - PointGroupClass::_Shutdown(); - VertexMaterialClass::Shutdown(); - BoxRenderObjClass::Shutdown(); - SHD_SHUTDOWN; - TheDX8MeshRenderer.Shutdown(); - MissingTexture::_Deinit(); - - if (CurrentCaps) { - delete CurrentCaps; - CurrentCaps=NULL; - } - -} bool DX8Wrapper::Create_Device(void) From b9724b7f0284fcdd443ee56d6d0b8381fc1bfba6 Mon Sep 17 00:00:00 2001 From: ryan-de-boer Date: Fri, 1 Aug 2025 14:51:08 +0800 Subject: [PATCH 08/20] Not crashing --- .../Code/Libraries/Source/WWVegas/WW3D2/sortingrenderer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/sortingrenderer.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/sortingrenderer.cpp index 9e19014a5c1..d33dae7adfc 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/sortingrenderer.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/sortingrenderer.cpp @@ -339,7 +339,7 @@ void SortingRendererClass::Insert_Triangles( WWASSERT( ((state->sorting_state.index_buffer_type==BUFFER_TYPE_SORTING || state->sorting_state.index_buffer_type==BUFFER_TYPE_DYNAMIC_SORTING) && - (state->sorting_state.vertex_buffer_type==BUFFER_TYPE_SORTING || state->sorting_state.vertex_buffer_type==BUFFER_TYPE_DYNAMIC_SORTING))); + (state->sorting_state.vertex_buffer_types[0] == BUFFER_TYPE_SORTING || state->sorting_state.vertex_buffer_types[0] == BUFFER_TYPE_DYNAMIC_SORTING))); state->bounding_sphere=bounding_sphere; @@ -811,7 +811,7 @@ void SortingRendererClass::Insert_VolumeParticle( WWASSERT( ((state->sorting_state.index_buffer_type==BUFFER_TYPE_SORTING || state->sorting_state.index_buffer_type==BUFFER_TYPE_DYNAMIC_SORTING) && - (state->sorting_state.vertex_buffer_type==BUFFER_TYPE_SORTING || state->sorting_state.vertex_buffer_type==BUFFER_TYPE_DYNAMIC_SORTING))); + (state->sorting_state.vertex_buffer_types[0] ==BUFFER_TYPE_SORTING || state->sorting_state.vertex_buffer_types[0] ==BUFFER_TYPE_DYNAMIC_SORTING))); state->bounding_sphere=bounding_sphere; state->start_index=start_index; From b69831c8fee804519c531df8cf01d24d331e1d78 Mon Sep 17 00:00:00 2001 From: ryan-de-boer Date: Fri, 1 Aug 2025 14:57:15 +0800 Subject: [PATCH 09/20] Up to Enumerate_Devices, dx8 caps tricky --- .../Common/Graphics/DX8/dx8wrapper_common.h | 304 ++++++++++++++++++ .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 162 ---------- .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 213 ------------ 3 files changed, 304 insertions(+), 375 deletions(-) diff --git a/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h b/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h index 2a303d9c0ab..329cdb7e298 100644 --- a/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h +++ b/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h @@ -252,3 +252,307 @@ void DX8Wrapper::Do_Onetime_Device_Dependent_Shutdowns(void) } +bool DX8Wrapper::Create_Device(void) +{ + WWASSERT(D3DDevice == NULL); // for now, once you've created a device, you're stuck with it! + + D3DCAPS8 caps; + if + ( + FAILED + ( + D3DInterface->GetDeviceCaps + ( + CurRenderDevice, + WW3D_DEVTYPE, + &caps + ) + ) + ) + { + return false; + } + + ::ZeroMemory(&CurrentAdapterIdentifier, sizeof(D3DADAPTER_IDENTIFIER8)); + + if + ( + FAILED + ( + D3DInterface->GetAdapterIdentifier + ( + CurRenderDevice, + D3DENUM_NO_WHQL_LEVEL, + &CurrentAdapterIdentifier + ) + ) + ) + { + return false; + } + +#ifndef _XBOX + + Vertex_Processing_Behavior = (caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) ? + D3DCREATE_MIXED_VERTEXPROCESSING : D3DCREATE_SOFTWARE_VERTEXPROCESSING; + + // enable this when all 'get' dx calls are removed KJM + /*if (caps.DevCaps&D3DDEVCAPS_PUREDEVICE) + { + Vertex_Processing_Behavior|=D3DCREATE_PUREDEVICE; + }*/ + +#else // XBOX + Vertex_Processing_Behavior = D3DCREATE_PUREDEVICE; +#endif // XBOX + +#ifdef CREATE_DX8_MULTI_THREADED + Vertex_Processing_Behavior |= D3DCREATE_MULTITHREADED; + _DX8SingleThreaded = false; +#else + _DX8SingleThreaded = true; +#endif + + if (DX8Wrapper_PreserveFPU) + Vertex_Processing_Behavior |= D3DCREATE_FPU_PRESERVE; + +#ifdef CREATE_DX8_FPU_PRESERVE + Vertex_Processing_Behavior |= D3DCREATE_FPU_PRESERVE; +#endif + + HRESULT hr = D3DInterface->CreateDevice + ( + CurRenderDevice, + WW3D_DEVTYPE, + _Hwnd, + Vertex_Processing_Behavior, + &_PresentParameters, + &D3DDevice + ); + + if (FAILED(hr)) + { + // The device selection may fail because the device lied that it supports 32 bit zbuffer with 16 bit + // display. This happens at least on Voodoo2. + + if ((_PresentParameters.BackBufferFormat == D3DFMT_R5G6B5 || + _PresentParameters.BackBufferFormat == D3DFMT_X1R5G5B5 || + _PresentParameters.BackBufferFormat == D3DFMT_A1R5G5B5) && + (_PresentParameters.AutoDepthStencilFormat == D3DFMT_D32 || + _PresentParameters.AutoDepthStencilFormat == D3DFMT_D24S8 || + _PresentParameters.AutoDepthStencilFormat == D3DFMT_D24X8)) + { + _PresentParameters.AutoDepthStencilFormat = D3DFMT_D16; + hr = D3DInterface->CreateDevice + ( + CurRenderDevice, + WW3D_DEVTYPE, + _Hwnd, + Vertex_Processing_Behavior, + &_PresentParameters, + &D3DDevice + ); + + if (FAILED(hr)) + { + return false; + } + } + else + { + return false; + } + } + + /* + ** Initialize all subsystems + */ + Do_Onetime_Device_Dependent_Inits(); + return true; +} + +bool DX8Wrapper::Reset_Device(bool reload_assets) +{ + WWDEBUG_SAY(("Resetting device.")); + DX8_THREAD_ASSERT(); + if ((IsInitted) && (D3DDevice != NULL)) { + // Release all non-MANAGED stuff + WW3D::_Invalidate_Textures(); + + for (unsigned i = 0; i < MAX_VERTEX_STREAMS; ++i) + { + Set_Vertex_Buffer(NULL, i); + } + Set_Index_Buffer(NULL, 0); + if (m_pCleanupHook) { + m_pCleanupHook->ReleaseResources(); + } + DynamicVBAccessClass::_Deinit(); + DynamicIBAccessClass::_Deinit(); + DX8TextureManagerClass::Release_Textures(); + SHD_SHUTDOWN_SHADERS; + + // Reset frame count to reflect the flipping chain being reset by Reset() + FrameCount = 0; + + memset(Vertex_Shader_Constants, 0, sizeof(Vector4) * MAX_VERTEX_SHADER_CONSTANTS); + memset(Pixel_Shader_Constants, 0, sizeof(Vector4) * MAX_PIXEL_SHADER_CONSTANTS); + + HRESULT hr = _Get_D3D_Device8()->TestCooperativeLevel(); + if (hr != D3DERR_DEVICELOST) + { + DX8CALL_HRES(Reset(&_PresentParameters), hr) + if (hr != D3D_OK) + return false; //reset failed. + } + else + return false; //device is lost and can't be reset. + + if (reload_assets) + { + DX8TextureManagerClass::Recreate_Textures(); + if (m_pCleanupHook) { + m_pCleanupHook->ReAcquireResources(); + } + } + Invalidate_Cached_Render_States(); + Set_Default_Global_Render_States(); + SHD_INIT_SHADERS; + WWDEBUG_SAY(("Device reset completed")); + return true; + } + WWDEBUG_SAY(("Device reset failed")); + return false; +} + +void DX8Wrapper::Release_Device(void) +{ + if (D3DDevice) { + + for (int a = 0; a < MAX_TEXTURE_STAGES; ++a) + { //release references to any textures that were used in last rendering call + DX8CALL(SetTexture(a, NULL)); + } + + DX8CALL(SetStreamSource(0, NULL, 0)); //release reference count on last rendered vertex buffer + DX8CALL(SetIndices(NULL, 0)); //release reference count on last rendered index buffer + + + /* + ** Release the current vertex and index buffers + */ + for (unsigned i = 0; i < MAX_VERTEX_STREAMS; ++i) + { + if (render_state.vertex_buffers[i]) render_state.vertex_buffers[i]->Release_Engine_Ref(); + REF_PTR_RELEASE(render_state.vertex_buffers[i]); + } + if (render_state.index_buffer) render_state.index_buffer->Release_Engine_Ref(); + REF_PTR_RELEASE(render_state.index_buffer); + + /* + ** Shutdown all subsystems + */ + Do_Onetime_Device_Dependent_Shutdowns(); + + /* + ** Release the device + */ + + D3DDevice->Release(); + D3DDevice = NULL; + } +} + +//void DX8Wrapper::Enumerate_Devices() +//{ +// DX8_Assert(); +// +// int adapter_count = D3DInterface->GetAdapterCount(); +// for (int adapter_index = 0; adapter_index < adapter_count; adapter_index++) { +// +// D3DADAPTER_IDENTIFIER8 id; +// ::ZeroMemory(&id, sizeof(D3DADAPTER_IDENTIFIER8)); +// HRESULT res = D3DInterface->GetAdapterIdentifier(adapter_index, D3DENUM_NO_WHQL_LEVEL, &id); +// +// if (res == D3D_OK) { +// +// /* +// ** Set up the render device description +// ** TODO: Fill in more fields of the render device description? (need some lookup tables) +// */ +// RenderDeviceDescClass desc; +// desc.set_device_name(id.Description); +// desc.set_driver_name(id.Driver); +// +// char buf[64]; +// sprintf(buf, "%d.%d.%d.%d", //"%04x.%04x.%04x.%04x", +// HIWORD(id.DriverVersion.HighPart), +// LOWORD(id.DriverVersion.HighPart), +// HIWORD(id.DriverVersion.LowPart), +// LOWORD(id.DriverVersion.LowPart)); +// +// desc.set_driver_version(buf); +// +// D3DInterface->GetDeviceCaps(adapter_index, WW3D_DEVTYPE, &desc.Caps); +// D3DInterface->GetAdapterIdentifier(adapter_index, D3DENUM_NO_WHQL_LEVEL, &desc.AdapterIdentifier); +// +// DX8Caps dx8caps(D3DInterface, desc.Caps, WW3D_FORMAT_UNKNOWN, desc.AdapterIdentifier); +// +// /* +// ** Enumerate the resolutions +// */ +// desc.reset_resolution_list(); +// int mode_count = D3DInterface->GetAdapterModeCount(adapter_index); +// for (int mode_index = 0; mode_index < mode_count; mode_index++) { +// D3DDISPLAYMODE d3dmode; +// ::ZeroMemory(&d3dmode, sizeof(D3DDISPLAYMODE)); +// HRESULT res = D3DInterface->EnumAdapterModes(adapter_index, mode_index, &d3dmode); +// +// if (res == D3D_OK) { +// int bits = 0; +// switch (d3dmode.Format) +// { +// case D3DFMT_R8G8B8: +// case D3DFMT_A8R8G8B8: +// case D3DFMT_X8R8G8B8: bits = 32; break; +// +// case D3DFMT_R5G6B5: +// case D3DFMT_X1R5G5B5: bits = 16; break; +// } +// +// // Some cards fail in certain modes, DX8Caps keeps list of those. +// if (!dx8caps.Is_Valid_Display_Format(d3dmode.Width, d3dmode.Height, D3DFormat_To_WW3DFormat(d3dmode.Format))) { +// bits = 0; +// } +// +// /* +// ** If we recognize the format, add it to the list +// ** TODO: should we handle more formats? will any cards report more than 24 or 16 bit? +// */ +// if (bits != 0) { +// desc.add_resolution(d3dmode.Width, d3dmode.Height, bits); +// } +// } +// } +// +// // IML: If the device has one or more valid resolutions add it to the device list. +// // NOTE: Testing has shown that there are drivers with zero resolutions. +// if (desc.Enumerate_Resolutions().Count() > 0) { +// +// /* +// ** Set up the device name +// */ +// StringClass device_name(id.Description, true); +// _RenderDeviceNameTable.Add(device_name); +// _RenderDeviceShortNameTable.Add(device_name); // for now, just add the same name to the "pretty name table" +// +// /* +// ** Add the render device to our table +// */ +// _RenderDeviceDescriptionTable.Add(desc); +// } +// } +// } +//} + + diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index ad592922009..8ae8fbc9c6a 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -297,168 +297,6 @@ void MoveRectIntoOtherRect(const RECT& inner, const RECT& outer, int* x, int* y) -bool DX8Wrapper::Create_Device(void) -{ - WWASSERT(D3DDevice==NULL); // for now, once you've created a device, you're stuck with it! - - D3DCAPS8 caps; - if - ( - FAILED - ( - D3DInterface->GetDeviceCaps - ( - CurRenderDevice, - WW3D_DEVTYPE, - &caps - ) - ) - ) - { - return false; - } - - ::ZeroMemory(&CurrentAdapterIdentifier, sizeof(D3DADAPTER_IDENTIFIER8)); - - if - ( - FAILED - ( - D3DInterface->GetAdapterIdentifier - ( - CurRenderDevice, - D3DENUM_NO_WHQL_LEVEL, - &CurrentAdapterIdentifier - ) - ) - ) - { - return false; - } - - Vertex_Processing_Behavior=D3DCREATE_SOFTWARE_VERTEXPROCESSING; - if (caps.DevCaps&D3DDEVCAPS_HWTRANSFORMANDLIGHT) - { - Vertex_Processing_Behavior=D3DCREATE_MIXED_VERTEXPROCESSING; - } - -#ifdef CREATE_DX8_MULTI_THREADED - Vertex_Processing_Behavior|=D3DCREATE_MULTITHREADED; - _DX8SingleThreaded=false; -#else - _DX8SingleThreaded=true; -#endif - - if (DX8Wrapper_PreserveFPU) - Vertex_Processing_Behavior |= D3DCREATE_FPU_PRESERVE; - -#ifdef CREATE_DX8_FPU_PRESERVE - Vertex_Processing_Behavior|=D3DCREATE_FPU_PRESERVE; -#endif - - HRESULT hr=D3DInterface->CreateDevice - ( - CurRenderDevice, - WW3D_DEVTYPE, - _Hwnd, - Vertex_Processing_Behavior, - &_PresentParameters, - &D3DDevice - ); - - if (FAILED(hr)) - { - return false; - } - - /* - ** Initialize all subsystems - */ - Do_Onetime_Device_Dependent_Inits(); - return true; -} - -bool DX8Wrapper::Reset_Device(bool reload_assets) -{ - WWDEBUG_SAY(("Resetting device.")); - DX8_THREAD_ASSERT(); - if ((IsInitted) && (D3DDevice != NULL)) { - // Release all non-MANAGED stuff - Set_Vertex_Buffer (NULL); - Set_Index_Buffer (NULL, 0); - if (m_pCleanupHook) { - m_pCleanupHook->ReleaseResources(); - } - DynamicVBAccessClass::_Deinit(); - DynamicIBAccessClass::_Deinit(); - DX8TextureManagerClass::Release_Textures(); - - memset(Vertex_Shader_Constants,0,sizeof(Vector4)*MAX_VERTEX_SHADER_CONSTANTS); - memset(Pixel_Shader_Constants,0,sizeof(Vector4)*MAX_PIXEL_SHADER_CONSTANTS); - - HRESULT hr=_Get_D3D_Device8()->TestCooperativeLevel(); - if (hr != D3DERR_DEVICELOST ) - { DX8CALL_HRES(Reset(&_PresentParameters),hr) - if (hr != D3D_OK) - return false; //reset failed. - } - else - return false; //device is lost and can't be reset. - - if (reload_assets) - { - DX8TextureManagerClass::Recreate_Textures(); - if (m_pCleanupHook) { - m_pCleanupHook->ReAcquireResources(); - } - } - Invalidate_Cached_Render_States(); - Set_Default_Global_Render_States(); - WWDEBUG_SAY(("Device reset completed")); - return true; - } - WWDEBUG_SAY(("Device reset failed")); - return false; -} - -void DX8Wrapper::Release_Device(void) -{ - if (D3DDevice) { - - for (int a = 0; a < MAX_TEXTURE_STAGES; ++a) - { //release references to any textures that were used in last rendering call - DX8CALL(SetTexture(a, NULL)); - } - - DX8CALL(SetStreamSource(0, NULL, 0)); //release reference count on last rendered vertex buffer - DX8CALL(SetIndices(NULL, 0)); //release reference count on last rendered index buffer - - - /* - ** Release the current vertex and index buffers - */ - for (unsigned i = 0; i < MAX_VERTEX_STREAMS; ++i) - { - if (render_state.vertex_buffers[i]) render_state.vertex_buffers[i]->Release_Engine_Ref(); - REF_PTR_RELEASE(render_state.vertex_buffers[i]); - } - if (render_state.index_buffer) render_state.index_buffer->Release_Engine_Ref(); - REF_PTR_RELEASE(render_state.index_buffer); - - /* - ** Shutdown all subsystems - */ - Do_Onetime_Device_Dependent_Shutdowns(); - - /* - ** Release the device - */ - - D3DDevice->Release(); - D3DDevice = NULL; - } -} - void DX8Wrapper::Enumerate_Devices() { DX8_Assert(); diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 503c270675c..6e0b328e181 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -272,219 +272,6 @@ void MoveRectIntoOtherRect(const RECT& inner, const RECT& outer, int* x, int* y) #include "../../Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h" - - - -bool DX8Wrapper::Create_Device(void) -{ - WWASSERT(D3DDevice==NULL); // for now, once you've created a device, you're stuck with it! - - D3DCAPS8 caps; - if - ( - FAILED - ( - D3DInterface->GetDeviceCaps - ( - CurRenderDevice, - WW3D_DEVTYPE, - &caps - ) - ) - ) - { - return false; - } - - ::ZeroMemory(&CurrentAdapterIdentifier, sizeof(D3DADAPTER_IDENTIFIER8)); - - if - ( - FAILED - ( - D3DInterface->GetAdapterIdentifier - ( - CurRenderDevice, - D3DENUM_NO_WHQL_LEVEL, - &CurrentAdapterIdentifier - ) - ) - ) - { - return false; - } - -#ifndef _XBOX - - Vertex_Processing_Behavior=(caps.DevCaps&D3DDEVCAPS_HWTRANSFORMANDLIGHT) ? - D3DCREATE_MIXED_VERTEXPROCESSING : D3DCREATE_SOFTWARE_VERTEXPROCESSING; - - // enable this when all 'get' dx calls are removed KJM - /*if (caps.DevCaps&D3DDEVCAPS_PUREDEVICE) - { - Vertex_Processing_Behavior|=D3DCREATE_PUREDEVICE; - }*/ - -#else // XBOX - Vertex_Processing_Behavior=D3DCREATE_PUREDEVICE; -#endif // XBOX - -#ifdef CREATE_DX8_MULTI_THREADED - Vertex_Processing_Behavior|=D3DCREATE_MULTITHREADED; - _DX8SingleThreaded=false; -#else - _DX8SingleThreaded=true; -#endif - - if (DX8Wrapper_PreserveFPU) - Vertex_Processing_Behavior |= D3DCREATE_FPU_PRESERVE; - -#ifdef CREATE_DX8_FPU_PRESERVE - Vertex_Processing_Behavior|=D3DCREATE_FPU_PRESERVE; -#endif - - HRESULT hr=D3DInterface->CreateDevice - ( - CurRenderDevice, - WW3D_DEVTYPE, - _Hwnd, - Vertex_Processing_Behavior, - &_PresentParameters, - &D3DDevice - ); - - if (FAILED(hr)) - { - // The device selection may fail because the device lied that it supports 32 bit zbuffer with 16 bit - // display. This happens at least on Voodoo2. - - if ((_PresentParameters.BackBufferFormat==D3DFMT_R5G6B5 || - _PresentParameters.BackBufferFormat==D3DFMT_X1R5G5B5 || - _PresentParameters.BackBufferFormat==D3DFMT_A1R5G5B5) && - (_PresentParameters.AutoDepthStencilFormat==D3DFMT_D32 || - _PresentParameters.AutoDepthStencilFormat==D3DFMT_D24S8 || - _PresentParameters.AutoDepthStencilFormat==D3DFMT_D24X8)) - { - _PresentParameters.AutoDepthStencilFormat=D3DFMT_D16; - hr = D3DInterface->CreateDevice - ( - CurRenderDevice, - WW3D_DEVTYPE, - _Hwnd, - Vertex_Processing_Behavior, - &_PresentParameters, - &D3DDevice - ); - - if (FAILED(hr)) - { - return false; - } - } - else - { - return false; - } - } - - /* - ** Initialize all subsystems - */ - Do_Onetime_Device_Dependent_Inits(); - return true; -} - -bool DX8Wrapper::Reset_Device(bool reload_assets) -{ - WWDEBUG_SAY(("Resetting device.")); - DX8_THREAD_ASSERT(); - if ((IsInitted) && (D3DDevice != NULL)) { - // Release all non-MANAGED stuff - WW3D::_Invalidate_Textures(); - - for (unsigned i=0;iReleaseResources(); - } - DynamicVBAccessClass::_Deinit(); - DynamicIBAccessClass::_Deinit(); - DX8TextureManagerClass::Release_Textures(); - SHD_SHUTDOWN_SHADERS; - - // Reset frame count to reflect the flipping chain being reset by Reset() - FrameCount = 0; - - memset(Vertex_Shader_Constants,0,sizeof(Vector4)*MAX_VERTEX_SHADER_CONSTANTS); - memset(Pixel_Shader_Constants,0,sizeof(Vector4)*MAX_PIXEL_SHADER_CONSTANTS); - - HRESULT hr=_Get_D3D_Device8()->TestCooperativeLevel(); - if (hr != D3DERR_DEVICELOST ) - { DX8CALL_HRES(Reset(&_PresentParameters),hr) - if (hr != D3D_OK) - return false; //reset failed. - } - else - return false; //device is lost and can't be reset. - - if (reload_assets) - { - DX8TextureManagerClass::Recreate_Textures(); - if (m_pCleanupHook) { - m_pCleanupHook->ReAcquireResources(); - } - } - Invalidate_Cached_Render_States(); - Set_Default_Global_Render_States(); - SHD_INIT_SHADERS; - WWDEBUG_SAY(("Device reset completed")); - return true; - } - WWDEBUG_SAY(("Device reset failed")); - return false; -} - -void DX8Wrapper::Release_Device(void) -{ - if (D3DDevice) { - - for (int a=0;aRelease_Engine_Ref(); - REF_PTR_RELEASE(render_state.vertex_buffers[i]); - } - if (render_state.index_buffer) render_state.index_buffer->Release_Engine_Ref(); - REF_PTR_RELEASE(render_state.index_buffer); - - /* - ** Shutdown all subsystems - */ - Do_Onetime_Device_Dependent_Shutdowns(); - - /* - ** Release the device - */ - - D3DDevice->Release(); - D3DDevice=NULL; - } -} - void DX8Wrapper::Enumerate_Devices() { DX8_Assert(); From c8b0a679dfd4b05e2206bae08e40dbd2aba5660b Mon Sep 17 00:00:00 2001 From: ryan-de-boer Date: Fri, 1 Aug 2025 15:05:44 +0800 Subject: [PATCH 10/20] Merge Enumerate_Devices --- .../Common/Graphics/DX8/dx8wrapper_common.h | 182 +++++++++--------- .../Source/WWVegas/WW3D2/dx8caps.cpp | 30 +++ .../Libraries/Source/WWVegas/WW3D2/dx8caps.h | 6 +- .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 79 -------- .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 91 --------- 5 files changed, 126 insertions(+), 262 deletions(-) diff --git a/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h b/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h index 329cdb7e298..4a6726f98ba 100644 --- a/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h +++ b/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h @@ -463,96 +463,96 @@ void DX8Wrapper::Release_Device(void) } } -//void DX8Wrapper::Enumerate_Devices() -//{ -// DX8_Assert(); -// -// int adapter_count = D3DInterface->GetAdapterCount(); -// for (int adapter_index = 0; adapter_index < adapter_count; adapter_index++) { -// -// D3DADAPTER_IDENTIFIER8 id; -// ::ZeroMemory(&id, sizeof(D3DADAPTER_IDENTIFIER8)); -// HRESULT res = D3DInterface->GetAdapterIdentifier(adapter_index, D3DENUM_NO_WHQL_LEVEL, &id); -// -// if (res == D3D_OK) { -// -// /* -// ** Set up the render device description -// ** TODO: Fill in more fields of the render device description? (need some lookup tables) -// */ -// RenderDeviceDescClass desc; -// desc.set_device_name(id.Description); -// desc.set_driver_name(id.Driver); -// -// char buf[64]; -// sprintf(buf, "%d.%d.%d.%d", //"%04x.%04x.%04x.%04x", -// HIWORD(id.DriverVersion.HighPart), -// LOWORD(id.DriverVersion.HighPart), -// HIWORD(id.DriverVersion.LowPart), -// LOWORD(id.DriverVersion.LowPart)); -// -// desc.set_driver_version(buf); -// -// D3DInterface->GetDeviceCaps(adapter_index, WW3D_DEVTYPE, &desc.Caps); -// D3DInterface->GetAdapterIdentifier(adapter_index, D3DENUM_NO_WHQL_LEVEL, &desc.AdapterIdentifier); -// -// DX8Caps dx8caps(D3DInterface, desc.Caps, WW3D_FORMAT_UNKNOWN, desc.AdapterIdentifier); -// -// /* -// ** Enumerate the resolutions -// */ -// desc.reset_resolution_list(); -// int mode_count = D3DInterface->GetAdapterModeCount(adapter_index); -// for (int mode_index = 0; mode_index < mode_count; mode_index++) { -// D3DDISPLAYMODE d3dmode; -// ::ZeroMemory(&d3dmode, sizeof(D3DDISPLAYMODE)); -// HRESULT res = D3DInterface->EnumAdapterModes(adapter_index, mode_index, &d3dmode); -// -// if (res == D3D_OK) { -// int bits = 0; -// switch (d3dmode.Format) -// { -// case D3DFMT_R8G8B8: -// case D3DFMT_A8R8G8B8: -// case D3DFMT_X8R8G8B8: bits = 32; break; -// -// case D3DFMT_R5G6B5: -// case D3DFMT_X1R5G5B5: bits = 16; break; -// } -// -// // Some cards fail in certain modes, DX8Caps keeps list of those. -// if (!dx8caps.Is_Valid_Display_Format(d3dmode.Width, d3dmode.Height, D3DFormat_To_WW3DFormat(d3dmode.Format))) { -// bits = 0; -// } -// -// /* -// ** If we recognize the format, add it to the list -// ** TODO: should we handle more formats? will any cards report more than 24 or 16 bit? -// */ -// if (bits != 0) { -// desc.add_resolution(d3dmode.Width, d3dmode.Height, bits); -// } -// } -// } -// -// // IML: If the device has one or more valid resolutions add it to the device list. -// // NOTE: Testing has shown that there are drivers with zero resolutions. -// if (desc.Enumerate_Resolutions().Count() > 0) { -// -// /* -// ** Set up the device name -// */ -// StringClass device_name(id.Description, true); -// _RenderDeviceNameTable.Add(device_name); -// _RenderDeviceShortNameTable.Add(device_name); // for now, just add the same name to the "pretty name table" -// -// /* -// ** Add the render device to our table -// */ -// _RenderDeviceDescriptionTable.Add(desc); -// } -// } -// } -//} +void DX8Wrapper::Enumerate_Devices() +{ + DX8_Assert(); + + int adapter_count = D3DInterface->GetAdapterCount(); + for (int adapter_index = 0; adapter_index < adapter_count; adapter_index++) { + + D3DADAPTER_IDENTIFIER8 id; + ::ZeroMemory(&id, sizeof(D3DADAPTER_IDENTIFIER8)); + HRESULT res = D3DInterface->GetAdapterIdentifier(adapter_index, D3DENUM_NO_WHQL_LEVEL, &id); + + if (res == D3D_OK) { + + /* + ** Set up the render device description + ** TODO: Fill in more fields of the render device description? (need some lookup tables) + */ + RenderDeviceDescClass desc; + desc.set_device_name(id.Description); + desc.set_driver_name(id.Driver); + + char buf[64]; + sprintf(buf, "%d.%d.%d.%d", //"%04x.%04x.%04x.%04x", + HIWORD(id.DriverVersion.HighPart), + LOWORD(id.DriverVersion.HighPart), + HIWORD(id.DriverVersion.LowPart), + LOWORD(id.DriverVersion.LowPart)); + + desc.set_driver_version(buf); + + D3DInterface->GetDeviceCaps(adapter_index, WW3D_DEVTYPE, &desc.Caps); + D3DInterface->GetAdapterIdentifier(adapter_index, D3DENUM_NO_WHQL_LEVEL, &desc.AdapterIdentifier); + + DX8Caps dx8caps(D3DInterface, desc.Caps, WW3D_FORMAT_UNKNOWN, desc.AdapterIdentifier); + + /* + ** Enumerate the resolutions + */ + desc.reset_resolution_list(); + int mode_count = D3DInterface->GetAdapterModeCount(adapter_index); + for (int mode_index = 0; mode_index < mode_count; mode_index++) { + D3DDISPLAYMODE d3dmode; + ::ZeroMemory(&d3dmode, sizeof(D3DDISPLAYMODE)); + HRESULT res = D3DInterface->EnumAdapterModes(adapter_index, mode_index, &d3dmode); + + if (res == D3D_OK) { + int bits = 0; + switch (d3dmode.Format) + { + case D3DFMT_R8G8B8: + case D3DFMT_A8R8G8B8: + case D3DFMT_X8R8G8B8: bits = 32; break; + + case D3DFMT_R5G6B5: + case D3DFMT_X1R5G5B5: bits = 16; break; + } + + // Some cards fail in certain modes, DX8Caps keeps list of those. + if (!dx8caps.Is_Valid_Display_Format(d3dmode.Width, d3dmode.Height, D3DFormat_To_WW3DFormat(d3dmode.Format))) { + bits = 0; + } + + /* + ** If we recognize the format, add it to the list + ** TODO: should we handle more formats? will any cards report more than 24 or 16 bit? + */ + if (bits != 0) { + desc.add_resolution(d3dmode.Width, d3dmode.Height, bits); + } + } + } + + // IML: If the device has one or more valid resolutions add it to the device list. + // NOTE: Testing has shown that there are drivers with zero resolutions. + if (desc.Enumerate_Resolutions().Count() > 0) { + + /* + ** Set up the device name + */ + StringClass device_name(id.Description, true); + _RenderDeviceNameTable.Add(device_name); + _RenderDeviceShortNameTable.Add(device_name); // for now, just add the same name to the "pretty name table" + + /* + ** Add the render device to our table + */ + _RenderDeviceDescriptionTable.Add(desc); + } + } + } +} diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8caps.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8caps.cpp index f8c67f1906a..c83542d6be8 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8caps.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8caps.cpp @@ -481,6 +481,27 @@ DX8Caps::DX8Caps( Compute_Caps(display_format, adapter_id); } +DX8Caps::DX8Caps( + IDirect3D8* direct3d, + const D3DCAPS8& caps, + WW3DFormat display_format, + const D3DADAPTER_IDENTIFIER8& adapter_id) + : + Direct3D(direct3d), + Caps(caps), + MaxDisplayWidth(0), + MaxDisplayHeight(0) +{ + if ((Caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == D3DDEVCAPS_HWTRANSFORMANDLIGHT) { + SupportTnL = true; + } + else { + SupportTnL = false; + } + + Compute_Caps(display_format, adapter_id); +} + //Don't really need this but I added this function to free static variables so //they don't show up in our memory manager as a leak. -MW 7-22-03 void DX8Caps::Shutdown(void) @@ -680,6 +701,15 @@ void DX8Caps::Check_Shader_Support(const D3DCAPS8& caps) PixelShaderVersion=caps.PixelShaderVersion; } +bool DX8Caps::Is_Valid_Display_Format(int width, int height, WW3DFormat format) +{ + // If nothing limits the maximum resolution, accept any resolution + if (MaxDisplayWidth == 0 && MaxDisplayHeight == 0) return true; + + if (width > MaxDisplayWidth || height > MaxDisplayHeight) return false; + return true; +} + // ---------------------------------------------------------------------------- // // Implement some vendor-specific hacks to fix certain driver bugs that can't be diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8caps.h b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8caps.h index 28c1b983b1f..e3206918075 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8caps.h +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8caps.h @@ -206,7 +206,7 @@ class DX8Caps DEVICE_INTEL_815 }; - + DX8Caps(IDirect3D8* direct3d, const D3DCAPS8& caps, WW3DFormat display_format, const D3DADAPTER_IDENTIFIER8& adapter_id); DX8Caps(IDirect3D8* direct3d, IDirect3DDevice8* D3DDevice,WW3DFormat display_format, const D3DADAPTER_IDENTIFIER8& adapter_id); static void Shutdown(void); @@ -220,6 +220,8 @@ class DX8Caps bool Support_Dot3() const { return SupportDot3; } int Get_Max_Textures_Per_Pass() const { return MaxTexturesPerPass; } + bool Is_Valid_Display_Format(int width, int height, WW3DFormat format); + // ------------------------------------------------------------------------- // // Vertex shader support. Version number is split in major and minor, such that 1.0 would @@ -266,6 +268,8 @@ class DX8Caps int MaxDisplayWidth; int MaxDisplayHeight; + D3DCAPS8 Caps; + D3DCAPS8 hwVPCaps; D3DCAPS8 swVPCaps; bool SupportTnL; diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 8ae8fbc9c6a..514ac500830 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -295,85 +295,6 @@ void MoveRectIntoOtherRect(const RECT& inner, const RECT& outer, int* x, int* y) #include "../../Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h" - - -void DX8Wrapper::Enumerate_Devices() -{ - DX8_Assert(); - - int adapter_count = D3DInterface->GetAdapterCount(); - for (int adapter_index=0; adapter_indexGetAdapterIdentifier(adapter_index,D3DENUM_NO_WHQL_LEVEL,&id); - - if (res == D3D_OK) { - - /* - ** Set up the device name - */ - StringClass device_name = id.Description; - _RenderDeviceNameTable.Add(device_name); - _RenderDeviceShortNameTable.Add(device_name); // for now, just add the same name to the "pretty name table" - - /* - ** Set up the render device description - ** TODO: Fill in more fields of the render device description? (need some lookup tables) - */ - RenderDeviceDescClass desc; - desc.set_device_name(id.Description); - desc.set_driver_name(id.Driver); - - char buf[64]; - sprintf(buf,"%d.%d.%d.%d", //"%04x.%04x.%04x.%04x", - HIWORD(id.DriverVersion.HighPart), - LOWORD(id.DriverVersion.HighPart), - HIWORD(id.DriverVersion.LowPart), - LOWORD(id.DriverVersion.LowPart)); - - desc.set_driver_version(buf); - - /* - ** Enumerate the resolutions - */ - desc.reset_resolution_list(); - int mode_count = D3DInterface->GetAdapterModeCount(adapter_index); - for (int mode_index=0; mode_indexEnumAdapterModes(adapter_index,mode_index,&d3dmode); - - if (res == D3D_OK) { - int bits = 0; - switch (d3dmode.Format) - { - case D3DFMT_R8G8B8: - case D3DFMT_A8R8G8B8: - case D3DFMT_X8R8G8B8: bits = 32; break; - - case D3DFMT_R5G6B5: - case D3DFMT_X1R5G5B5: bits = 16; break; - } - - /* - ** If we recognize the format, add it to the list - ** TODO: should we handle more formats? will any cards report more than 24 or 16 bit? - */ - if (bits != 0) { - desc.add_resolution(d3dmode.Width,d3dmode.Height,bits); - } - } - } - - /* - ** Add the render device to our table - */ - _RenderDeviceDescriptionTable.Add(desc); - } - } -} - bool DX8Wrapper::Set_Any_Render_Device(void) { // Try windowed first diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 6e0b328e181..5dd00ab1eef 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -272,97 +272,6 @@ void MoveRectIntoOtherRect(const RECT& inner, const RECT& outer, int* x, int* y) #include "../../Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h" -void DX8Wrapper::Enumerate_Devices() -{ - DX8_Assert(); - - int adapter_count = D3DInterface->GetAdapterCount(); - for (int adapter_index=0; adapter_indexGetAdapterIdentifier(adapter_index,D3DENUM_NO_WHQL_LEVEL,&id); - - if (res == D3D_OK) { - - /* - ** Set up the render device description - ** TODO: Fill in more fields of the render device description? (need some lookup tables) - */ - RenderDeviceDescClass desc; - desc.set_device_name(id.Description); - desc.set_driver_name(id.Driver); - - char buf[64]; - sprintf(buf,"%d.%d.%d.%d", //"%04x.%04x.%04x.%04x", - HIWORD(id.DriverVersion.HighPart), - LOWORD(id.DriverVersion.HighPart), - HIWORD(id.DriverVersion.LowPart), - LOWORD(id.DriverVersion.LowPart)); - - desc.set_driver_version(buf); - - D3DInterface->GetDeviceCaps(adapter_index,WW3D_DEVTYPE,&desc.Caps); - D3DInterface->GetAdapterIdentifier(adapter_index,D3DENUM_NO_WHQL_LEVEL,&desc.AdapterIdentifier); - - DX8Caps dx8caps(D3DInterface,desc.Caps,WW3D_FORMAT_UNKNOWN,desc.AdapterIdentifier); - - /* - ** Enumerate the resolutions - */ - desc.reset_resolution_list(); - int mode_count = D3DInterface->GetAdapterModeCount(adapter_index); - for (int mode_index=0; mode_indexEnumAdapterModes(adapter_index,mode_index,&d3dmode); - - if (res == D3D_OK) { - int bits = 0; - switch (d3dmode.Format) - { - case D3DFMT_R8G8B8: - case D3DFMT_A8R8G8B8: - case D3DFMT_X8R8G8B8: bits = 32; break; - - case D3DFMT_R5G6B5: - case D3DFMT_X1R5G5B5: bits = 16; break; - } - - // Some cards fail in certain modes, DX8Caps keeps list of those. - if (!dx8caps.Is_Valid_Display_Format(d3dmode.Width,d3dmode.Height,D3DFormat_To_WW3DFormat(d3dmode.Format))) { - bits=0; - } - - /* - ** If we recognize the format, add it to the list - ** TODO: should we handle more formats? will any cards report more than 24 or 16 bit? - */ - if (bits != 0) { - desc.add_resolution(d3dmode.Width,d3dmode.Height,bits); - } - } - } - - // IML: If the device has one or more valid resolutions add it to the device list. - // NOTE: Testing has shown that there are drivers with zero resolutions. - if (desc.Enumerate_Resolutions().Count() > 0) { - - /* - ** Set up the device name - */ - StringClass device_name(id.Description,true); - _RenderDeviceNameTable.Add(device_name); - _RenderDeviceShortNameTable.Add(device_name); // for now, just add the same name to the "pretty name table" - - /* - ** Add the render device to our table - */ - _RenderDeviceDescriptionTable.Add(desc); - } - } - } -} bool DX8Wrapper::Set_Any_Render_Device(void) { From b346569b24cda5209fde155894b1ab95034e1c15 Mon Sep 17 00:00:00 2001 From: ryan-de-boer Date: Fri, 1 Aug 2025 17:03:00 +0800 Subject: [PATCH 11/20] Unified Set_Any_Render_Device to Set_Light --- .../Common/Graphics/DX8/dx8wrapper_common.h | 2274 +++++++++++ .../Source/Common/System/MemoryInit.cpp | 1 + .../W3DDevice/GameClient/W3DAssetManager.cpp | 2 +- .../W3DDevice/GameClient/W3DDisplay.cpp | 1 - .../Source/W3DDevice/GameClient/W3DShroud.cpp | 7 +- .../W3DDevice/GameClient/W3DVideoBuffer.cpp | 3 +- .../W3DDevice/GameClient/Water/W3DWater.cpp | 2 +- .../Source/WWVegas/WW3D2/assetmgr.cpp | 52 +- .../Libraries/Source/WWVegas/WW3D2/assetmgr.h | 4 +- .../Source/WWVegas/WW3D2/dx8texman.h | 37 + .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 2305 ++--------- .../Source/WWVegas/WW3D2/dx8wrapper.h | 40 +- .../Source/WWVegas/WW3D2/texproject.cpp | 48 +- .../Source/WWVegas/WW3D2/texproject.h | 7 +- .../Source/WWVegas/WW3D2/texture.cpp | 2164 ++++++++--- .../Libraries/Source/WWVegas/WW3D2/texture.h | 576 ++- .../Source/WWVegas/WW3D2/textureloader.cpp | 3379 ++++++++++++----- .../Source/WWVegas/WW3D2/textureloader.h | 334 +- .../Source/WWVegas/WW3D2/texturethumbnail.cpp | 348 +- .../Source/WWVegas/WW3D2/texturethumbnail.h | 81 +- .../Tools/WorldBuilder/src/ObjectPreview.cpp | 2 +- .../Tools/WorldBuilder/src/WorldBuilder.cpp | 1 - .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 2259 ----------- 23 files changed, 7798 insertions(+), 6129 deletions(-) diff --git a/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h b/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h index 4a6726f98ba..fa6289e3a8f 100644 --- a/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h +++ b/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h @@ -556,3 +556,2277 @@ void DX8Wrapper::Enumerate_Devices() } +bool DX8Wrapper::Set_Any_Render_Device(void) +{ + // Then fullscreen + int dev_number = 0; + for (; dev_number < _RenderDeviceNameTable.Count(); dev_number++) { + if (Set_Render_Device(dev_number, -1, -1, -1, 0, false)) { + return true; + } + } + + // Try windowed first + for (dev_number = 0; dev_number < _RenderDeviceNameTable.Count(); dev_number++) { + if (Set_Render_Device(dev_number, -1, -1, -1, 1, false)) { + return true; + } + } + + return false; +} + +bool DX8Wrapper::Set_Render_Device +( + const char* dev_name, + int width, + int height, + int bits, + int windowed, + bool resize_window +) +{ + for (int dev_number = 0; dev_number < _RenderDeviceNameTable.Count(); dev_number++) { + if (strcmp(dev_name, _RenderDeviceNameTable[dev_number]) == 0) { + return Set_Render_Device(dev_number, width, height, bits, windowed, resize_window); + } + + if (strcmp(dev_name, _RenderDeviceShortNameTable[dev_number]) == 0) { + return Set_Render_Device(dev_number, width, height, bits, windowed, resize_window); + } + } + return false; +} + +void DX8Wrapper::Get_Format_Name(unsigned int format, StringClass* tex_format) +{ + *tex_format = "Unknown"; + switch (format) { + case D3DFMT_A8R8G8B8: *tex_format = "D3DFMT_A8R8G8B8"; break; + case D3DFMT_R8G8B8: *tex_format = "D3DFMT_R8G8B8"; break; + case D3DFMT_A4R4G4B4: *tex_format = "D3DFMT_A4R4G4B4"; break; + case D3DFMT_A1R5G5B5: *tex_format = "D3DFMT_A1R5G5B5"; break; + case D3DFMT_R5G6B5: *tex_format = "D3DFMT_R5G6B5"; break; + case D3DFMT_L8: *tex_format = "D3DFMT_L8"; break; + case D3DFMT_A8: *tex_format = "D3DFMT_A8"; break; + case D3DFMT_P8: *tex_format = "D3DFMT_P8"; break; + case D3DFMT_X8R8G8B8: *tex_format = "D3DFMT_X8R8G8B8"; break; + case D3DFMT_X1R5G5B5: *tex_format = "D3DFMT_X1R5G5B5"; break; + case D3DFMT_R3G3B2: *tex_format = "D3DFMT_R3G3B2"; break; + case D3DFMT_A8R3G3B2: *tex_format = "D3DFMT_A8R3G3B2"; break; + case D3DFMT_X4R4G4B4: *tex_format = "D3DFMT_X4R4G4B4"; break; + case D3DFMT_A8P8: *tex_format = "D3DFMT_A8P8"; break; + case D3DFMT_A8L8: *tex_format = "D3DFMT_A8L8"; break; + case D3DFMT_A4L4: *tex_format = "D3DFMT_A4L4"; break; + case D3DFMT_V8U8: *tex_format = "D3DFMT_V8U8"; break; + case D3DFMT_L6V5U5: *tex_format = "D3DFMT_L6V5U5"; break; + case D3DFMT_X8L8V8U8: *tex_format = "D3DFMT_X8L8V8U8"; break; + case D3DFMT_Q8W8V8U8: *tex_format = "D3DFMT_Q8W8V8U8"; break; + case D3DFMT_V16U16: *tex_format = "D3DFMT_V16U16"; break; + case D3DFMT_W11V11U10: *tex_format = "D3DFMT_W11V11U10"; break; + case D3DFMT_UYVY: *tex_format = "D3DFMT_UYVY"; break; + case D3DFMT_YUY2: *tex_format = "D3DFMT_YUY2"; break; + case D3DFMT_DXT1: *tex_format = "D3DFMT_DXT1"; break; + case D3DFMT_DXT2: *tex_format = "D3DFMT_DXT2"; break; + case D3DFMT_DXT3: *tex_format = "D3DFMT_DXT3"; break; + case D3DFMT_DXT4: *tex_format = "D3DFMT_DXT4"; break; + case D3DFMT_DXT5: *tex_format = "D3DFMT_DXT5"; break; + case D3DFMT_D16_LOCKABLE: *tex_format = "D3DFMT_D16_LOCKABLE"; break; + case D3DFMT_D32: *tex_format = "D3DFMT_D32"; break; + case D3DFMT_D15S1: *tex_format = "D3DFMT_D15S1"; break; + case D3DFMT_D24S8: *tex_format = "D3DFMT_D24S8"; break; + case D3DFMT_D16: *tex_format = "D3DFMT_D16"; break; + case D3DFMT_D24X8: *tex_format = "D3DFMT_D24X8"; break; + case D3DFMT_D24X4S4: *tex_format = "D3DFMT_D24X4S4"; break; + default: break; + } +} + +void DX8Wrapper::Resize_And_Position_Window() +{ + // Get the current dimensions of the 'render area' of the window + RECT rect = { 0 }; + ::GetClientRect(_Hwnd, &rect); + + // Is the window the correct size for this resolution? + if ((rect.right - rect.left) != ResolutionWidth || + (rect.bottom - rect.top) != ResolutionHeight) { + + // Calculate what the main window's bounding rectangle should be to + // accommodate this resolution + rect.left = 0; + rect.top = 0; + rect.right = ResolutionWidth; + rect.bottom = ResolutionHeight; + DWORD dwstyle = ::GetWindowLong(_Hwnd, GWL_STYLE); + AdjustWindowRect(&rect, dwstyle, FALSE); + int width = rect.right - rect.left; + int height = rect.bottom - rect.top; + + // Resize the window to fit this resolution + if (!IsWindowed) + { + ::SetWindowPos(_Hwnd, HWND_TOPMOST, 0, 0, width, height, SWP_NOSIZE | SWP_NOMOVE); + + DEBUG_LOG(("Window resized to w:%d h:%d", width, height)); + } + else + { + // TheSuperHackers @feature helmutbuhler 14/04/2025 + // Center the window in the workarea of the monitor it is on. + MONITORINFO mi = { sizeof(MONITORINFO) }; + GetMonitorInfo(MonitorFromWindow(_Hwnd, MONITOR_DEFAULTTOPRIMARY), &mi); + int left = (mi.rcWork.left + mi.rcWork.right - width) / 2; + int top = (mi.rcWork.top + mi.rcWork.bottom - height) / 2; + + // TheSuperHackers @feature helmutbuhler 14/04/2025 + // Move the window to try fit it into the monitor area, if one of its dimensions is larger than the work area. + // Otherwise align the window to the top left edges, if it is even larger than the monitor area. + RECT rectClient; + rectClient.left = left - rect.left; + rectClient.top = top - rect.top; + rectClient.right = rectClient.left + ResolutionWidth; + rectClient.bottom = rectClient.top + ResolutionHeight; + MoveRectIntoOtherRect(rectClient, mi.rcMonitor, &left, &top); + + ::SetWindowPos(_Hwnd, NULL, left, top, width, height, SWP_NOZORDER); + + DEBUG_LOG(("Window positioned to x:%d y:%d, resized to w:%d h:%d", left, top, width, height)); + } + } +} + + + +bool DX8Wrapper::Set_Render_Device(int dev, int width, int height, int bits, int windowed, + bool resize_window, bool reset_device, bool restore_assets) +{ + WWASSERT(IsInitted); + WWASSERT(dev >= -1); + WWASSERT(dev < _RenderDeviceNameTable.Count()); + + /* + ** If user has never selected a render device, start out with device 0 + */ + if ((CurRenderDevice == -1) && (dev == -1)) { + CurRenderDevice = 0; + } + else if (dev != -1) { + CurRenderDevice = dev; + } + + /* + ** If user doesn't want to change res, set the res variables to match the + ** current resolution + */ + if (width != -1) ResolutionWidth = width; + if (height != -1) ResolutionHeight = height; + + // Initialize Render2DClass Screen Resolution + Render2DClass::Set_Screen_Resolution(RectClass(0, 0, ResolutionWidth, ResolutionHeight)); + + if (bits != -1) BitDepth = bits; + if (windowed != -1) IsWindowed = (windowed != 0); + DX8Wrapper_IsWindowed = IsWindowed; + + WWDEBUG_SAY(("Attempting Set_Render_Device: name: %s (%s:%s), width: %d, height: %d, windowed: %d", + _RenderDeviceNameTable[CurRenderDevice].str(), _RenderDeviceDescriptionTable[CurRenderDevice].Get_Driver_Name(), + _RenderDeviceDescriptionTable[CurRenderDevice].Get_Driver_Version(), ResolutionWidth, ResolutionHeight, (IsWindowed ? 1 : 0))); + +#ifdef _WINDOWS + // PWG 4/13/2000 - changed so that if you say to resize the window it resizes + // regardless of whether its windowed or not as OpenGL resizes its self around + // the caption and edges of the window type you provide, so its important to + // push the client area to be the size you really want. + // if ( resize_window && windowed ) { + if (resize_window) { + Resize_And_Position_Window(); + } +#endif + //must be either resetting existing device or creating a new one. + WWASSERT(reset_device || D3DDevice == NULL); + + /* + ** Initialize values for D3DPRESENT_PARAMETERS members. + */ + ::ZeroMemory(&_PresentParameters, sizeof(D3DPRESENT_PARAMETERS)); + + _PresentParameters.BackBufferWidth = ResolutionWidth; + _PresentParameters.BackBufferHeight = ResolutionHeight; + _PresentParameters.BackBufferCount = IsWindowed ? 1 : 2; + + _PresentParameters.MultiSampleType = D3DMULTISAMPLE_NONE; + //I changed this to discard all the time (even when full-screen) since that the most efficient. 07-16-03 MW: + _PresentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;//IsWindowed ? D3DSWAPEFFECT_DISCARD : D3DSWAPEFFECT_FLIP; // Shouldn't this be D3DSWAPEFFECT_FLIP? + _PresentParameters.hDeviceWindow = _Hwnd; + _PresentParameters.Windowed = IsWindowed; + + _PresentParameters.EnableAutoDepthStencil = TRUE; // Driver will attempt to match Z-buffer depth + _PresentParameters.Flags = 0; // We're not going to lock the backbuffer + + _PresentParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; + _PresentParameters.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT; + + /* + ** Set up the buffer formats. Several issues here: + ** - if in windowed mode, the backbuffer must use the current display format. + ** - the depth buffer must use + */ + if (IsWindowed) { + + D3DDISPLAYMODE desktop_mode; + ::ZeroMemory(&desktop_mode, sizeof(D3DDISPLAYMODE)); + D3DInterface->GetAdapterDisplayMode(CurRenderDevice, &desktop_mode); + + DisplayFormat = _PresentParameters.BackBufferFormat = desktop_mode.Format; + + // In windowed mode, define the bitdepth from desktop mode (as it can't be changed) + switch (_PresentParameters.BackBufferFormat) { + case D3DFMT_X8R8G8B8: + case D3DFMT_A8R8G8B8: + case D3DFMT_R8G8B8: BitDepth = 32; break; + case D3DFMT_A4R4G4B4: + case D3DFMT_A1R5G5B5: + case D3DFMT_R5G6B5: BitDepth = 16; break; + case D3DFMT_L8: + case D3DFMT_A8: + case D3DFMT_P8: BitDepth = 8; break; + default: + // Unknown backbuffer format probably means the device can't do windowed + return false; + } + + if (BitDepth == 32 && D3DInterface->CheckDeviceType(0, D3DDEVTYPE_HAL, desktop_mode.Format, D3DFMT_A8R8G8B8, TRUE) == D3D_OK) + { //promote 32-bit modes to include destination alpha + _PresentParameters.BackBufferFormat = D3DFMT_A8R8G8B8; + } + + /* + ** Find a appropriate Z buffer + */ + if (!Find_Z_Mode(DisplayFormat, _PresentParameters.BackBufferFormat, &_PresentParameters.AutoDepthStencilFormat)) + { + // If opening 32 bit mode failed, try 16 bit, even if the desktop happens to be 32 bit + if (BitDepth == 32) { + BitDepth = 16; + _PresentParameters.BackBufferFormat = D3DFMT_R5G6B5; + if (!Find_Z_Mode(_PresentParameters.BackBufferFormat, _PresentParameters.BackBufferFormat, &_PresentParameters.AutoDepthStencilFormat)) { + _PresentParameters.AutoDepthStencilFormat = D3DFMT_UNKNOWN; + } + } + else { + _PresentParameters.AutoDepthStencilFormat = D3DFMT_UNKNOWN; + } + } + + } + else { + + /* + ** Try to find a mode that matches the user's desired bit-depth. + */ + Find_Color_And_Z_Mode(ResolutionWidth, ResolutionHeight, BitDepth, &DisplayFormat, + &_PresentParameters.BackBufferFormat, &_PresentParameters.AutoDepthStencilFormat); + } + + /* + ** Time to actually create the device. + */ + if (_PresentParameters.AutoDepthStencilFormat == D3DFMT_UNKNOWN) { + if (BitDepth == 32) { + _PresentParameters.AutoDepthStencilFormat = D3DFMT_D32; + } + else { + _PresentParameters.AutoDepthStencilFormat = D3DFMT_D16; + } + } + + StringClass displayFormat; + StringClass backbufferFormat; + + Get_Format_Name(DisplayFormat, &displayFormat); + Get_Format_Name(_PresentParameters.BackBufferFormat, &backbufferFormat); + + WWDEBUG_SAY(("Using Display/BackBuffer Formats: %s/%s", displayFormat.str(), backbufferFormat.str())); + + bool ret; + + if (reset_device) + { + WWDEBUG_SAY(("DX8Wrapper::Set_Render_Device is resetting the device.")); + ret = Reset_Device(restore_assets); //reset device without restoring data - we're likely switching out of the app. + } + else + ret = Create_Device(); + + WWDEBUG_SAY(("Reset/Create_Device done, reset_device=%d, restore_assets=%d", reset_device, restore_assets)); + + return ret; +} + +bool DX8Wrapper::Set_Next_Render_Device(void) +{ + int new_dev = (CurRenderDevice + 1) % _RenderDeviceNameTable.Count(); + return Set_Render_Device(new_dev); +} + +bool DX8Wrapper::Toggle_Windowed(void) +{ +#ifdef WW3D_DX8 + // State OK? + assert(IsInitted); + if (IsInitted) { + + // Get information about the current render device's resolutions + const RenderDeviceDescClass& render_device = Get_Render_Device_Desc(); + const DynamicVectorClass& resolutions = render_device.Enumerate_Resolutions(); + + // Loop through all the resolutions supported by the current device. + // If we aren't currently running under one of these resolutions, + // then we should probably to the closest resolution before + // toggling the windowed state. + int curr_res = -1; + for (int res = 0; + (res < resolutions.Count()) && (curr_res == -1); + res++) { + + // Is this the resolution we are looking for? + if ((resolutions[res].Width == ResolutionWidth) && + (resolutions[res].Height == ResolutionHeight) && + (resolutions[res].BitDepth == BitDepth)) { + curr_res = res; + } + } + + if (curr_res == -1) { + + // We don't match any of the standard resolutions, + // so set the first resolution and toggle the windowed state. + return Set_Device_Resolution(resolutions[0].Width, + resolutions[0].Height, + resolutions[0].BitDepth, + !IsWindowed, true); + } + else { + + // Toggle the windowed state + return Set_Device_Resolution(-1, -1, -1, !IsWindowed, true); + } + } +#endif //WW3D_DX8 + + return false; +} + +void DX8Wrapper::Set_Swap_Interval(int swap) +{ + switch (swap) { + case 0: _PresentParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; break; + case 1: _PresentParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_ONE; break; + case 2: _PresentParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_TWO; break; + case 3: _PresentParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_THREE; break; + default: _PresentParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_ONE; break; + } + + WWDEBUG_SAY(("DX8Wrapper::Set_Swap_Interval is resetting the device.")); + Reset_Device(); +} + +int DX8Wrapper::Get_Swap_Interval(void) +{ + return _PresentParameters.FullScreen_PresentationInterval; +} + +bool DX8Wrapper::Has_Stencil(void) +{ + bool has_stencil = (_PresentParameters.AutoDepthStencilFormat == D3DFMT_D24S8 || + _PresentParameters.AutoDepthStencilFormat == D3DFMT_D24X4S4); + return has_stencil; +} + +int DX8Wrapper::Get_Render_Device_Count(void) +{ + return _RenderDeviceNameTable.Count(); + +} +int DX8Wrapper::Get_Render_Device(void) +{ + assert(IsInitted); + return CurRenderDevice; +} + +const RenderDeviceDescClass& DX8Wrapper::Get_Render_Device_Desc(int deviceidx) +{ + WWASSERT(IsInitted); + + if ((deviceidx == -1) && (CurRenderDevice == -1)) { + CurRenderDevice = 0; + } + + // if the device index is -1 then we want the current device + if (deviceidx == -1) { + WWASSERT(CurRenderDevice >= 0); + WWASSERT(CurRenderDevice < _RenderDeviceNameTable.Count()); + return _RenderDeviceDescriptionTable[CurRenderDevice]; + } + + // We can only ask for multiple device information if the devices + // have been detected. + WWASSERT(deviceidx >= 0); + WWASSERT(deviceidx < _RenderDeviceNameTable.Count()); + return _RenderDeviceDescriptionTable[deviceidx]; +} + +const char* DX8Wrapper::Get_Render_Device_Name(int device_index) +{ + device_index = device_index % _RenderDeviceShortNameTable.Count(); + return _RenderDeviceShortNameTable[device_index]; +} + +bool DX8Wrapper::Set_Device_Resolution(int width, int height, int bits, int windowed, bool resize_window) +{ + if (D3DDevice != NULL) { + + if (width != -1) { + _PresentParameters.BackBufferWidth = ResolutionWidth = width; + } + if (height != -1) { + _PresentParameters.BackBufferHeight = ResolutionHeight = height; + } + if (resize_window) + { + Resize_And_Position_Window(); + } +#pragma message("TODO: support changing windowed status and changing the bit depth") + WWDEBUG_SAY(("DX8Wrapper::Set_Device_Resolution is resetting the device.")); + return Reset_Device(); + } + else { + return false; + } +} + +void DX8Wrapper::Get_Device_Resolution(int& set_w, int& set_h, int& set_bits, bool& set_windowed) +{ + WWASSERT(IsInitted); + + set_w = ResolutionWidth; + set_h = ResolutionHeight; + set_bits = BitDepth; + set_windowed = IsWindowed; + + return; +} + +void DX8Wrapper::Get_Render_Target_Resolution(int& set_w, int& set_h, int& set_bits, bool& set_windowed) +{ + WWASSERT(IsInitted); + + if (CurrentRenderTarget != NULL) { + D3DSURFACE_DESC info; + CurrentRenderTarget->GetDesc(&info); + + set_w = info.Width; + set_h = info.Height; + set_bits = BitDepth; // should we get the actual bit depth of the target? + set_windowed = IsWindowed; // this doesn't really make sense for render targets (shouldn't matter)... + + } + else { + Get_Device_Resolution(set_w, set_h, set_bits, set_windowed); + } + + return; +} + +bool DX8Wrapper::Registry_Save_Render_Device(const char* sub_key) +{ + int width, height, depth; + bool windowed; + Get_Device_Resolution(width, height, depth, windowed); + return Registry_Save_Render_Device(sub_key, CurRenderDevice, ResolutionWidth, ResolutionHeight, BitDepth, IsWindowed, TextureBitDepth); +} + +bool DX8Wrapper::Registry_Save_Render_Device(const char* sub_key, int device, int width, int height, int depth, bool windowed, int texture_depth) +{ + RegistryClass* registry = W3DNEW RegistryClass(sub_key); + WWASSERT(registry); + + if (!registry->Is_Valid()) { + delete registry; + WWDEBUG_SAY(("Error getting Registry")); + return false; + } + + registry->Set_String(VALUE_NAME_RENDER_DEVICE_NAME, + _RenderDeviceShortNameTable[device]); + registry->Set_Int(VALUE_NAME_RENDER_DEVICE_WIDTH, width); + registry->Set_Int(VALUE_NAME_RENDER_DEVICE_HEIGHT, height); + registry->Set_Int(VALUE_NAME_RENDER_DEVICE_DEPTH, depth); + registry->Set_Int(VALUE_NAME_RENDER_DEVICE_WINDOWED, windowed); + registry->Set_Int(VALUE_NAME_RENDER_DEVICE_TEXTURE_DEPTH, texture_depth); + + delete registry; + return true; +} + +bool DX8Wrapper::Registry_Load_Render_Device(const char* sub_key, bool resize_window) +{ + char name[200]; + int width, height, depth, windowed; + + if (Registry_Load_Render_Device(sub_key, + name, + sizeof(name), + width, + height, + depth, + windowed, + TextureBitDepth) && + (*name != 0)) + { + WWDEBUG_SAY(("Device %s (%d X %d) %d bit windowed:%d", name, width, height, depth, windowed)); + + if (TextureBitDepth == 16 || TextureBitDepth == 32) { + // WWDEBUG_SAY(( "Texture depth %d", TextureBitDepth)); + } + else { + WWDEBUG_SAY(("Invalid texture depth %d, switching to 16 bits", TextureBitDepth)); + TextureBitDepth = 16; + } + + + // _RenderDeviceDescriptionTable. + + + if (Set_Render_Device(name, width, height, depth, windowed, resize_window) != true) { + if (depth == 16) depth = 32; + else depth = 16; + if (Set_Render_Device(name, width, height, depth, windowed, resize_window) == true) { + return true; + } + if (depth == 16) depth = 32; + else depth = 16; + // we'll test resolutions down, so if start is 640, increase to begin with... + if (width == 640) { + width = 1024; + height = 768; + } + for (;;) { + if (width > 2048) { + width = 2048; + height = 1536; + } + else if (width > 1920) { + width = 1920; + height = 1440; + } + else if (width > 1600) { + width = 1600; + height = 1200; + } + else if (width > 1280) { + width = 1280; + height = 1024; + } + else if (width > 1024) { + width = 1024; + height = 768; + } + else if (width > 800) { + width = 800; + height = 600; + } + else if (width != 640) { + width = 640; + height = 480; + } + else { + return Set_Any_Render_Device(); + } + for (int i = 0; i < 2; ++i) { + if (Set_Render_Device(name, width, height, depth, windowed, resize_window) == true) { + return true; + } + if (depth == 16) depth = 32; + else depth = 16; + } + } + } + + return true; + } + + WWDEBUG_SAY(("Error getting Registry")); + + return Set_Any_Render_Device(); +} + +bool DX8Wrapper::Registry_Load_Render_Device(const char* sub_key, char* device, int device_len, int& width, int& height, int& depth, int& windowed, int& texture_depth) +{ + RegistryClass registry(sub_key); + + if (registry.Is_Valid()) { + registry.Get_String(VALUE_NAME_RENDER_DEVICE_NAME, + device, device_len); + + width = registry.Get_Int(VALUE_NAME_RENDER_DEVICE_WIDTH, -1); + height = registry.Get_Int(VALUE_NAME_RENDER_DEVICE_HEIGHT, -1); + depth = registry.Get_Int(VALUE_NAME_RENDER_DEVICE_DEPTH, -1); + windowed = registry.Get_Int(VALUE_NAME_RENDER_DEVICE_WINDOWED, -1); + texture_depth = registry.Get_Int(VALUE_NAME_RENDER_DEVICE_TEXTURE_DEPTH, -1); + return true; + } + *device = 0; + width = -1; + height = -1; + depth = -1; + windowed = -1; + texture_depth = -1; + return false; +} + + +bool DX8Wrapper::Find_Color_And_Z_Mode(int resx, int resy, int bitdepth, D3DFORMAT* set_colorbuffer, D3DFORMAT* set_backbuffer, D3DFORMAT* set_zmode) +{ + static D3DFORMAT _formats16[] = + { + D3DFMT_R5G6B5, + D3DFMT_X1R5G5B5, + D3DFMT_A1R5G5B5 + }; + + static D3DFORMAT _formats32[] = + { + D3DFMT_A8R8G8B8, + D3DFMT_X8R8G8B8, + D3DFMT_R8G8B8, + }; + + /* + ** Select the table that we're going to use to search for a valid backbuffer format + */ + D3DFORMAT* format_table = NULL; + int format_count = 0; + + if (BitDepth == 16) { + format_table = _formats16; + format_count = sizeof(_formats16) / sizeof(D3DFORMAT); + } + else { + format_table = _formats32; + format_count = sizeof(_formats32) / sizeof(D3DFORMAT); + } + + /* + ** now search for a valid format + */ + bool found = false; + unsigned int mode = 0; + + int format_index = 0; + for (; format_index < format_count; format_index++) { + found |= Find_Color_Mode(format_table[format_index], resx, resy, &mode); + if (found) break; + } + + if (!found) { + return false; + } + else { + *set_backbuffer = *set_colorbuffer = format_table[format_index]; + } + + if (bitdepth == 32 && *set_colorbuffer == D3DFMT_X8R8G8B8 && D3DInterface->CheckDeviceType(0, D3DDEVTYPE_HAL, *set_colorbuffer, D3DFMT_A8R8G8B8, TRUE) == D3D_OK) + { //promote 32-bit modes to include destination alpha when supported + *set_backbuffer = D3DFMT_A8R8G8B8; + } + + /* + ** We found a backbuffer format, now find a zbuffer format + */ + return Find_Z_Mode(*set_colorbuffer, *set_backbuffer, set_zmode); +}; + + +// find the resolution mode with at least resx,resy with the highest supported +// refresh rate +bool DX8Wrapper::Find_Color_Mode(D3DFORMAT colorbuffer, int resx, int resy, UINT* mode) +{ + UINT i, j, modemax; + UINT rx, ry; + D3DDISPLAYMODE dmode; + ::ZeroMemory(&dmode, sizeof(D3DDISPLAYMODE)); + + rx = (unsigned int)resx; + ry = (unsigned int)resy; + + bool found = false; + + modemax = D3DInterface->GetAdapterModeCount(D3DADAPTER_DEFAULT); + + i = 0; + + while (i < modemax && !found) + { + D3DInterface->EnumAdapterModes(D3DADAPTER_DEFAULT, i, &dmode); + if (dmode.Width == rx && dmode.Height == ry && dmode.Format == colorbuffer) { + WWDEBUG_SAY(("Found valid color mode. Width = %d Height = %d Format = %d", dmode.Width, dmode.Height, dmode.Format)); + found = true; + } + i++; + } + + i--; // this is the first valid mode + + // no match + if (!found) { + WWDEBUG_SAY(("Failed to find a valid color mode")); + return false; + } + + // go to the highest refresh rate in this mode + bool stillok = true; + + j = i; + while (j < modemax && stillok) + { + D3DInterface->EnumAdapterModes(D3DADAPTER_DEFAULT, j, &dmode); + if (dmode.Width == rx && dmode.Height == ry && dmode.Format == colorbuffer) + stillok = true; else stillok = false; + j++; + } + + if (stillok == false) *mode = j - 2; + else *mode = i; + + return true; +} + +// Helper function to find a Z buffer mode for the colorbuffer +// Will look for greatest Z precision +bool DX8Wrapper::Find_Z_Mode(D3DFORMAT colorbuffer, D3DFORMAT backbuffer, D3DFORMAT* zmode) +{ + //MW: Swapped the next 2 tests so that Stencil modes get tested first. + if (Test_Z_Mode(colorbuffer, backbuffer, D3DFMT_D24S8)) + { + *zmode = D3DFMT_D24S8; + WWDEBUG_SAY(("Found zbuffer mode D3DFMT_D24S8")); + return true; + } + + if (Test_Z_Mode(colorbuffer, backbuffer, D3DFMT_D32)) + { + *zmode = D3DFMT_D32; + WWDEBUG_SAY(("Found zbuffer mode D3DFMT_D32")); + return true; + } + + if (Test_Z_Mode(colorbuffer, backbuffer, D3DFMT_D24X8)) + { + *zmode = D3DFMT_D24X8; + WWDEBUG_SAY(("Found zbuffer mode D3DFMT_D24X8")); + return true; + } + + if (Test_Z_Mode(colorbuffer, backbuffer, D3DFMT_D24X4S4)) + { + *zmode = D3DFMT_D24X4S4; + WWDEBUG_SAY(("Found zbuffer mode D3DFMT_D24X4S4")); + return true; + } + + if (Test_Z_Mode(colorbuffer, backbuffer, D3DFMT_D16)) + { + *zmode = D3DFMT_D16; + WWDEBUG_SAY(("Found zbuffer mode D3DFMT_D16")); + return true; + } + + if (Test_Z_Mode(colorbuffer, backbuffer, D3DFMT_D15S1)) + { + *zmode = D3DFMT_D15S1; + WWDEBUG_SAY(("Found zbuffer mode D3DFMT_D15S1")); + return true; + } + + // can't find a match + WWDEBUG_SAY(("Failed to find a valid zbuffer mode")); + return false; +} + +bool DX8Wrapper::Test_Z_Mode(D3DFORMAT colorbuffer, D3DFORMAT backbuffer, D3DFORMAT zmode) +{ + // See if we have this mode first + if (FAILED(D3DInterface->CheckDeviceFormat(D3DADAPTER_DEFAULT, WW3D_DEVTYPE, + colorbuffer, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, zmode))) + { + WWDEBUG_SAY(("CheckDeviceFormat failed. Colorbuffer format = %d Zbufferformat = %d", colorbuffer, zmode)); + return false; + } + + // Then see if it matches the color buffer + if (FAILED(D3DInterface->CheckDepthStencilMatch(D3DADAPTER_DEFAULT, WW3D_DEVTYPE, + colorbuffer, backbuffer, zmode))) + { + WWDEBUG_SAY(("CheckDepthStencilMatch failed. Colorbuffer format = %d Backbuffer format = %d Zbufferformat = %d", colorbuffer, backbuffer, zmode)); + return false; + } + return true; +} + + +void DX8Wrapper::Reset_Statistics() +{ + matrix_changes = 0; + material_changes = 0; + vertex_buffer_changes = 0; + index_buffer_changes = 0; + light_changes = 0; + texture_changes = 0; + render_state_changes = 0; + texture_stage_state_changes = 0; + draw_calls = 0; + + number_of_DX8_calls = 0; + last_frame_matrix_changes = 0; + last_frame_material_changes = 0; + last_frame_vertex_buffer_changes = 0; + last_frame_index_buffer_changes = 0; + last_frame_light_changes = 0; + last_frame_texture_changes = 0; + last_frame_render_state_changes = 0; + last_frame_texture_stage_state_changes = 0; + last_frame_number_of_DX8_calls = 0; + last_frame_draw_calls = 0; +} + +void DX8Wrapper::Begin_Statistics() +{ + matrix_changes = 0; + material_changes = 0; + vertex_buffer_changes = 0; + index_buffer_changes = 0; + light_changes = 0; + texture_changes = 0; + render_state_changes = 0; + texture_stage_state_changes = 0; + number_of_DX8_calls = 0; + draw_calls = 0; +} + +void DX8Wrapper::End_Statistics() +{ + last_frame_matrix_changes = matrix_changes; + last_frame_material_changes = material_changes; + last_frame_vertex_buffer_changes = vertex_buffer_changes; + last_frame_index_buffer_changes = index_buffer_changes; + last_frame_light_changes = light_changes; + last_frame_texture_changes = texture_changes; + last_frame_render_state_changes = render_state_changes; + last_frame_texture_stage_state_changes = texture_stage_state_changes; + last_frame_number_of_DX8_calls = number_of_DX8_calls; + last_frame_draw_calls = draw_calls; +} + +unsigned DX8Wrapper::Get_Last_Frame_Matrix_Changes() { return last_frame_matrix_changes; } +unsigned DX8Wrapper::Get_Last_Frame_Material_Changes() { return last_frame_material_changes; } +unsigned DX8Wrapper::Get_Last_Frame_Vertex_Buffer_Changes() { return last_frame_vertex_buffer_changes; } +unsigned DX8Wrapper::Get_Last_Frame_Index_Buffer_Changes() { return last_frame_index_buffer_changes; } +unsigned DX8Wrapper::Get_Last_Frame_Light_Changes() { return last_frame_light_changes; } +unsigned DX8Wrapper::Get_Last_Frame_Texture_Changes() { return last_frame_texture_changes; } +unsigned DX8Wrapper::Get_Last_Frame_Render_State_Changes() { return last_frame_render_state_changes; } +unsigned DX8Wrapper::Get_Last_Frame_Texture_Stage_State_Changes() { return last_frame_texture_stage_state_changes; } +unsigned DX8Wrapper::Get_Last_Frame_DX8_Calls() { return last_frame_number_of_DX8_calls; } +unsigned DX8Wrapper::Get_Last_Frame_Draw_Calls() { return last_frame_draw_calls; } +unsigned long DX8Wrapper::Get_FrameCount(void) { return FrameCount; } + +void DX8_Assert() +{ + WWASSERT(DX8Wrapper::_Get_D3D8()); + DX8_THREAD_ASSERT(); +} + +void DX8Wrapper::Begin_Scene(void) +{ + DX8_THREAD_ASSERT(); + +#if ENABLE_EMBEDDED_BROWSER + DX8WebBrowser::Update(); +#endif + + DX8CALL(BeginScene()); + + DX8WebBrowser::Update(); +} + +void DX8Wrapper::End_Scene(bool flip_frames) +{ + DX8_THREAD_ASSERT(); + DX8CALL(EndScene()); + + DX8WebBrowser::Render(0); + + if (flip_frames) { + DX8_Assert(); + HRESULT hr; + { + WWPROFILE("DX8Device::Present()"); + hr = _Get_D3D_Device8()->Present(NULL, NULL, NULL, NULL); + } + + number_of_DX8_calls++; + + if (SUCCEEDED(hr)) { +#ifdef EXTENDED_STATS + if (stats.m_sleepTime) { + ::Sleep(stats.m_sleepTime); + } +#endif + IsDeviceLost = false; + FrameCount++; + } + else { + IsDeviceLost = true; + } + + // If the device was lost we need to check for cooperative level and possibly reset the device + if (hr == D3DERR_DEVICELOST) { + hr = _Get_D3D_Device8()->TestCooperativeLevel(); + if (hr == D3DERR_DEVICENOTRESET) { + WWDEBUG_SAY(("DX8Wrapper::End_Scene is resetting the device.")); + Reset_Device(); + } + else { + // Sleep it not active + ThreadClass::Sleep_Ms(200); + } + } + else { + DX8_ErrorCode(hr); + } + } + + // Each frame, release all of the buffers and textures. + Set_Vertex_Buffer(NULL); + Set_Index_Buffer(NULL, 0); + for (int i = 0; i < CurrentCaps->Get_Max_Textures_Per_Pass(); ++i) Set_Texture(i, NULL); + Set_Material(NULL); +} + + +void DX8Wrapper::Flip_To_Primary(void) +{ + // If we are fullscreen and the current frame is odd then we need + // to force a page flip to ensure that the first buffer in the flipping + // chain is the one visible. + if (!IsWindowed) { + DX8_Assert(); + + int numBuffers = (_PresentParameters.BackBufferCount + 1); + int visibleBuffer = (FrameCount % numBuffers); + int flipCount = ((numBuffers - visibleBuffer) % numBuffers); + int resetAttempts = 0; + + while ((flipCount > 0) && (resetAttempts < 3)) { + HRESULT hr = _Get_D3D_Device8()->TestCooperativeLevel(); + + if (FAILED(hr)) { + WWDEBUG_SAY(("TestCooperativeLevel Failed!")); + + if (D3DERR_DEVICELOST == hr) { + IsDeviceLost = true; + WWDEBUG_SAY(("DEVICELOST: Cannot flip to primary.")); + return; + } + IsDeviceLost = false; + + if (D3DERR_DEVICENOTRESET == hr) { + WWDEBUG_SAY(("DEVICENOTRESET")); + Reset_Device(); + resetAttempts++; + } + } + else { + WWDEBUG_SAY(("Flipping: %ld", FrameCount)); + hr = _Get_D3D_Device8()->Present(NULL, NULL, NULL, NULL); + + if (SUCCEEDED(hr)) { + IsDeviceLost = false; + FrameCount++; + WWDEBUG_SAY(("Flip to primary succeeded %ld", FrameCount)); + } + else { + IsDeviceLost = true; + } + } + + --flipCount; + } + } +} + + + +//********************************************************************************************** +//! Clear current render device +/*! KM +/* 5/17/02 KM Fixed support for render to texture with depth/stencil buffers +*/ +void DX8Wrapper::Clear(bool clear_color, bool clear_z_stencil, const Vector3& color, float dest_alpha, float z, unsigned int stencil) +{ + DX8_THREAD_ASSERT(); + + // If we try to clear a stencil buffer which is not there, the entire call will fail + // KJM fixed this to get format from back buffer (incase render to texture is used) + /*bool has_stencil = ( _PresentParameters.AutoDepthStencilFormat == D3DFMT_D15S1 || + _PresentParameters.AutoDepthStencilFormat == D3DFMT_D24S8 || + _PresentParameters.AutoDepthStencilFormat == D3DFMT_D24X4S4);*/ + bool has_stencil = false; + IDirect3DSurface8* depthbuffer; + + _Get_D3D_Device8()->GetDepthStencilSurface(&depthbuffer); + number_of_DX8_calls++; + + if (depthbuffer) + { + D3DSURFACE_DESC desc; + depthbuffer->GetDesc(&desc); + has_stencil = + ( + desc.Format == D3DFMT_D15S1 || + desc.Format == D3DFMT_D24S8 || + desc.Format == D3DFMT_D24X4S4 + ); + + // release ref + depthbuffer->Release(); + } + + DWORD flags = 0; + if (clear_color) flags |= D3DCLEAR_TARGET; + if (clear_z_stencil) flags |= D3DCLEAR_ZBUFFER; + if (clear_z_stencil && has_stencil) flags |= D3DCLEAR_STENCIL; + if (flags) + { + DX8CALL(Clear(0, NULL, flags, Convert_Color(color, dest_alpha), z, stencil)); + } +} + +void DX8Wrapper::Set_Viewport(CONST D3DVIEWPORT8* pViewport) +{ + DX8_THREAD_ASSERT(); + DX8CALL(SetViewport(pViewport)); +} + +// ---------------------------------------------------------------------------- +// +// Set vertex buffer. A reference to previous vertex buffer is released and +// this one is assigned the current vertex buffer. The DX8 vertex buffer will +// actually be set in Apply() which is called by Draw_Indexed_Triangles(). +// +// ---------------------------------------------------------------------------- + +void DX8Wrapper::Set_Vertex_Buffer(const VertexBufferClass* vb, unsigned stream) +{ + render_state.vba_offset = 0; + render_state.vba_count = 0; + if (render_state.vertex_buffers[stream]) { + render_state.vertex_buffers[stream]->Release_Engine_Ref(); + } + REF_PTR_SET(render_state.vertex_buffers[stream], const_cast(vb)); + if (vb) { + vb->Add_Engine_Ref(); + render_state.vertex_buffer_types[stream] = vb->Type(); + } + else { + render_state.vertex_buffer_types[stream] = BUFFER_TYPE_INVALID; + } + render_state_changed |= VERTEX_BUFFER_CHANGED; +} + +// ---------------------------------------------------------------------------- +// +// Set index buffer. A reference to previous index buffer is released and +// this one is assigned the current index buffer. The DX8 index buffer will +// actually be set in Apply() which is called by Draw_Indexed_Triangles(). +// +// ---------------------------------------------------------------------------- + +void DX8Wrapper::Set_Index_Buffer(const IndexBufferClass* ib, unsigned short index_base_offset) +{ + render_state.iba_offset = 0; + if (render_state.index_buffer) { + render_state.index_buffer->Release_Engine_Ref(); + } + REF_PTR_SET(render_state.index_buffer, const_cast(ib)); + render_state.index_base_offset = index_base_offset; + if (ib) { + ib->Add_Engine_Ref(); + render_state.index_buffer_type = ib->Type(); + } + else { + render_state.index_buffer_type = BUFFER_TYPE_INVALID; + } + render_state_changed |= INDEX_BUFFER_CHANGED; +} + +// ---------------------------------------------------------------------------- +// +// Set vertex buffer using dynamic access object. +// +// ---------------------------------------------------------------------------- + +void DX8Wrapper::Set_Vertex_Buffer(const DynamicVBAccessClass& vba_) +{ + // Release all streams (only one stream allowed in the legacy pipeline) + for (int i = 1; i < MAX_VERTEX_STREAMS; ++i) { + DX8Wrapper::Set_Vertex_Buffer(NULL, i); + } + + if (render_state.vertex_buffers[0]) render_state.vertex_buffers[0]->Release_Engine_Ref(); + DynamicVBAccessClass& vba = const_cast(vba_); + render_state.vertex_buffer_types[0] = vba.Get_Type(); + render_state.vba_offset = vba.VertexBufferOffset; + render_state.vba_count = vba.Get_Vertex_Count(); + REF_PTR_SET(render_state.vertex_buffers[0], vba.VertexBuffer); + render_state.vertex_buffers[0]->Add_Engine_Ref(); + render_state_changed |= VERTEX_BUFFER_CHANGED; + render_state_changed |= INDEX_BUFFER_CHANGED; // vba_offset changes so index buffer needs to be reset as well. +} + +// ---------------------------------------------------------------------------- +// +// Set index buffer using dynamic access object. +// +// ---------------------------------------------------------------------------- + +void DX8Wrapper::Set_Index_Buffer(const DynamicIBAccessClass& iba_, unsigned short index_base_offset) +{ + if (render_state.index_buffer) render_state.index_buffer->Release_Engine_Ref(); + + DynamicIBAccessClass& iba = const_cast(iba_); + render_state.index_base_offset = index_base_offset; + render_state.index_buffer_type = iba.Get_Type(); + render_state.iba_offset = iba.IndexBufferOffset; + REF_PTR_SET(render_state.index_buffer, iba.IndexBuffer); + render_state.index_buffer->Add_Engine_Ref(); + render_state_changed |= INDEX_BUFFER_CHANGED; +} + +// ---------------------------------------------------------------------------- +// +// Private function for the special case of rendering polygons from sorting +// index and vertex buffers. +// +// ---------------------------------------------------------------------------- + +void DX8Wrapper::Draw_Sorting_IB_VB( + unsigned primitive_type, + unsigned short start_index, + unsigned short polygon_count, + unsigned short min_vertex_index, + unsigned short vertex_count) +{ + WWASSERT(render_state.vertex_buffer_types[0] == BUFFER_TYPE_SORTING || render_state.vertex_buffer_types[0] == BUFFER_TYPE_DYNAMIC_SORTING); + WWASSERT(render_state.index_buffer_type == BUFFER_TYPE_SORTING || render_state.index_buffer_type == BUFFER_TYPE_DYNAMIC_SORTING); + + // Fill dynamic vertex buffer with sorting vertex buffer vertices + DynamicVBAccessClass dyn_vb_access(BUFFER_TYPE_DYNAMIC_DX8, dynamic_fvf_type, vertex_count); + { + DynamicVBAccessClass::WriteLockClass lock(&dyn_vb_access); + VertexFormatXYZNDUV2* src = static_cast(render_state.vertex_buffers[0])->VertexBuffer; + VertexFormatXYZNDUV2* dest = lock.Get_Formatted_Vertex_Array(); + src += render_state.vba_offset + render_state.index_base_offset + min_vertex_index; + unsigned size = dyn_vb_access.FVF_Info().Get_FVF_Size() * vertex_count / sizeof(unsigned); + unsigned* dest_u = (unsigned*)dest; + unsigned* src_u = (unsigned*)src; + + for (unsigned i = 0; i < size; ++i) { + *dest_u++ = *src_u++; + } + } + + DX8CALL(SetStreamSource( + 0, + static_cast(dyn_vb_access.VertexBuffer)->Get_DX8_Vertex_Buffer(), + dyn_vb_access.FVF_Info().Get_FVF_Size())); + // If using FVF format VB, set the FVF as vertex shader (may not be needed here KM) + unsigned fvf = dyn_vb_access.FVF_Info().Get_FVF(); + if (fvf != 0) { + DX8CALL(SetVertexShader(fvf)); + } + DX8_RECORD_VERTEX_BUFFER_CHANGE(); + + unsigned index_count = 0; + switch (primitive_type) { + case D3DPT_TRIANGLELIST: index_count = polygon_count * 3; break; + case D3DPT_TRIANGLESTRIP: index_count = polygon_count + 2; break; + case D3DPT_TRIANGLEFAN: index_count = polygon_count + 2; break; + default: WWASSERT(0); break; // Unsupported primitive type + } + + // Fill dynamic index buffer with sorting index buffer vertices + DynamicIBAccessClass dyn_ib_access(BUFFER_TYPE_DYNAMIC_DX8, index_count); + { + DynamicIBAccessClass::WriteLockClass lock(&dyn_ib_access); + unsigned short* dest = lock.Get_Index_Array(); + unsigned short* src = NULL; + src = static_cast(render_state.index_buffer)->index_buffer; + src += render_state.iba_offset + start_index; + + for (unsigned short i = 0; i < index_count; ++i) { + unsigned short index = *src++; + index -= min_vertex_index; + WWASSERT(index < vertex_count); + *dest++ = index; + } + } + + DX8CALL(SetIndices( + static_cast(dyn_ib_access.IndexBuffer)->Get_DX8_Index_Buffer(), + dyn_vb_access.VertexBufferOffset)); + DX8_RECORD_INDEX_BUFFER_CHANGE(); + + DX8_RECORD_DRAW_CALLS(); + DX8CALL(DrawIndexedPrimitive( + D3DPT_TRIANGLELIST, + 0, // start vertex + vertex_count, + dyn_ib_access.IndexBufferOffset, + polygon_count)); + + DX8_RECORD_RENDER(polygon_count, vertex_count, render_state.shader); +} + +// ---------------------------------------------------------------------------- +// +// +// +// ---------------------------------------------------------------------------- + +void DX8Wrapper::Draw( + unsigned primitive_type, + unsigned short start_index, + unsigned short polygon_count, + unsigned short min_vertex_index, + unsigned short vertex_count) +{ + if (DrawPolygonLowBoundLimit && DrawPolygonLowBoundLimit >= polygon_count) return; + + DX8_THREAD_ASSERT(); + SNAPSHOT_SAY(("DX8 - draw")); + + Apply_Render_State_Changes(); + + // Debug feature to disable triangle drawing... + if (!_Is_Triangle_Draw_Enabled()) return; + +#ifdef MESH_RENDER_SNAPSHOT_ENABLED + if (WW3D::Is_Snapshot_Activated()) { + unsigned long passes = 0; + SNAPSHOT_SAY(("ValidateDevice:")); + HRESULT res = D3DDevice->ValidateDevice(&passes); + switch (res) { + case D3D_OK: + SNAPSHOT_SAY(("OK")); + break; + + case D3DERR_CONFLICTINGTEXTUREFILTER: + SNAPSHOT_SAY(("D3DERR_CONFLICTINGTEXTUREFILTER")); + break; + case D3DERR_CONFLICTINGTEXTUREPALETTE: + SNAPSHOT_SAY(("D3DERR_CONFLICTINGTEXTUREPALETTE")); + break; + case D3DERR_DEVICELOST: + SNAPSHOT_SAY(("D3DERR_DEVICELOST")); + break; + case D3DERR_TOOMANYOPERATIONS: + SNAPSHOT_SAY(("D3DERR_TOOMANYOPERATIONS")); + break; + case D3DERR_UNSUPPORTEDALPHAARG: + SNAPSHOT_SAY(("D3DERR_UNSUPPORTEDALPHAARG")); + break; + case D3DERR_UNSUPPORTEDALPHAOPERATION: + SNAPSHOT_SAY(("D3DERR_UNSUPPORTEDALPHAOPERATION")); + break; + case D3DERR_UNSUPPORTEDCOLORARG: + SNAPSHOT_SAY(("D3DERR_UNSUPPORTEDCOLORARG")); + break; + case D3DERR_UNSUPPORTEDCOLOROPERATION: + SNAPSHOT_SAY(("D3DERR_UNSUPPORTEDCOLOROPERATION")); + break; + case D3DERR_UNSUPPORTEDFACTORVALUE: + SNAPSHOT_SAY(("D3DERR_UNSUPPORTEDFACTORVALUE")); + break; + case D3DERR_UNSUPPORTEDTEXTUREFILTER: + SNAPSHOT_SAY(("D3DERR_UNSUPPORTEDTEXTUREFILTER")); + break; + case D3DERR_WRONGTEXTUREFORMAT: + SNAPSHOT_SAY(("D3DERR_WRONGTEXTUREFORMAT")); + break; + default: + SNAPSHOT_SAY(("UNKNOWN Error")); + break; + } + } +#endif // MESH_RENDER_SHAPSHOT_ENABLED + + + SNAPSHOT_SAY(("DX8 - draw %d polygons (%d vertices)", polygon_count, vertex_count)); + + if (vertex_count < 3) { + min_vertex_index = 0; + switch (render_state.vertex_buffer_types[0]) { + case BUFFER_TYPE_DX8: + case BUFFER_TYPE_SORTING: + vertex_count = render_state.vertex_buffers[0]->Get_Vertex_Count() - render_state.index_base_offset - render_state.vba_offset - min_vertex_index; + break; + case BUFFER_TYPE_DYNAMIC_DX8: + case BUFFER_TYPE_DYNAMIC_SORTING: + vertex_count = render_state.vba_count; + break; + } + } + + switch (render_state.vertex_buffer_types[0]) { + case BUFFER_TYPE_DX8: + case BUFFER_TYPE_DYNAMIC_DX8: + switch (render_state.index_buffer_type) { + case BUFFER_TYPE_DX8: + case BUFFER_TYPE_DYNAMIC_DX8: + { + /* if ((start_index+render_state.iba_offset+polygon_count*3) > render_state.index_buffer->Get_Index_Count()) + { WWASSERT_PRINT(0,"OVERFLOWING INDEX BUFFER"); + ///@todo: MUST FIND OUT WHY THIS HAPPENS WITH LOTS OF PARTICLES ON BIG FIGHT! -MW + break; + }*/ + DX8_RECORD_RENDER(polygon_count, vertex_count, render_state.shader); + DX8_RECORD_DRAW_CALLS(); + DX8CALL(DrawIndexedPrimitive( + (D3DPRIMITIVETYPE)primitive_type, + min_vertex_index, + vertex_count, + start_index + render_state.iba_offset, + polygon_count)); + } + break; + case BUFFER_TYPE_SORTING: + case BUFFER_TYPE_DYNAMIC_SORTING: + WWASSERT_PRINT(0, "VB and IB must of same type (sorting or dx8)"); + break; + case BUFFER_TYPE_INVALID: + WWASSERT(0); + break; + } + break; + case BUFFER_TYPE_SORTING: + case BUFFER_TYPE_DYNAMIC_SORTING: + switch (render_state.index_buffer_type) { + case BUFFER_TYPE_DX8: + case BUFFER_TYPE_DYNAMIC_DX8: + WWASSERT_PRINT(0, "VB and IB must of same type (sorting or dx8)"); + break; + case BUFFER_TYPE_SORTING: + case BUFFER_TYPE_DYNAMIC_SORTING: + Draw_Sorting_IB_VB(primitive_type, start_index, polygon_count, min_vertex_index, vertex_count); + break; + case BUFFER_TYPE_INVALID: + WWASSERT(0); + break; + } + break; + case BUFFER_TYPE_INVALID: + WWASSERT(0); + break; + } +} + +// ---------------------------------------------------------------------------- +// +// +// +// ---------------------------------------------------------------------------- + +void DX8Wrapper::Draw_Triangles( + unsigned buffer_type, + unsigned short start_index, + unsigned short polygon_count, + unsigned short min_vertex_index, + unsigned short vertex_count) +{ + if (buffer_type == BUFFER_TYPE_SORTING || buffer_type == BUFFER_TYPE_DYNAMIC_SORTING) { + SortingRendererClass::Insert_Triangles(start_index, polygon_count, min_vertex_index, vertex_count); + } + else { + Draw(D3DPT_TRIANGLELIST, start_index, polygon_count, min_vertex_index, vertex_count); + } +} + +// ---------------------------------------------------------------------------- +// +// +// +// ---------------------------------------------------------------------------- + +void DX8Wrapper::Draw_Triangles( + unsigned short start_index, + unsigned short polygon_count, + unsigned short min_vertex_index, + unsigned short vertex_count) +{ + Draw(D3DPT_TRIANGLELIST, start_index, polygon_count, min_vertex_index, vertex_count); +} + +// ---------------------------------------------------------------------------- +// +// +// +// ---------------------------------------------------------------------------- + +void DX8Wrapper::Draw_Strip( + unsigned short start_index, + unsigned short polygon_count, + unsigned short min_vertex_index, + unsigned short vertex_count) +{ + Draw(D3DPT_TRIANGLESTRIP, start_index, polygon_count, min_vertex_index, vertex_count); +} + + + +// ---------------------------------------------------------------------------- +// +// +// +// ---------------------------------------------------------------------------- + +void DX8Wrapper::Apply_Render_State_Changes() +{ + SNAPSHOT_SAY(("DX8Wrapper::Apply_Render_State_Changes()")); + + if (!render_state_changed) return; + if (render_state_changed & SHADER_CHANGED) { + SNAPSHOT_SAY(("DX8 - apply shader")); + render_state.shader.Apply(); + } + + unsigned mask = TEXTURE0_CHANGED; + int i = 0; + for (; i < CurrentCaps->Get_Max_Textures_Per_Pass(); ++i, mask <<= 1) + { + if (render_state_changed & mask) + { + SNAPSHOT_SAY(("DX8 - apply texture %d (%s)", i, render_state.Textures[i] ? render_state.Textures[i]->Get_Full_Path().str() : "NULL")); + + if (render_state.Textures[i]) + { + render_state.Textures[i]->Apply(i); + } + else + { + TextureBaseClass::Apply_Null(i); + } + } + } + + if (render_state_changed & MATERIAL_CHANGED) + { + SNAPSHOT_SAY(("DX8 - apply material")); + VertexMaterialClass* material = const_cast(render_state.material); + if (material) + { + material->Apply(); + } + else VertexMaterialClass::Apply_Null(); + } + + if (render_state_changed & LIGHTS_CHANGED) + { + unsigned mask = LIGHT0_CHANGED; + for (unsigned index = 0; index < 4; ++index, mask <<= 1) { + if (render_state_changed & mask) { + SNAPSHOT_SAY(("DX8 - apply light %d", index)); + if (render_state.LightEnable[index]) { +#ifdef MESH_RENDER_SNAPSHOT_ENABLED + if (WW3D::Is_Snapshot_Activated()) { + D3DLIGHT8* light = &(render_state.Lights[index]); + static const char* _light_types[] = { "Unknown", "Point","Spot", "Directional" }; + WWASSERT((light->Type >= 0) && (light->Type <= 3)); + + SNAPSHOT_SAY((" type = %s amb = %4.2f,%4.2f,%4.2f diff = %4.2f,%4.2f,%4.2f spec = %4.2f, %4.2f, %4.2f", + _light_types[light->Type], + light->Ambient.r, light->Ambient.g, light->Ambient.b, + light->Diffuse.r, light->Diffuse.g, light->Diffuse.b, + light->Specular.r, light->Specular.g, light->Specular.b)); + SNAPSHOT_SAY((" pos = %f, %f, %f dir = %f, %f, %f", + light->Position.x, light->Position.y, light->Position.z, + light->Direction.x, light->Direction.y, light->Direction.z)); + } +#endif + + Set_DX8_Light(index, &render_state.Lights[index]); + } + else { + Set_DX8_Light(index, NULL); + SNAPSHOT_SAY((" clearing light to NULL")); + } + } + } + } + + if (render_state_changed & WORLD_CHANGED) { + SNAPSHOT_SAY(("DX8 - apply world matrix")); + _Set_DX8_Transform(D3DTS_WORLD, render_state.world); + } + if (render_state_changed & VIEW_CHANGED) { + SNAPSHOT_SAY(("DX8 - apply view matrix")); + _Set_DX8_Transform(D3DTS_VIEW, render_state.view); + } + if (render_state_changed & VERTEX_BUFFER_CHANGED) { + SNAPSHOT_SAY(("DX8 - apply vb change")); + for (i = 0; i < MAX_VERTEX_STREAMS; ++i) { + if (render_state.vertex_buffers[i]) { + switch (render_state.vertex_buffer_types[i]) {//->Type()) { + case BUFFER_TYPE_DX8: + case BUFFER_TYPE_DYNAMIC_DX8: + DX8CALL(SetStreamSource( + i, + static_cast(render_state.vertex_buffers[i])->Get_DX8_Vertex_Buffer(), + render_state.vertex_buffers[i]->FVF_Info().Get_FVF_Size())); + DX8_RECORD_VERTEX_BUFFER_CHANGE(); + { + // If the VB format is FVF, set the FVF as a vertex shader + unsigned fvf = render_state.vertex_buffers[i]->FVF_Info().Get_FVF(); + if (fvf != 0) { + Set_Vertex_Shader(fvf); + } + } + break; + case BUFFER_TYPE_SORTING: + case BUFFER_TYPE_DYNAMIC_SORTING: + break; + default: + WWASSERT(0); + } + } + else { + DX8CALL(SetStreamSource(i, NULL, 0)); + DX8_RECORD_VERTEX_BUFFER_CHANGE(); + } + } + } + if (render_state_changed & INDEX_BUFFER_CHANGED) { + SNAPSHOT_SAY(("DX8 - apply ib change")); + if (render_state.index_buffer) { + switch (render_state.index_buffer_type) {//->Type()) { + case BUFFER_TYPE_DX8: + case BUFFER_TYPE_DYNAMIC_DX8: + DX8CALL(SetIndices( + static_cast(render_state.index_buffer)->Get_DX8_Index_Buffer(), + render_state.index_base_offset + render_state.vba_offset)); + DX8_RECORD_INDEX_BUFFER_CHANGE(); + break; + case BUFFER_TYPE_SORTING: + case BUFFER_TYPE_DYNAMIC_SORTING: + break; + default: + WWASSERT(0); + } + } + else { + DX8CALL(SetIndices( + NULL, + 0)); + DX8_RECORD_INDEX_BUFFER_CHANGE(); + } + } + + render_state_changed &= ((unsigned)WORLD_IDENTITY | (unsigned)VIEW_IDENTITY); + + SNAPSHOT_SAY(("DX8Wrapper::Apply_Render_State_Changes() - finished")); +} + +IDirect3DTexture8* DX8Wrapper::_Create_DX8_Texture +( + unsigned int width, + unsigned int height, + WW3DFormat format, + MipCountType mip_level_count, + D3DPOOL pool, + bool rendertarget +) +{ + DX8_THREAD_ASSERT(); + DX8_Assert(); + IDirect3DTexture8* 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 = D3DXCreateTexture( + DX8Wrapper::_Get_D3D_Device8(), + width, + height, + 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 = D3DXCreateTexture( + DX8Wrapper::_Get_D3D_Device8(), + width, + height, + 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 = D3DXCreateTexture( + DX8Wrapper::_Get_D3D_Device8(), + width, + height, + 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 = D3DXCreateTexture( + DX8Wrapper::_Get_D3D_Device8(), + width, + height, + 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; +} + +IDirect3DTexture8* DX8Wrapper::_Create_DX8_Texture +( + const char* filename, + MipCountType mip_level_count +) +{ + DX8_THREAD_ASSERT(); + DX8_Assert(); + IDirect3DTexture8* texture = NULL; + + // NOTE: If the original image format is not supported as a texture format, it will + // automatically be converted to an appropriate format. + // NOTE: It is possible to get the size and format of the original image file from this + // function as well, so if we later want to second-guess D3DX's format conversion decisions + // we can do so after this function is called.. + unsigned result = D3DXCreateTextureFromFileExA( + _Get_D3D_Device8(), + filename, + D3DX_DEFAULT, + D3DX_DEFAULT, + mip_level_count,//create_mipmaps ? 0 : 1, + 0, + D3DFMT_UNKNOWN, + D3DPOOL_MANAGED, + D3DX_FILTER_BOX, + D3DX_FILTER_BOX, + 0, + NULL, + NULL, + &texture); + + if (result != D3D_OK) { + return MissingTexture::_Get_Missing_Texture(); + } + + // Make sure texture wasn't paletted! + D3DSURFACE_DESC desc; + texture->GetLevelDesc(0, &desc); + if (desc.Format == D3DFMT_P8) { + texture->Release(); + return MissingTexture::_Get_Missing_Texture(); + } + return texture; +} + +IDirect3DTexture8* DX8Wrapper::_Create_DX8_Texture +( + IDirect3DSurface8* surface, + MipCountType mip_level_count +) +{ + DX8_THREAD_ASSERT(); + DX8_Assert(); + IDirect3DTexture8* texture = NULL; + + D3DSURFACE_DESC surface_desc; + ::ZeroMemory(&surface_desc, sizeof(D3DSURFACE_DESC)); + surface->GetDesc(&surface_desc); + + // This function will create a texture with a different (but similar) format if the surface is + // not in a supported texture format. + WW3DFormat format = D3DFormat_To_WW3DFormat(surface_desc.Format); + texture = _Create_DX8_Texture(surface_desc.Width, surface_desc.Height, format, mip_level_count); + + // Copy the surface to the texture + IDirect3DSurface8* tex_surface = NULL; + texture->GetSurfaceLevel(0, &tex_surface); + DX8_ErrorCode(D3DXLoadSurfaceFromSurface(tex_surface, NULL, NULL, surface, NULL, NULL, D3DX_FILTER_BOX, 0)); + tex_surface->Release(); + + // Create mipmaps if needed + if (mip_level_count != MIP_LEVELS_1) + { + DX8_ErrorCode(D3DXFilterTexture(texture, NULL, 0, D3DX_FILTER_BOX)); + } + + return 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(); + DX8_Assert(); + + IDirect3DSurface8* surface = NULL; + + // Paletted surfaces not supported! + WWASSERT(format != D3DFMT_P8); + + DX8CALL(CreateImageSurface(width, height, WW3DFormat_To_D3DFormat(format), &surface)); + + return surface; +} + +IDirect3DSurface8* DX8Wrapper::_Create_DX8_Surface(const char* filename_) +{ + DX8_THREAD_ASSERT(); + DX8_Assert(); + + // Note: Since there is no "D3DXCreateSurfaceFromFile" and no "GetSurfaceInfoFromFile" (the + // latter is supposed to be added to D3DX in a future version), we create a texture from the + // file (w/o mipmaps), check that its surface is equal to the original file data (which it + // will not be if the file is not in a texture-supported format or size). If so, copy its + // surface (we might be able to just get its surface and add a ref to it but I'm not sure so + // I'm not going to risk it) and release the texture. If not, create a surface according to + // the file data and use D3DXLoadSurfaceFromFile. This is a horrible hack, but it saves us + // having to write file loaders. Will fix this when D3DX provides us with the right functions. + // Create a surface the size of the file image data + IDirect3DSurface8* surface = NULL; + + { + + file_auto_ptr myfile(_TheFileFactory, filename_); + // If file not found, create a surface with missing texture in it + + if (!myfile->Is_Available()) { + // If file not found, try the dds format + // else create a surface with missing texture in it + char compressed_name[200]; + strncpy(compressed_name, filename_, ARRAY_SIZE(compressed_name)); + compressed_name[ARRAY_SIZE(compressed_name) - 1] = '\0'; + char* ext = strstr(compressed_name, "."); + if (ext && (strlen(ext) == 4) && + ((ext[1] == 't') || (ext[1] == 'T')) && + ((ext[2] == 'g') || (ext[2] == 'G')) && + ((ext[3] == 'a') || (ext[3] == 'A'))) { + ext[1] = 'd'; + ext[2] = 'd'; + ext[3] = 's'; + } + file_auto_ptr myfile2(_TheFileFactory, compressed_name); + if (!myfile2->Is_Available()) + return MissingTexture::_Create_Missing_Surface(); + } + } + + StringClass filename_string(filename_, true); + surface = TextureLoader::Load_Surface_Immediate( + filename_string, + WW3D_FORMAT_UNKNOWN, + true); + return surface; +} + + +/*********************************************************************************************** + * DX8Wrapper::_Update_Texture -- Copies a texture from system memory to video memory * + * * + * * + * * + * * + * INPUT: * + * * + * OUTPUT: * + * * + * WARNINGS: * + * * + * HISTORY: * + * 4/26/2001 hy : Created. * + *=============================================================================================*/ +void DX8Wrapper::_Update_Texture(TextureClass* system, TextureClass* video) +{ + WWASSERT(system); + WWASSERT(video); + WWASSERT(system->Get_Pool() == TextureClass::POOL_SYSTEMMEM); + WWASSERT(video->Get_Pool() == TextureClass::POOL_DEFAULT); + DX8CALL(UpdateTexture(system->Peek_D3D_Base_Texture(), video->Peek_D3D_Base_Texture())); +} + +void DX8Wrapper::Compute_Caps(WW3DFormat display_format) +{ + DX8_THREAD_ASSERT(); + DX8_Assert(); + delete CurrentCaps; + CurrentCaps = new DX8Caps(_Get_D3D8(), D3DDevice, display_format, Get_Current_Adapter_Identifier()); +} + + +void DX8Wrapper::Set_Light(unsigned index, const D3DLIGHT8* light) +{ + if (light) { + render_state.Lights[index] = *light; + render_state.LightEnable[index] = true; + } + else { + render_state.LightEnable[index] = false; + } + render_state_changed |= (LIGHT0_CHANGED << index); +} + +void DX8Wrapper::Set_Light(unsigned index, const LightClass& light) +{ + D3DLIGHT8 dlight; + Vector3 temp; + memset(&dlight, 0, sizeof(D3DLIGHT8)); + + switch (light.Get_Type()) + { + case LightClass::POINT: + { + dlight.Type = D3DLIGHT_POINT; + } + break; + case LightClass::DIRECTIONAL: + { + dlight.Type = D3DLIGHT_DIRECTIONAL; + } + break; + case LightClass::SPOT: + { + dlight.Type = D3DLIGHT_SPOT; + } + break; + } + + light.Get_Diffuse(&temp); + temp *= light.Get_Intensity(); + dlight.Diffuse.r = temp.X; + dlight.Diffuse.g = temp.Y; + dlight.Diffuse.b = temp.Z; + dlight.Diffuse.a = 1.0f; + + light.Get_Specular(&temp); + temp *= light.Get_Intensity(); + dlight.Specular.r = temp.X; + dlight.Specular.g = temp.Y; + dlight.Specular.b = temp.Z; + dlight.Specular.a = 1.0f; + + light.Get_Ambient(&temp); + temp *= light.Get_Intensity(); + dlight.Ambient.r = temp.X; + dlight.Ambient.g = temp.Y; + dlight.Ambient.b = temp.Z; + dlight.Ambient.a = 1.0f; + + temp = light.Get_Position(); + dlight.Position = *(D3DVECTOR*)&temp; + + light.Get_Spot_Direction(temp); + dlight.Direction = *(D3DVECTOR*)&temp; + + dlight.Range = light.Get_Attenuation_Range(); + dlight.Falloff = light.Get_Spot_Exponent(); + dlight.Theta = light.Get_Spot_Angle(); + dlight.Phi = light.Get_Spot_Angle(); + + // Inverse linear light 1/(1+D) + double a, b; + light.Get_Far_Attenuation_Range(a, b); + dlight.Attenuation0 = 1.0f; + if (fabs(a - b) < 1e-5) + // if the attenuation range is too small assume uniform with cutoff + dlight.Attenuation1 = 0.0f; + else + // this will cause the light to drop to half intensity at the first far attenuation + dlight.Attenuation1 = (float)1.0 / a; + dlight.Attenuation2 = 0.0f; + + Set_Light(index, &dlight); +} + diff --git a/Generals/Code/GameEngine/Source/Common/System/MemoryInit.cpp b/Generals/Code/GameEngine/Source/Common/System/MemoryInit.cpp index 9c6fb92d96c..be31bc6b532 100644 --- a/Generals/Code/GameEngine/Source/Common/System/MemoryInit.cpp +++ b/Generals/Code/GameEngine/Source/Common/System/MemoryInit.cpp @@ -663,6 +663,7 @@ static PoolSizeRec sizes[] = { "DynamicMeshModel", 32, 32 }, { "GapFillerClass", 32, 32 }, { "FontCharsClass", 64, 32 }, + { "ThumbnailManagerClass", 32, 32 }, { 0, 0, 0 } }; diff --git a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DAssetManager.cpp b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DAssetManager.cpp index 595e15bdc88..4585cc0072e 100644 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DAssetManager.cpp +++ b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DAssetManager.cpp @@ -628,7 +628,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 a03ed940b88..b8a6cfb4986 100644 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp +++ b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp @@ -412,7 +412,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/W3DShroud.cpp b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DShroud.cpp index be441cbf743..9a5a0a613be 100644 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DShroud.cpp +++ b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DShroud.cpp @@ -127,9 +127,14 @@ void W3DShroud::init(WorldHeightMap *pMap, Real worldCellSizeX, Real worldCellSi //shroud cells are larger than terrain cells). dstTextureWidth=m_numMaxVisibleCellsX=REAL_TO_INT_FLOOR((Real)(pMap->getDrawWidth()-1)*MAP_XY_FACTOR/m_cellWidth)+1; dstTextureHeight=m_numMaxVisibleCellsY=REAL_TO_INT_FLOOR((Real)(pMap->getDrawHeight()-1)*MAP_XY_FACTOR/m_cellHeight)+1; + + dstTextureWidth = m_numCellsX; + dstTextureHeight = m_numCellsY; + dstTextureWidth += 2; //enlarge by 2 pixels so we can have a border color all the way around. + unsigned int depth = 1; dstTextureHeight += 2; //enlarge by 2 pixels so we can have border color all the way around. - TextureLoader::Validate_Texture_Size((unsigned int &)dstTextureWidth,(unsigned int &)dstTextureHeight); + TextureLoader::Validate_Texture_Size((unsigned int&)dstTextureWidth, (unsigned int&)dstTextureHeight, depth); } UnsignedInt srcWidth,srcHeight; diff --git a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DVideoBuffer.cpp b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DVideoBuffer.cpp index 4f7701d094c..b3a04ae629e 100644 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DVideoBuffer.cpp +++ b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DVideoBuffer.cpp @@ -122,7 +122,8 @@ Bool W3DVideoBuffer::allocate( UnsignedInt width, UnsignedInt height ) m_height = height; m_textureWidth = width;; m_textureHeight = height;; - TextureLoader::Validate_Texture_Size( m_textureWidth, m_textureHeight); + unsigned int temp_depth = 1; + TextureLoader::Validate_Texture_Size(m_textureWidth, m_textureHeight, temp_depth); WW3DFormat w3dFormat = TypeToW3DFormat( m_format ); diff --git a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWater.cpp b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWater.cpp index ee1d7fab7f0..1e2b3855c9e 100644 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWater.cpp +++ b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Water/W3DWater.cpp @@ -1438,7 +1438,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 diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/assetmgr.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/assetmgr.cpp index c731064a32d..4a31e6a0f74 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/assetmgr.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/assetmgr.cpp @@ -1044,6 +1044,8 @@ HTreeClass * WW3DAssetManager::Get_HTree(const char * name) return htree; } +//doesn't exist in ZH + /*********************************************************************************************** * 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. * @@ -1058,31 +1060,31 @@ HTreeClass * WW3DAssetManager::Get_HTree(const char * name) * 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; -} +//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 * diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/assetmgr.h b/Generals/Code/Libraries/Source/WWVegas/WW3D2/assetmgr.h index 36e8446dee3..06fab701a75 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/assetmgr.h +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/assetmgr.h @@ -271,7 +271,9 @@ class WW3DAssetManager TextureBaseClass::TexAssetType type=TextureBaseClass::TEX_REGULAR, bool allow_reduction=true ); - TextureClass* Get_Bumpmap_Based_On_Texture(TextureClass* texture); + + //doesn't exist in ZH + //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/dx8texman.h b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8texman.h index cef92a6f614..649dcf21ca7 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8texman.h +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8texman.h @@ -126,6 +126,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 514ac500830..716ddbd762c 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -84,38 +84,6 @@ #include "shdlib.h" -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; -}; - const int DEFAULT_RESOLUTION_WIDTH = 640; const int DEFAULT_RESOLUTION_HEIGHT = 480; @@ -166,1961 +134,137 @@ Vector3 DX8Wrapper::Ambient_Color; bool DX8Wrapper::world_identity; unsigned DX8Wrapper::RenderStates[256]; unsigned DX8Wrapper::TextureStageStates[MAX_TEXTURE_STAGES][32]; -IDirect3DBaseTexture8 * DX8Wrapper::Textures[MAX_TEXTURE_STAGES]; -RenderStateStruct DX8Wrapper::render_state; -unsigned DX8Wrapper::render_state_changed; - -bool DX8Wrapper::FogEnable = false; -D3DCOLOR DX8Wrapper::FogColor = 0; - -IDirect3D8 * DX8Wrapper::D3DInterface = NULL; -IDirect3DDevice8 * DX8Wrapper::D3DDevice = NULL; -IDirect3DSurface8 * DX8Wrapper::CurrentRenderTarget = NULL; -IDirect3DSurface8 * DX8Wrapper::DefaultRenderTarget = NULL; -bool DX8Wrapper::IsRenderToTexture = false; - -unsigned DX8Wrapper::matrix_changes = 0; -unsigned DX8Wrapper::material_changes = 0; -unsigned DX8Wrapper::vertex_buffer_changes = 0; -unsigned DX8Wrapper::index_buffer_changes = 0; -unsigned DX8Wrapper::light_changes = 0; -unsigned DX8Wrapper::texture_changes = 0; -unsigned DX8Wrapper::render_state_changes = 0; -unsigned DX8Wrapper::texture_stage_state_changes = 0; -unsigned DX8Wrapper::draw_calls = 0; -unsigned DX8Wrapper::_MainThreadID = 0; -bool DX8Wrapper::CurrentDX8LightEnables[4]; -bool DX8Wrapper::IsDeviceLost; -int DX8Wrapper::ZBias; -float DX8Wrapper::ZNear; -float DX8Wrapper::ZFar; -Matrix4x4 DX8Wrapper::ProjectionMatrix; -Matrix4x4 DX8Wrapper::DX8Transforms[D3DTS_WORLD+1]; - -DX8Caps* DX8Wrapper::CurrentCaps = 0; - -// Hack test... this disables rendering of batches of too few polygons. -unsigned DX8Wrapper::DrawPolygonLowBoundLimit=0; - -D3DADAPTER_IDENTIFIER8 DX8Wrapper::CurrentAdapterIdentifier; - -unsigned long DX8Wrapper::FrameCount = 0; - -bool _DX8SingleThreaded = false; - -unsigned number_of_DX8_calls = 0; -static unsigned last_frame_matrix_changes = 0; -static unsigned last_frame_material_changes = 0; -static unsigned last_frame_vertex_buffer_changes = 0; -static unsigned last_frame_index_buffer_changes = 0; -static unsigned last_frame_light_changes = 0; -static unsigned last_frame_texture_changes = 0; -static unsigned last_frame_render_state_changes = 0; -static unsigned last_frame_texture_stage_state_changes = 0; -static unsigned last_frame_number_of_DX8_calls = 0; -static unsigned last_frame_draw_calls = 0; - -static D3DPRESENT_PARAMETERS _PresentParameters; -static DynamicVectorClass _RenderDeviceNameTable; -static DynamicVectorClass _RenderDeviceShortNameTable; -static DynamicVectorClass _RenderDeviceDescriptionTable; - - -typedef IDirect3D8* (WINAPI *Direct3DCreate8Type) (UINT SDKVersion); -Direct3DCreate8Type Direct3DCreate8Ptr = NULL; -HINSTANCE D3D8Lib = NULL; - -DX8_CleanupHook *DX8Wrapper::m_pCleanupHook=NULL; -#ifdef EXTENDED_STATS -DX8_Stats DX8Wrapper::stats; -#endif -/*********************************************************************************** -** -** DX8Wrapper Implementation -** -***********************************************************************************/ - -void Log_DX8_ErrorCode(unsigned res) -{ - char tmp[256]=""; - - HRESULT new_res=D3DXGetErrorStringA( - res, - tmp, - sizeof(tmp)); - - if (new_res==D3D_OK) { - WWDEBUG_SAY((tmp)); - } - - WWASSERT(0); -} - -void Non_Fatal_Log_DX8_ErrorCode(unsigned res,const char * file,int line) -{ - char tmp[256]=""; - - HRESULT new_res=D3DXGetErrorStringA( - res, - tmp, - sizeof(tmp)); - - if (new_res==D3D_OK) { - WWDEBUG_SAY(("DX8 Error: %s, File: %s, Line: %d",tmp,file,line)); - } -} - -// TheSuperHackers @info helmutbuhler 14/04/2025 -// Helper function that moves x and y such that the inner rect fits into the outer rect. -// If the inner rect already is in the outer rect, then this does nothing. -// If the inner rect is larger than the outer rect, then the inner rect will be aligned to the top left of the outer rect. -void MoveRectIntoOtherRect(const RECT& inner, const RECT& outer, int* x, int* y) -{ - int dx = 0; - if (inner.right > outer.right) - dx = outer.right-inner.right; - if (inner.left < outer.left) - dx = outer.left-inner.left; - - int dy = 0; - if (inner.bottom > outer.bottom) - dy = outer.bottom-inner.bottom; - if (inner.top < outer.top) - dy = outer.top-inner.top; - - *x += dx; - *y += dy; -} - -#include "../../Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h" - - -bool DX8Wrapper::Set_Any_Render_Device(void) -{ - // Try windowed first - int dev_number = 0; - for (; dev_number < _RenderDeviceNameTable.Count(); dev_number++) { - if (Set_Render_Device(dev_number,-1,-1,-1,1,false)) { - return true; - } - } - - // Then fullscreen - for (dev_number = 0; dev_number < _RenderDeviceNameTable.Count(); dev_number++) { - if (Set_Render_Device(dev_number,-1,-1,-1,0,false)) { - return true; - } - } - - return false; -} - -bool DX8Wrapper::Set_Render_Device -( - const char * dev_name, - int width, - int height, - int bits, - int windowed, - bool resize_window -) -{ - for ( int dev_number = 0; dev_number < _RenderDeviceNameTable.Count(); dev_number++) { - if ( strcmp( dev_name, _RenderDeviceNameTable[dev_number]) == 0) { - return Set_Render_Device( dev_number, width, height, bits, windowed, resize_window ); - } - - if ( strcmp( dev_name, _RenderDeviceShortNameTable[dev_number]) == 0) { - return Set_Render_Device( dev_number, width, height, bits, windowed, resize_window ); - } - } - return false; -} - -void DX8Wrapper::Get_Format_Name(unsigned int format, StringClass *tex_format) -{ - *tex_format="Unknown"; - switch (format) { - case D3DFMT_A8R8G8B8: *tex_format="D3DFMT_A8R8G8B8"; break; - case D3DFMT_R8G8B8: *tex_format="D3DFMT_R8G8B8"; break; - case D3DFMT_A4R4G4B4: *tex_format="D3DFMT_A4R4G4B4"; break; - case D3DFMT_A1R5G5B5: *tex_format="D3DFMT_A1R5G5B5"; break; - case D3DFMT_R5G6B5: *tex_format="D3DFMT_R5G6B5"; break; - case D3DFMT_L8: *tex_format="D3DFMT_L8"; break; - case D3DFMT_A8: *tex_format="D3DFMT_A8"; break; - case D3DFMT_P8: *tex_format="D3DFMT_P8"; break; - case D3DFMT_X8R8G8B8: *tex_format="D3DFMT_X8R8G8B8"; break; - case D3DFMT_X1R5G5B5: *tex_format="D3DFMT_X1R5G5B5"; break; - case D3DFMT_R3G3B2: *tex_format="D3DFMT_R3G3B2"; break; - case D3DFMT_A8R3G3B2: *tex_format="D3DFMT_A8R3G3B2"; break; - case D3DFMT_X4R4G4B4: *tex_format="D3DFMT_X4R4G4B4"; break; - case D3DFMT_A8P8: *tex_format="D3DFMT_A8P8"; break; - case D3DFMT_A8L8: *tex_format="D3DFMT_A8L8"; break; - case D3DFMT_A4L4: *tex_format="D3DFMT_A4L4"; break; - case D3DFMT_V8U8: *tex_format="D3DFMT_V8U8"; break; - case D3DFMT_L6V5U5: *tex_format="D3DFMT_L6V5U5"; break; - case D3DFMT_X8L8V8U8: *tex_format="D3DFMT_X8L8V8U8"; break; - case D3DFMT_Q8W8V8U8: *tex_format="D3DFMT_Q8W8V8U8"; break; - case D3DFMT_V16U16: *tex_format="D3DFMT_V16U16"; break; - case D3DFMT_W11V11U10: *tex_format="D3DFMT_W11V11U10"; break; - case D3DFMT_UYVY: *tex_format="D3DFMT_UYVY"; break; - case D3DFMT_YUY2: *tex_format="D3DFMT_YUY2"; break; - case D3DFMT_DXT1: *tex_format="D3DFMT_DXT1"; break; - case D3DFMT_DXT2: *tex_format="D3DFMT_DXT2"; break; - case D3DFMT_DXT3: *tex_format="D3DFMT_DXT3"; break; - case D3DFMT_DXT4: *tex_format="D3DFMT_DXT4"; break; - case D3DFMT_DXT5: *tex_format="D3DFMT_DXT5"; break; - case D3DFMT_D16_LOCKABLE: *tex_format="D3DFMT_D16_LOCKABLE"; break; - case D3DFMT_D32: *tex_format="D3DFMT_D32"; break; - case D3DFMT_D15S1: *tex_format="D3DFMT_D15S1"; break; - case D3DFMT_D24S8: *tex_format="D3DFMT_D24S8"; break; - case D3DFMT_D16: *tex_format="D3DFMT_D16"; break; - case D3DFMT_D24X8: *tex_format="D3DFMT_D24X8"; break; - case D3DFMT_D24X4S4: *tex_format="D3DFMT_D24X4S4"; break; - default: break; - } -} - -void DX8Wrapper::Resize_And_Position_Window() -{ - // Get the current dimensions of the 'render area' of the window - RECT rect = { 0 }; - ::GetClientRect (_Hwnd, &rect); - - // Is the window the correct size for this resolution? - if ((rect.right-rect.left) != ResolutionWidth || - (rect.bottom-rect.top) != ResolutionHeight) { - - // Calculate what the main window's bounding rectangle should be to - // accommodate this resolution - rect.left = 0; - rect.top = 0; - rect.right = ResolutionWidth; - rect.bottom = ResolutionHeight; - DWORD dwstyle = ::GetWindowLong (_Hwnd, GWL_STYLE); - AdjustWindowRect (&rect, dwstyle, FALSE); - int width = rect.right-rect.left; - int height = rect.bottom-rect.top; - - // Resize the window to fit this resolution - if (!IsWindowed) - { - ::SetWindowPos(_Hwnd, HWND_TOPMOST, 0, 0, width, height, SWP_NOSIZE | SWP_NOMOVE); - - DEBUG_LOG(("Window resized to w:%d h:%d", width, height)); - } - else - { - // TheSuperHackers @feature helmutbuhler 14/04/2025 - // Center the window in the workarea of the monitor it is on. - MONITORINFO mi = {sizeof(MONITORINFO)}; - GetMonitorInfo(MonitorFromWindow(_Hwnd, MONITOR_DEFAULTTOPRIMARY), &mi); - int left = (mi.rcWork.left + mi.rcWork.right - width) / 2; - int top = (mi.rcWork.top + mi.rcWork.bottom - height) / 2; - - // TheSuperHackers @feature helmutbuhler 14/04/2025 - // Move the window to try fit it into the monitor area, if one of its dimensions is larger than the work area. - // Otherwise align the window to the top left edges, if it is even larger than the monitor area. - RECT rectClient; - rectClient.left = left - rect.left; - rectClient.top = top - rect.top; - rectClient.right = rectClient.left + ResolutionWidth; - rectClient.bottom = rectClient.top + ResolutionHeight; - MoveRectIntoOtherRect(rectClient, mi.rcMonitor, &left, &top); - - ::SetWindowPos (_Hwnd, NULL, left, top, width, height, SWP_NOZORDER); - - DEBUG_LOG(("Window positioned to x:%d y:%d, resized to w:%d h:%d", left, top, width, height)); - } - } -} - -bool DX8Wrapper::Set_Render_Device(int dev, int width, int height, int bits, int windowed, - bool resize_window,bool reset_device, bool restore_assets) -{ - WWASSERT(IsInitted); - WWASSERT(dev >= -1); - WWASSERT(dev < _RenderDeviceNameTable.Count()); - - /* - ** If user has never selected a render device, start out with device 0 - */ - if ((CurRenderDevice == -1) && (dev == -1)) { - CurRenderDevice = 0; - } else if (dev != -1) { - CurRenderDevice = dev; - } - - /* - ** If user doesn't want to change res, set the res variables to match the - ** current resolution - */ - if (width != -1) ResolutionWidth = width; - if (height != -1) ResolutionHeight = height; - - // Initialize Render2DClass Screen Resolution - Render2DClass::Set_Screen_Resolution( RectClass( 0, 0, ResolutionWidth, ResolutionHeight ) ); - - if (bits != -1) BitDepth = bits; - if (windowed != -1) IsWindowed = (windowed != 0); - DX8Wrapper_IsWindowed = IsWindowed; - - WWDEBUG_SAY(("Attempting Set_Render_Device: name: %s (%s:%s), width: %d, height: %d, windowed: %d", - _RenderDeviceNameTable[CurRenderDevice].str(),_RenderDeviceDescriptionTable[CurRenderDevice].Get_Driver_Name(), - _RenderDeviceDescriptionTable[CurRenderDevice].Get_Driver_Version(),ResolutionWidth,ResolutionHeight,(IsWindowed ? 1 : 0))); - -#ifdef _WINDOWS - // PWG 4/13/2000 - changed so that if you say to resize the window it resizes - // regardless of whether its windowed or not as OpenGL resizes its self around - // the caption and edges of the window type you provide, so its important to - // push the client area to be the size you really want. - // if ( resize_window && windowed ) { - if (resize_window) { - Resize_And_Position_Window(); - } -#endif - //must be either resetting existing device or creating a new one. - WWASSERT(reset_device || D3DDevice == NULL); - - /* - ** Initialize values for D3DPRESENT_PARAMETERS members. - */ - ::ZeroMemory(&_PresentParameters, sizeof(D3DPRESENT_PARAMETERS)); - - _PresentParameters.BackBufferWidth = ResolutionWidth; - _PresentParameters.BackBufferHeight = ResolutionHeight; - _PresentParameters.BackBufferCount = IsWindowed ? 1 : 2; - - _PresentParameters.MultiSampleType = D3DMULTISAMPLE_NONE; - _PresentParameters.SwapEffect = IsWindowed ? D3DSWAPEFFECT_DISCARD : D3DSWAPEFFECT_FLIP; // Shouldn't this be D3DSWAPEFFECT_FLIP? - _PresentParameters.hDeviceWindow = _Hwnd; - _PresentParameters.Windowed = IsWindowed; - - _PresentParameters.EnableAutoDepthStencil = TRUE; // Driver will attempt to match Z-buffer depth - _PresentParameters.Flags=0; // We're not going to lock the backbuffer - - _PresentParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; - _PresentParameters.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT; - - /* - ** Set up the buffer formats. Several issues here: - ** - if in windowed mode, the backbuffer must use the current display format. - ** - the depth buffer must use - */ - if (IsWindowed) { - - D3DDISPLAYMODE desktop_mode; - ::ZeroMemory(&desktop_mode, sizeof(D3DDISPLAYMODE)); - D3DInterface->GetAdapterDisplayMode( CurRenderDevice, &desktop_mode ); - - DisplayFormat=_PresentParameters.BackBufferFormat = desktop_mode.Format; - - // In windowed mode, define the bitdepth from desktop mode (as it can't be changed) - switch (_PresentParameters.BackBufferFormat) { - case D3DFMT_X8R8G8B8: - case D3DFMT_A8R8G8B8: - case D3DFMT_R8G8B8: BitDepth=32; break; - case D3DFMT_A4R4G4B4: - case D3DFMT_A1R5G5B5: - case D3DFMT_R5G6B5: BitDepth=16; break; - case D3DFMT_L8: - case D3DFMT_A8: - case D3DFMT_P8: BitDepth=8; break; - default: - // Unknown backbuffer format probably means the device can't do windowed - return false; - } - - if (BitDepth==32 && D3DInterface->CheckDeviceType(0,D3DDEVTYPE_HAL,desktop_mode.Format,D3DFMT_A8R8G8B8, TRUE) == D3D_OK) - { //promote 32-bit modes to include destination alpha - _PresentParameters.BackBufferFormat = D3DFMT_A8R8G8B8; - } - - /* - ** Find a appropriate Z buffer - */ - if (!Find_Z_Mode(DisplayFormat,_PresentParameters.BackBufferFormat,&_PresentParameters.AutoDepthStencilFormat)) - { - // If opening 32 bit mode failed, try 16 bit, even if the desktop happens to be 32 bit - if (BitDepth==32) { - BitDepth=16; - _PresentParameters.BackBufferFormat=D3DFMT_R5G6B5; - if (!Find_Z_Mode(_PresentParameters.BackBufferFormat,_PresentParameters.BackBufferFormat,&_PresentParameters.AutoDepthStencilFormat)) { - _PresentParameters.AutoDepthStencilFormat=D3DFMT_UNKNOWN; - } - } - else { - _PresentParameters.AutoDepthStencilFormat=D3DFMT_UNKNOWN; - } - } - - } else { - - /* - ** Try to find a mode that matches the user's desired bit-depth. - */ - Find_Color_And_Z_Mode(ResolutionWidth,ResolutionHeight,BitDepth,&DisplayFormat, - &_PresentParameters.BackBufferFormat,&_PresentParameters.AutoDepthStencilFormat); - } - - /* - ** Time to actually create the device. - */ - if (_PresentParameters.AutoDepthStencilFormat==D3DFMT_UNKNOWN) { - if (BitDepth==32) { - _PresentParameters.AutoDepthStencilFormat=D3DFMT_D32; - } - else { - _PresentParameters.AutoDepthStencilFormat=D3DFMT_D16; - } - } - - StringClass displayFormat; - StringClass backbufferFormat; - - Get_Format_Name(DisplayFormat,&displayFormat); - Get_Format_Name(_PresentParameters.BackBufferFormat,&backbufferFormat); - - WWDEBUG_SAY(("Using Display/BackBuffer Formats: %s/%s",displayFormat.str(),backbufferFormat.str())); - - bool ret; - - if (reset_device) - { - WWDEBUG_SAY(("DX8Wrapper::Set_Render_Device is resetting the device.")); - ret = Reset_Device(restore_assets); //reset device without restoring data - we're likely switching out of the app. - } - else - ret = Create_Device(); - - WWDEBUG_SAY(("Reset/Create_Device done, reset_device=%d, restore_assets=%d", reset_device, restore_assets)); - - return ret; -} - -bool DX8Wrapper::Set_Next_Render_Device(void) -{ - int new_dev = (CurRenderDevice + 1) % _RenderDeviceNameTable.Count(); - return Set_Render_Device(new_dev); -} - -bool DX8Wrapper::Toggle_Windowed(void) -{ -#ifdef WW3D_DX8 - // State OK? - assert (IsInitted); - if (IsInitted) { - - // Get information about the current render device's resolutions - const RenderDeviceDescClass &render_device = Get_Render_Device_Desc (); - const DynamicVectorClass &resolutions = render_device.Enumerate_Resolutions (); - - // Loop through all the resolutions supported by the current device. - // If we aren't currently running under one of these resolutions, - // then we should probably to the closest resolution before - // toggling the windowed state. - int curr_res = -1; - for (int res = 0; - (res < resolutions.Count ()) && (curr_res == -1); - res ++) { - - // Is this the resolution we are looking for? - if ((resolutions[res].Width == ResolutionWidth) && - (resolutions[res].Height == ResolutionHeight) && - (resolutions[res].BitDepth == BitDepth)) { - curr_res = res; - } - } - - if (curr_res == -1) { - - // We don't match any of the standard resolutions, - // so set the first resolution and toggle the windowed state. - return Set_Device_Resolution (resolutions[0].Width, - resolutions[0].Height, - resolutions[0].BitDepth, - !IsWindowed, true); - } else { - - // Toggle the windowed state - return Set_Device_Resolution (-1, -1, -1, !IsWindowed, true); - } - } -#endif //WW3D_DX8 - - return false; -} - -void DX8Wrapper::Set_Swap_Interval(int swap) -{ - switch (swap) { - case 0: _PresentParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; break; - case 1: _PresentParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_ONE ; break; - case 2: _PresentParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_TWO; break; - case 3: _PresentParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_THREE; break; - default: _PresentParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_ONE ; break; - } - - WWDEBUG_SAY(("DX8Wrapper::Set_Swap_Interval is resetting the device.")); - Reset_Device(); -} - -int DX8Wrapper::Get_Swap_Interval(void) -{ - return _PresentParameters.FullScreen_PresentationInterval; -} - -bool DX8Wrapper::Has_Stencil(void) -{ - bool has_stencil = (_PresentParameters.AutoDepthStencilFormat == D3DFMT_D24S8 || - _PresentParameters.AutoDepthStencilFormat == D3DFMT_D24X4S4); - return has_stencil; -} - -int DX8Wrapper::Get_Render_Device_Count(void) -{ - return _RenderDeviceNameTable.Count(); - -} -int DX8Wrapper::Get_Render_Device(void) -{ - assert(IsInitted); - return CurRenderDevice; -} - -const RenderDeviceDescClass & DX8Wrapper::Get_Render_Device_Desc(int deviceidx) -{ - WWASSERT(IsInitted); - - if ((deviceidx == -1) && (CurRenderDevice == -1)) { - CurRenderDevice = 0; - } - - // if the device index is -1 then we want the current device - if (deviceidx == -1) { - WWASSERT(CurRenderDevice >= 0); - WWASSERT(CurRenderDevice < _RenderDeviceNameTable.Count()); - return _RenderDeviceDescriptionTable[CurRenderDevice]; - } - - // We can only ask for multiple device information if the devices - // have been detected. - WWASSERT(deviceidx >= 0); - WWASSERT(deviceidx < _RenderDeviceNameTable.Count()); - return _RenderDeviceDescriptionTable[deviceidx]; -} - -const char * DX8Wrapper::Get_Render_Device_Name(int device_index) -{ - device_index = device_index % _RenderDeviceShortNameTable.Count(); - return _RenderDeviceShortNameTable[device_index]; -} - -bool DX8Wrapper::Set_Device_Resolution(int width,int height,int bits,int windowed, bool resize_window) -{ - if (D3DDevice != NULL) { - - if (width != -1) { - _PresentParameters.BackBufferWidth = ResolutionWidth = width; - } - if (height != -1) { - _PresentParameters.BackBufferHeight = ResolutionHeight = height; - } - if (resize_window) - { - Resize_And_Position_Window(); - } -#pragma message("TODO: support changing windowed status and changing the bit depth") - WWDEBUG_SAY(("DX8Wrapper::Set_Device_Resolution is resetting the device.")); - return Reset_Device(); - } else { - return false; - } -} - -void DX8Wrapper::Get_Device_Resolution(int & set_w,int & set_h,int & set_bits,bool & set_windowed) -{ - WWASSERT(IsInitted); - - set_w = ResolutionWidth; - set_h = ResolutionHeight; - set_bits = BitDepth; - set_windowed = IsWindowed; - - return ; -} - -void DX8Wrapper::Get_Render_Target_Resolution(int & set_w,int & set_h,int & set_bits,bool & set_windowed) -{ - WWASSERT(IsInitted); - - if (CurrentRenderTarget != NULL) { - D3DSURFACE_DESC info; - CurrentRenderTarget->GetDesc (&info); - - set_w = info.Width; - set_h = info.Height; - set_bits = BitDepth; // should we get the actual bit depth of the target? - set_windowed = IsWindowed; // this doesn't really make sense for render targets (shouldn't matter)... - - } else { - Get_Device_Resolution (set_w, set_h, set_bits, set_windowed); - } - - return ; -} - -bool DX8Wrapper::Registry_Save_Render_Device( const char * sub_key ) -{ - int width, height, depth; - bool windowed; - Get_Device_Resolution(width, height, depth, windowed); - return Registry_Save_Render_Device(sub_key, CurRenderDevice, ResolutionWidth, ResolutionHeight, BitDepth, IsWindowed, TextureBitDepth); -} - -bool DX8Wrapper::Registry_Save_Render_Device( const char *sub_key, int device, int width, int height, int depth, bool windowed, int texture_depth) -{ - RegistryClass * registry = W3DNEW RegistryClass( sub_key ); - WWASSERT( registry ); - - if ( !registry->Is_Valid() ) { - delete registry; - WWDEBUG_SAY(( "Error getting Registry" )); - return false; - } - - registry->Set_String( VALUE_NAME_RENDER_DEVICE_NAME, - _RenderDeviceShortNameTable[device] ); - registry->Set_Int( VALUE_NAME_RENDER_DEVICE_WIDTH, width ); - registry->Set_Int( VALUE_NAME_RENDER_DEVICE_HEIGHT, height ); - registry->Set_Int( VALUE_NAME_RENDER_DEVICE_DEPTH, depth ); - registry->Set_Int( VALUE_NAME_RENDER_DEVICE_WINDOWED, windowed ); - registry->Set_Int( VALUE_NAME_RENDER_DEVICE_TEXTURE_DEPTH, texture_depth ); - - delete registry; - return true; -} - -bool DX8Wrapper::Registry_Load_Render_Device( const char * sub_key, bool resize_window ) -{ - char name[ 200 ]; - int width,height,depth,windowed; - - if ( Registry_Load_Render_Device( sub_key, - name, - sizeof(name), - width, - height, - depth, - windowed, - TextureBitDepth) && - (*name != 0)) - { - WWDEBUG_SAY(( "Device %s (%d X %d) %d bit windowed:%d", name,width,height,depth,windowed)); - - if (TextureBitDepth==16 || TextureBitDepth==32) { -// WWDEBUG_SAY(( "Texture depth %d", TextureBitDepth)); - } else { - WWDEBUG_SAY(( "Invalid texture depth %d, switching to 16 bits", TextureBitDepth)); - TextureBitDepth=16; - } - - if ( Set_Render_Device( name, width,height,depth,windowed, resize_window ) != true) { - return Set_Any_Render_Device(); - } - - return true; - } - - WWDEBUG_SAY(( "Error getting Registry" )); - - return Set_Any_Render_Device(); -} - -bool DX8Wrapper::Registry_Load_Render_Device( const char * sub_key, char *device, int device_len, int &width, int &height, int &depth, int &windowed, int &texture_depth) -{ - RegistryClass registry( sub_key ); - - if ( registry.Is_Valid() ) { - registry.Get_String( VALUE_NAME_RENDER_DEVICE_NAME, - device, device_len); - - width = registry.Get_Int( VALUE_NAME_RENDER_DEVICE_WIDTH, -1 ); - height = registry.Get_Int( VALUE_NAME_RENDER_DEVICE_HEIGHT, -1 ); - depth = registry.Get_Int( VALUE_NAME_RENDER_DEVICE_DEPTH, -1 ); - windowed = registry.Get_Int( VALUE_NAME_RENDER_DEVICE_WINDOWED, -1 ); - texture_depth = registry.Get_Int( VALUE_NAME_RENDER_DEVICE_TEXTURE_DEPTH, -1 ); - return true; - } - *device=0; - width=-1; - height=-1; - depth=-1; - windowed=-1; - texture_depth=-1; - return false; -} - - -bool DX8Wrapper::Find_Color_And_Z_Mode(int resx,int resy,int bitdepth,D3DFORMAT * set_colorbuffer,D3DFORMAT * set_backbuffer,D3DFORMAT * set_zmode) -{ - static D3DFORMAT _formats16[] = - { - D3DFMT_R5G6B5, - D3DFMT_X1R5G5B5, - D3DFMT_A1R5G5B5 - }; - - static D3DFORMAT _formats32[] = - { - D3DFMT_A8R8G8B8, - D3DFMT_X8R8G8B8, - D3DFMT_R8G8B8, - }; - - /* - ** Select the table that we're going to use to search for a valid backbuffer format - */ - D3DFORMAT * format_table = NULL; - int format_count = 0; - - if (BitDepth == 16) { - format_table = _formats16; - format_count = sizeof(_formats16) / sizeof(D3DFORMAT); - } else { - format_table = _formats32; - format_count = sizeof(_formats32) / sizeof(D3DFORMAT); - } - - /* - ** now search for a valid format - */ - bool found = false; - unsigned int mode = 0; - - int format_index=0; - for (; format_index < format_count; format_index++) { - found |= Find_Color_Mode(format_table[format_index],resx,resy,&mode); - if (found) break; - } - - if (!found) { - return false; - } else { - *set_backbuffer=*set_colorbuffer = format_table[format_index]; - } - - if (bitdepth==32 && *set_colorbuffer == D3DFMT_X8R8G8B8 && D3DInterface->CheckDeviceType(0,D3DDEVTYPE_HAL,*set_colorbuffer,D3DFMT_A8R8G8B8, TRUE) == D3D_OK) - { //promote 32-bit modes to include destination alpha when supported - *set_backbuffer = D3DFMT_A8R8G8B8; - } - - /* - ** We found a backbuffer format, now find a zbuffer format - */ - return Find_Z_Mode(*set_colorbuffer,*set_backbuffer, set_zmode); -}; - - -// find the resolution mode with at least resx,resy with the highest supported -// refresh rate -bool DX8Wrapper::Find_Color_Mode(D3DFORMAT colorbuffer, int resx, int resy, UINT *mode) -{ - UINT i,j,modemax; - UINT rx,ry; - D3DDISPLAYMODE dmode; - ::ZeroMemory(&dmode, sizeof(D3DDISPLAYMODE)); - - rx=(unsigned int) resx; - ry=(unsigned int) resy; - - bool found=false; - - modemax=D3DInterface->GetAdapterModeCount(D3DADAPTER_DEFAULT); - - i=0; - - while (iEnumAdapterModes(D3DADAPTER_DEFAULT, i, &dmode); - if (dmode.Width==rx && dmode.Height==ry && dmode.Format==colorbuffer) { - WWDEBUG_SAY(("Found valid color mode. Width = %d Height = %d Format = %d",dmode.Width,dmode.Height,dmode.Format)); - found=true; - } - i++; - } - - i--; // this is the first valid mode - - // no match - if (!found) { - WWDEBUG_SAY(("Failed to find a valid color mode")); - return false; - } - - // go to the highest refresh rate in this mode - bool stillok=true; - - j=i; - while (jEnumAdapterModes(D3DADAPTER_DEFAULT, j, &dmode); - if (dmode.Width==rx && dmode.Height==ry && dmode.Format==colorbuffer) - stillok=true; else stillok=false; - j++; - } - - if (stillok==false) *mode=j-2; - else *mode=i; - - return true; -} - -// Helper function to find a Z buffer mode for the colorbuffer -// Will look for greatest Z precision -bool DX8Wrapper::Find_Z_Mode(D3DFORMAT colorbuffer,D3DFORMAT backbuffer, D3DFORMAT *zmode) -{ - //MW: Swapped the next 2 tests so that Stencil modes get tested first. - if (Test_Z_Mode(colorbuffer,backbuffer,D3DFMT_D24S8)) - { - *zmode=D3DFMT_D24S8; - WWDEBUG_SAY(("Found zbuffer mode D3DFMT_D24S8")); - return true; - } - - if (Test_Z_Mode(colorbuffer,backbuffer,D3DFMT_D32)) - { - *zmode=D3DFMT_D32; - WWDEBUG_SAY(("Found zbuffer mode D3DFMT_D32")); - return true; - } - - if (Test_Z_Mode(colorbuffer,backbuffer,D3DFMT_D24X8)) - { - *zmode=D3DFMT_D24X8; - WWDEBUG_SAY(("Found zbuffer mode D3DFMT_D24X8")); - return true; - } - - if (Test_Z_Mode(colorbuffer,backbuffer,D3DFMT_D24X4S4)) - { - *zmode=D3DFMT_D24X4S4; - WWDEBUG_SAY(("Found zbuffer mode D3DFMT_D24X4S4")); - return true; - } - - if (Test_Z_Mode(colorbuffer,backbuffer,D3DFMT_D16)) - { - *zmode=D3DFMT_D16; - WWDEBUG_SAY(("Found zbuffer mode D3DFMT_D16")); - return true; - } - - if (Test_Z_Mode(colorbuffer,backbuffer,D3DFMT_D15S1)) - { - *zmode=D3DFMT_D15S1; - WWDEBUG_SAY(("Found zbuffer mode D3DFMT_D15S1")); - return true; - } - - // can't find a match - WWDEBUG_SAY(("Failed to find a valid zbuffer mode")); - return false; -} - -bool DX8Wrapper::Test_Z_Mode(D3DFORMAT colorbuffer,D3DFORMAT backbuffer, D3DFORMAT zmode) -{ - // See if we have this mode first - if (FAILED(D3DInterface->CheckDeviceFormat(D3DADAPTER_DEFAULT,WW3D_DEVTYPE, - colorbuffer,D3DUSAGE_DEPTHSTENCIL,D3DRTYPE_SURFACE,zmode))) - { - WWDEBUG_SAY(("CheckDeviceFormat failed. Colorbuffer format = %d Zbufferformat = %d",colorbuffer,zmode)); - return false; - } - - // Then see if it matches the color buffer - if(FAILED(D3DInterface->CheckDepthStencilMatch(D3DADAPTER_DEFAULT, WW3D_DEVTYPE, - colorbuffer,backbuffer,zmode))) - { - WWDEBUG_SAY(("CheckDepthStencilMatch failed. Colorbuffer format = %d Backbuffer format = %d Zbufferformat = %d",colorbuffer,backbuffer,zmode)); - return false; - } - return true; -} - - -void DX8Wrapper::Reset_Statistics() -{ - matrix_changes = 0; - material_changes = 0; - vertex_buffer_changes = 0; - index_buffer_changes = 0; - light_changes = 0; - texture_changes = 0; - render_state_changes =0; - texture_stage_state_changes =0; - draw_calls =0; - - number_of_DX8_calls = 0; - last_frame_matrix_changes = 0; - last_frame_material_changes = 0; - last_frame_vertex_buffer_changes = 0; - last_frame_index_buffer_changes = 0; - last_frame_light_changes = 0; - last_frame_texture_changes = 0; - last_frame_render_state_changes = 0; - last_frame_texture_stage_state_changes = 0; - last_frame_number_of_DX8_calls = 0; - last_frame_draw_calls =0; -} - -void DX8Wrapper::Begin_Statistics() -{ - matrix_changes=0; - material_changes=0; - vertex_buffer_changes=0; - index_buffer_changes=0; - light_changes=0; - texture_changes = 0; - render_state_changes =0; - texture_stage_state_changes =0; - number_of_DX8_calls=0; - draw_calls=0; -} - -void DX8Wrapper::End_Statistics() -{ - last_frame_matrix_changes=matrix_changes; - last_frame_material_changes=material_changes; - last_frame_vertex_buffer_changes=vertex_buffer_changes; - last_frame_index_buffer_changes=index_buffer_changes; - last_frame_light_changes=light_changes; - last_frame_texture_changes = texture_changes; - last_frame_render_state_changes = render_state_changes; - last_frame_texture_stage_state_changes = texture_stage_state_changes; - last_frame_number_of_DX8_calls=number_of_DX8_calls; - last_frame_draw_calls=draw_calls; -} - -unsigned DX8Wrapper::Get_Last_Frame_Matrix_Changes() { return last_frame_matrix_changes; } -unsigned DX8Wrapper::Get_Last_Frame_Material_Changes() { return last_frame_material_changes; } -unsigned DX8Wrapper::Get_Last_Frame_Vertex_Buffer_Changes() { return last_frame_vertex_buffer_changes; } -unsigned DX8Wrapper::Get_Last_Frame_Index_Buffer_Changes() { return last_frame_index_buffer_changes; } -unsigned DX8Wrapper::Get_Last_Frame_Light_Changes() { return last_frame_light_changes; } -unsigned DX8Wrapper::Get_Last_Frame_Texture_Changes() { return last_frame_texture_changes; } -unsigned DX8Wrapper::Get_Last_Frame_Render_State_Changes() { return last_frame_render_state_changes; } -unsigned DX8Wrapper::Get_Last_Frame_Texture_Stage_State_Changes() { return last_frame_texture_stage_state_changes; } -unsigned DX8Wrapper::Get_Last_Frame_DX8_Calls() { return last_frame_number_of_DX8_calls; } -unsigned DX8Wrapper::Get_Last_Frame_Draw_Calls() { return last_frame_draw_calls; } -unsigned long DX8Wrapper::Get_FrameCount(void) {return FrameCount;} - -void DX8_Assert() -{ - WWASSERT(DX8Wrapper::_Get_D3D8()); - DX8_THREAD_ASSERT(); -} - -void DX8Wrapper::Begin_Scene(void) -{ - DX8_THREAD_ASSERT(); - -#if ENABLE_EMBEDDED_BROWSER - DX8WebBrowser::Update(); -#endif - - DX8CALL(BeginScene()); - - DX8WebBrowser::Update(); -} - -void DX8Wrapper::End_Scene(bool flip_frames) -{ - DX8_THREAD_ASSERT(); - DX8CALL(EndScene()); - - DX8WebBrowser::Render(0); - - if (flip_frames) { - DX8_Assert(); - HRESULT hr; - { - WWPROFILE("DX8Device::Present()"); - hr=_Get_D3D_Device8()->Present(NULL, NULL, NULL, NULL); - } - - number_of_DX8_calls++; - - if (SUCCEEDED(hr)) { -#ifdef EXTENDED_STATS - if (stats.m_sleepTime) { - ::Sleep(stats.m_sleepTime); - } -#endif - IsDeviceLost=false; - FrameCount++; - } - else { - IsDeviceLost=true; - } - - // If the device was lost we need to check for cooperative level and possibly reset the device - if (hr==D3DERR_DEVICELOST) { - hr=_Get_D3D_Device8()->TestCooperativeLevel(); - if (hr==D3DERR_DEVICENOTRESET) { - WWDEBUG_SAY(("DX8Wrapper::End_Scene is resetting the device.")); - Reset_Device(); - } - else { - // Sleep it not active - ThreadClass::Sleep_Ms(200); - } - } - else { - DX8_ErrorCode(hr); - } - } - - // Each frame, release all of the buffers and textures. - Set_Vertex_Buffer(NULL); - Set_Index_Buffer(NULL,0); - for (int i=0;iGet_Max_Textures_Per_Pass();++i) Set_Texture(i,NULL); - Set_Material(NULL); -} - - -void DX8Wrapper::Flip_To_Primary(void) -{ - // If we are fullscreen and the current frame is odd then we need - // to force a page flip to ensure that the first buffer in the flipping - // chain is the one visible. - if (!IsWindowed) { - DX8_Assert(); - - int numBuffers = (_PresentParameters.BackBufferCount + 1); - int visibleBuffer = (FrameCount % numBuffers); - int flipCount = ((numBuffers - visibleBuffer) % numBuffers); - int resetAttempts = 0; - - while ((flipCount > 0) && (resetAttempts < 3)) { - HRESULT hr = _Get_D3D_Device8()->TestCooperativeLevel(); - - if (FAILED(hr)) { - WWDEBUG_SAY(("TestCooperativeLevel Failed!")); - - if (D3DERR_DEVICELOST == hr) { - IsDeviceLost=true; - WWDEBUG_SAY(("DEVICELOST: Cannot flip to primary.")); - return; - } - IsDeviceLost=false; - - if (D3DERR_DEVICENOTRESET == hr) { - WWDEBUG_SAY(("DEVICENOTRESET")); - Reset_Device(); - resetAttempts++; - } - } else { - WWDEBUG_SAY(("Flipping: %ld", FrameCount)); - hr = _Get_D3D_Device8()->Present(NULL, NULL, NULL, NULL); - - if (SUCCEEDED(hr)) { - IsDeviceLost=false; - FrameCount++; - WWDEBUG_SAY(("Flip to primary succeeded %ld", FrameCount)); - } - else { - IsDeviceLost=true; - } - } - - --flipCount; - } - } -} - - -void DX8Wrapper::Clear(bool clear_color, bool clear_z_stencil, const Vector3 &color, float dest_alpha, float z, unsigned int stencil) -{ - DX8_THREAD_ASSERT(); - // If we try to clear a stencil buffer which is not there, the entire call will fail - bool has_stencil = ( _PresentParameters.AutoDepthStencilFormat == D3DFMT_D15S1 || - _PresentParameters.AutoDepthStencilFormat == D3DFMT_D24S8 || - _PresentParameters.AutoDepthStencilFormat == D3DFMT_D24X4S4); - - DWORD flags = 0; - if (clear_color) flags |= D3DCLEAR_TARGET; - if (clear_z_stencil) flags |= D3DCLEAR_ZBUFFER; - if (clear_z_stencil && has_stencil) flags |= D3DCLEAR_STENCIL; - if (flags) - { - DX8CALL(Clear(0, NULL, flags, Convert_Color(color,dest_alpha), z, stencil)); - } -} - -void DX8Wrapper::Set_Viewport(CONST D3DVIEWPORT8* pViewport) -{ - DX8_THREAD_ASSERT(); - DX8CALL(SetViewport(pViewport)); -} - -// ---------------------------------------------------------------------------- -// -// Set vertex buffer. A reference to previous vertex buffer is released and -// this one is assigned the current vertex buffer. The DX8 vertex buffer will -// actually be set in Apply() which is called by Draw_Indexed_Triangles(). -// -// ---------------------------------------------------------------------------- - -void DX8Wrapper::Set_Vertex_Buffer(const VertexBufferClass* vb, unsigned stream) -{ - render_state.vba_offset = 0; - render_state.vba_count = 0; - if (render_state.vertex_buffers[stream]) { - render_state.vertex_buffers[stream]->Release_Engine_Ref(); - } - REF_PTR_SET(render_state.vertex_buffers[stream], const_cast(vb)); - if (vb) { - vb->Add_Engine_Ref(); - render_state.vertex_buffer_types[stream] = vb->Type(); - } - else { - render_state.vertex_buffer_types[stream] = BUFFER_TYPE_INVALID; - } - render_state_changed |= VERTEX_BUFFER_CHANGED; -} - -// ---------------------------------------------------------------------------- -// -// Set index buffer. A reference to previous index buffer is released and -// this one is assigned the current index buffer. The DX8 index buffer will -// actually be set in Apply() which is called by Draw_Indexed_Triangles(). -// -// ---------------------------------------------------------------------------- - -void DX8Wrapper::Set_Index_Buffer(const IndexBufferClass* ib,unsigned short index_base_offset) -{ - render_state.iba_offset=0; - if (render_state.index_buffer) { - render_state.index_buffer->Release_Engine_Ref(); - } - REF_PTR_SET(render_state.index_buffer,const_cast(ib)); - render_state.index_base_offset=index_base_offset; - if (ib) { - ib->Add_Engine_Ref(); - render_state.index_buffer_type=ib->Type(); - } - else { - render_state.index_buffer_type=BUFFER_TYPE_INVALID; - } - render_state_changed|=INDEX_BUFFER_CHANGED; -} - -// ---------------------------------------------------------------------------- -// -// Set vertex buffer using dynamic access object. -// -// ---------------------------------------------------------------------------- - -void DX8Wrapper::Set_Vertex_Buffer(const DynamicVBAccessClass& vba_) -{ - // Release all streams (only one stream allowed in the legacy pipeline) - for (int i = 1; i < MAX_VERTEX_STREAMS; ++i) { - DX8Wrapper::Set_Vertex_Buffer(NULL, i); - } - - if (render_state.vertex_buffers[0]) render_state.vertex_buffers[0]->Release_Engine_Ref(); - DynamicVBAccessClass& vba = const_cast(vba_); - render_state.vertex_buffer_types[0] = vba.Get_Type(); - render_state.vba_offset = vba.VertexBufferOffset; - render_state.vba_count = vba.Get_Vertex_Count(); - REF_PTR_SET(render_state.vertex_buffers[0], vba.VertexBuffer); - render_state.vertex_buffers[0]->Add_Engine_Ref(); - render_state_changed |= VERTEX_BUFFER_CHANGED; - render_state_changed |= INDEX_BUFFER_CHANGED; // vba_offset changes so index buffer needs to be reset as well. -} - -// ---------------------------------------------------------------------------- -// -// Set index buffer using dynamic access object. -// -// ---------------------------------------------------------------------------- - -void DX8Wrapper::Set_Index_Buffer(const DynamicIBAccessClass& iba_,unsigned short index_base_offset) -{ - if (render_state.index_buffer) render_state.index_buffer->Release_Engine_Ref(); - - DynamicIBAccessClass& iba=const_cast(iba_); - render_state.index_base_offset=index_base_offset; - render_state.index_buffer_type=iba.Get_Type(); - render_state.iba_offset=iba.IndexBufferOffset; - REF_PTR_SET(render_state.index_buffer,iba.IndexBuffer); - render_state.index_buffer->Add_Engine_Ref(); - render_state_changed|=INDEX_BUFFER_CHANGED; -} - -// ---------------------------------------------------------------------------- -// -// Private function for the special case of rendering polygons from sorting -// index and vertex buffers. -// -// ---------------------------------------------------------------------------- - -void DX8Wrapper::Draw_Sorting_IB_VB( - unsigned primitive_type, - unsigned short start_index, - unsigned short polygon_count, - unsigned short min_vertex_index, - unsigned short vertex_count) -{ - WWASSERT(render_state.vertex_buffer_types[0] == BUFFER_TYPE_SORTING || render_state.vertex_buffer_types[0] == BUFFER_TYPE_DYNAMIC_SORTING); - WWASSERT(render_state.index_buffer_type == BUFFER_TYPE_SORTING || render_state.index_buffer_type == BUFFER_TYPE_DYNAMIC_SORTING); - - // Fill dynamic vertex buffer with sorting vertex buffer vertices - DynamicVBAccessClass dyn_vb_access(BUFFER_TYPE_DYNAMIC_DX8, dynamic_fvf_type, vertex_count); - { - DynamicVBAccessClass::WriteLockClass lock(&dyn_vb_access); - VertexFormatXYZNDUV2* src = static_cast(render_state.vertex_buffers[0])->VertexBuffer; - VertexFormatXYZNDUV2* dest = lock.Get_Formatted_Vertex_Array(); - src += render_state.vba_offset + render_state.index_base_offset + min_vertex_index; - unsigned size = dyn_vb_access.FVF_Info().Get_FVF_Size() * vertex_count / sizeof(unsigned); - unsigned* dest_u = (unsigned*)dest; - unsigned* src_u = (unsigned*)src; - - for (unsigned i = 0; i < size; ++i) { - *dest_u++ = *src_u++; - } - } - - DX8CALL(SetStreamSource( - 0, - static_cast(dyn_vb_access.VertexBuffer)->Get_DX8_Vertex_Buffer(), - dyn_vb_access.FVF_Info().Get_FVF_Size())); - // If using FVF format VB, set the FVF as vertex shader (may not be needed here KM) - unsigned fvf = dyn_vb_access.FVF_Info().Get_FVF(); - if (fvf != 0) { - DX8CALL(SetVertexShader(fvf)); - } - DX8_RECORD_VERTEX_BUFFER_CHANGE(); - - unsigned index_count = 0; - switch (primitive_type) { - case D3DPT_TRIANGLELIST: index_count = polygon_count * 3; break; - case D3DPT_TRIANGLESTRIP: index_count = polygon_count + 2; break; - case D3DPT_TRIANGLEFAN: index_count = polygon_count + 2; break; - default: WWASSERT(0); break; // Unsupported primitive type - } - - // Fill dynamic index buffer with sorting index buffer vertices - DynamicIBAccessClass dyn_ib_access(BUFFER_TYPE_DYNAMIC_DX8, index_count); - { - DynamicIBAccessClass::WriteLockClass lock(&dyn_ib_access); - unsigned short* dest = lock.Get_Index_Array(); - unsigned short* src = NULL; - src = static_cast(render_state.index_buffer)->index_buffer; - src += render_state.iba_offset + start_index; - - for (unsigned short i = 0; i < index_count; ++i) { - unsigned short index = *src++; - index -= min_vertex_index; - WWASSERT(index < vertex_count); - *dest++ = index; - } - } - - DX8CALL(SetIndices( - static_cast(dyn_ib_access.IndexBuffer)->Get_DX8_Index_Buffer(), - dyn_vb_access.VertexBufferOffset)); - DX8_RECORD_INDEX_BUFFER_CHANGE(); - - DX8_RECORD_DRAW_CALLS(); - DX8CALL(DrawIndexedPrimitive( - D3DPT_TRIANGLELIST, - 0, // start vertex - vertex_count, - dyn_ib_access.IndexBufferOffset, - polygon_count)); - - DX8_RECORD_RENDER(polygon_count, vertex_count, render_state.shader); -} - -// ---------------------------------------------------------------------------- -// -// -// -// ---------------------------------------------------------------------------- - -void DX8Wrapper::Draw( - unsigned primitive_type, - unsigned short start_index, - unsigned short polygon_count, - unsigned short min_vertex_index, - unsigned short vertex_count) -{ - if (DrawPolygonLowBoundLimit && DrawPolygonLowBoundLimit>=polygon_count) return; - - DX8_THREAD_ASSERT(); - SNAPSHOT_SAY(("DX8 - draw")); - - Apply_Render_State_Changes(); - - // Debug feature to disable triangle drawing... - if (!_Is_Triangle_Draw_Enabled()) return; - -#ifdef MESH_RENDER_SNAPSHOT_ENABLED - if (WW3D::Is_Snapshot_Activated()) { - unsigned long passes=0; - SNAPSHOT_SAY(("ValidateDevice:")); - HRESULT res=D3DDevice->ValidateDevice(&passes); - switch (res) { - case D3D_OK: - SNAPSHOT_SAY(("OK")); - break; - - case D3DERR_CONFLICTINGTEXTUREFILTER: - SNAPSHOT_SAY(("D3DERR_CONFLICTINGTEXTUREFILTER")); - break; - case D3DERR_CONFLICTINGTEXTUREPALETTE: - SNAPSHOT_SAY(("D3DERR_CONFLICTINGTEXTUREPALETTE")); - break; - case D3DERR_DEVICELOST: - SNAPSHOT_SAY(("D3DERR_DEVICELOST")); - break; - case D3DERR_TOOMANYOPERATIONS: - SNAPSHOT_SAY(("D3DERR_TOOMANYOPERATIONS")); - break; - case D3DERR_UNSUPPORTEDALPHAARG: - SNAPSHOT_SAY(("D3DERR_UNSUPPORTEDALPHAARG")); - break; - case D3DERR_UNSUPPORTEDALPHAOPERATION: - SNAPSHOT_SAY(("D3DERR_UNSUPPORTEDALPHAOPERATION")); - break; - case D3DERR_UNSUPPORTEDCOLORARG: - SNAPSHOT_SAY(("D3DERR_UNSUPPORTEDCOLORARG")); - break; - case D3DERR_UNSUPPORTEDCOLOROPERATION: - SNAPSHOT_SAY(("D3DERR_UNSUPPORTEDCOLOROPERATION")); - break; - case D3DERR_UNSUPPORTEDFACTORVALUE: - SNAPSHOT_SAY(("D3DERR_UNSUPPORTEDFACTORVALUE")); - break; - case D3DERR_UNSUPPORTEDTEXTUREFILTER: - SNAPSHOT_SAY(("D3DERR_UNSUPPORTEDTEXTUREFILTER")); - break; - case D3DERR_WRONGTEXTUREFORMAT: - SNAPSHOT_SAY(("D3DERR_WRONGTEXTUREFORMAT")); - break; - default: - SNAPSHOT_SAY(("UNKNOWN Error")); - break; - } - } -#endif // MESH_RENDER_SHAPSHOT_ENABLED - - - SNAPSHOT_SAY(("DX8 - draw %d polygons (%d vertices)",polygon_count,vertex_count)); - - if (vertex_count < 3) { - min_vertex_index = 0; - switch (render_state.vertex_buffer_types[0]) { - case BUFFER_TYPE_DX8: - case BUFFER_TYPE_SORTING: - vertex_count = render_state.vertex_buffers[0]->Get_Vertex_Count() - render_state.index_base_offset - render_state.vba_offset - min_vertex_index; - break; - case BUFFER_TYPE_DYNAMIC_DX8: - case BUFFER_TYPE_DYNAMIC_SORTING: - vertex_count = render_state.vba_count; - break; - } - } - - switch (render_state.vertex_buffer_types[0]) { - case BUFFER_TYPE_DX8: - case BUFFER_TYPE_DYNAMIC_DX8: - switch (render_state.index_buffer_type) { - case BUFFER_TYPE_DX8: - case BUFFER_TYPE_DYNAMIC_DX8: - { - /* if ((start_index+render_state.iba_offset+polygon_count*3) > render_state.index_buffer->Get_Index_Count()) - { WWASSERT_PRINT(0,"OVERFLOWING INDEX BUFFER"); - ///@todo: MUST FIND OUT WHY THIS HAPPENS WITH LOTS OF PARTICLES ON BIG FIGHT! -MW - break; - }*/ - DX8_RECORD_RENDER(polygon_count, vertex_count, render_state.shader); - DX8_RECORD_DRAW_CALLS(); - DX8CALL(DrawIndexedPrimitive( - (D3DPRIMITIVETYPE)primitive_type, - min_vertex_index, - vertex_count, - start_index + render_state.iba_offset, - polygon_count)); - } - break; - case BUFFER_TYPE_SORTING: - case BUFFER_TYPE_DYNAMIC_SORTING: - WWASSERT_PRINT(0, "VB and IB must of same type (sorting or dx8)"); - break; - case BUFFER_TYPE_INVALID: - WWASSERT(0); - break; - } - break; - case BUFFER_TYPE_SORTING: - case BUFFER_TYPE_DYNAMIC_SORTING: - switch (render_state.index_buffer_type) { - case BUFFER_TYPE_DX8: - case BUFFER_TYPE_DYNAMIC_DX8: - WWASSERT_PRINT(0, "VB and IB must of same type (sorting or dx8)"); - break; - case BUFFER_TYPE_SORTING: - case BUFFER_TYPE_DYNAMIC_SORTING: - Draw_Sorting_IB_VB(primitive_type, start_index, polygon_count, min_vertex_index, vertex_count); - break; - case BUFFER_TYPE_INVALID: - WWASSERT(0); - break; - } - break; - case BUFFER_TYPE_INVALID: - WWASSERT(0); - break; - } -} - -// ---------------------------------------------------------------------------- -// -// -// -// ---------------------------------------------------------------------------- - -void DX8Wrapper::Draw_Triangles( - unsigned buffer_type, - unsigned short start_index, - unsigned short polygon_count, - unsigned short min_vertex_index, - unsigned short vertex_count) -{ - if (buffer_type==BUFFER_TYPE_SORTING || buffer_type==BUFFER_TYPE_DYNAMIC_SORTING) { - SortingRendererClass::Insert_Triangles(start_index,polygon_count,min_vertex_index,vertex_count); - } - else { - Draw(D3DPT_TRIANGLELIST,start_index,polygon_count,min_vertex_index,vertex_count); - } -} - -// ---------------------------------------------------------------------------- -// -// -// -// ---------------------------------------------------------------------------- - -void DX8Wrapper::Draw_Triangles( - unsigned short start_index, - unsigned short polygon_count, - unsigned short min_vertex_index, - unsigned short vertex_count) -{ - Draw(D3DPT_TRIANGLELIST,start_index,polygon_count,min_vertex_index,vertex_count); -} - -// ---------------------------------------------------------------------------- -// -// -// -// ---------------------------------------------------------------------------- - -void DX8Wrapper::Draw_Strip( - unsigned short start_index, - unsigned short polygon_count, - unsigned short min_vertex_index, - unsigned short vertex_count) -{ - Draw(D3DPT_TRIANGLESTRIP,start_index,polygon_count,min_vertex_index,vertex_count); -} - -// ---------------------------------------------------------------------------- -// -// -// -// ---------------------------------------------------------------------------- - -void DX8Wrapper::Apply_Render_State_Changes() -{ - SNAPSHOT_SAY(("DX8Wrapper::Apply_Render_State_Changes()")); - - if (!render_state_changed) return; - if (render_state_changed&SHADER_CHANGED) { - SNAPSHOT_SAY(("DX8 - apply shader")); - render_state.shader.Apply(); - } - - unsigned mask=TEXTURE0_CHANGED; - int i=0; - for (;iGet_Max_Textures_Per_Pass();++i,mask<<=1) - { - if (render_state_changed&mask) - { - SNAPSHOT_SAY(("DX8 - apply texture %d",i)); - - if (render_state.Textures[i]) - { - render_state.Textures[i]->Apply(i); - } - else - { - TextureBaseClass::Apply_Null(i); - } - } - } - - if (render_state_changed&MATERIAL_CHANGED) - { - SNAPSHOT_SAY(("DX8 - apply material")); - VertexMaterialClass* material=const_cast(render_state.material); - if (material) - { - material->Apply(); - } - else VertexMaterialClass::Apply_Null(); - } - - if (render_state_changed&LIGHTS_CHANGED) - { - unsigned mask=LIGHT0_CHANGED; - for (unsigned index=0;index<4;++index,mask<<=1) { - if (render_state_changed&mask) { - SNAPSHOT_SAY(("DX8 - apply light %d",index)); - if (render_state.LightEnable[index]) { -#ifdef MESH_RENDER_SNAPSHOT_ENABLED - if ( WW3D::Is_Snapshot_Activated() ) { - D3DLIGHT8 * light = &(render_state.Lights[index]); - static const char * _light_types[] = { "Unknown", "Point","Spot", "Directional" }; - WWASSERT((light->Type >= 0) && (light->Type <= 3)); - - SNAPSHOT_SAY((" type = %s amb = %4.2f,%4.2f,%4.2f diff = %4.2f,%4.2f,%4.2f spec = %4.2f, %4.2f, %4.2f", - _light_types[light->Type], - light->Ambient.r,light->Ambient.g,light->Ambient.b, - light->Diffuse.r,light->Diffuse.g,light->Diffuse.b, - light->Specular.r,light->Specular.g,light->Specular.b )); - SNAPSHOT_SAY((" pos = %f, %f, %f dir = %f, %f, %f", - light->Position.x, light->Position.y, light->Position.z, - light->Direction.x, light->Direction.y, light->Direction.z )); - } -#endif - - Set_DX8_Light(index,&render_state.Lights[index]); - } - else { - Set_DX8_Light(index,NULL); - SNAPSHOT_SAY((" clearing light to NULL")); - } - } - } - } - - if (render_state_changed&WORLD_CHANGED) { - SNAPSHOT_SAY(("DX8 - apply world matrix")); - _Set_DX8_Transform(D3DTS_WORLD,render_state.world); - } - if (render_state_changed&VIEW_CHANGED) { - SNAPSHOT_SAY(("DX8 - apply view matrix")); - _Set_DX8_Transform(D3DTS_VIEW,render_state.view); - } - if (render_state_changed & VERTEX_BUFFER_CHANGED) { - SNAPSHOT_SAY(("DX8 - apply vb change")); - for (i = 0; i < MAX_VERTEX_STREAMS; ++i) { - if (render_state.vertex_buffers[i]) { - switch (render_state.vertex_buffer_types[i]) {//->Type()) { - case BUFFER_TYPE_DX8: - case BUFFER_TYPE_DYNAMIC_DX8: - DX8CALL(SetStreamSource( - i, - static_cast(render_state.vertex_buffers[i])->Get_DX8_Vertex_Buffer(), - render_state.vertex_buffers[i]->FVF_Info().Get_FVF_Size())); - DX8_RECORD_VERTEX_BUFFER_CHANGE(); - { - // If the VB format is FVF, set the FVF as a vertex shader - unsigned fvf = render_state.vertex_buffers[i]->FVF_Info().Get_FVF(); - if (fvf != 0) { - Set_Vertex_Shader(fvf); - } - } - break; - case BUFFER_TYPE_SORTING: - case BUFFER_TYPE_DYNAMIC_SORTING: - break; - default: - WWASSERT(0); - } - } - else { - DX8CALL(SetStreamSource(i, NULL, 0)); - DX8_RECORD_VERTEX_BUFFER_CHANGE(); - } - } - } - if (render_state_changed&INDEX_BUFFER_CHANGED) { - SNAPSHOT_SAY(("DX8 - apply ib change")); - if (render_state.index_buffer) { - switch (render_state.index_buffer_type) {//->Type()) { - case BUFFER_TYPE_DX8: - case BUFFER_TYPE_DYNAMIC_DX8: - DX8CALL(SetIndices( - static_cast(render_state.index_buffer)->Get_DX8_Index_Buffer(), - render_state.index_base_offset+render_state.vba_offset)); - DX8_RECORD_INDEX_BUFFER_CHANGE(); - break; - case BUFFER_TYPE_SORTING: - case BUFFER_TYPE_DYNAMIC_SORTING: - break; - default: - WWASSERT(0); - } - } - else { - DX8CALL(SetIndices( - NULL, - 0)); - DX8_RECORD_INDEX_BUFFER_CHANGE(); - } - } - - render_state_changed&=((unsigned)WORLD_IDENTITY|(unsigned)VIEW_IDENTITY); - - SNAPSHOT_SAY(("DX8Wrapper::Apply_Render_State_Changes() - finished")); -} - -IDirect3DTexture8 * DX8Wrapper::_Create_DX8_Texture -( - unsigned int width, - unsigned int height, - WW3DFormat format, - MipCountType mip_level_count, - D3DPOOL pool, - bool rendertarget -) -{ - DX8_THREAD_ASSERT(); - DX8_Assert(); - IDirect3DTexture8 *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=D3DXCreateTexture( - DX8Wrapper::_Get_D3D_Device8(), - width, - height, - 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 (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; - } - - // Don't allow any errors in non-render target - // texture creation. - DX8_ErrorCode(D3DXCreateTexture( - DX8Wrapper::_Get_D3D_Device8(), - width, - height, - mip_level_count, - 0, - WW3DFormat_To_D3DFormat(format), - pool, - &texture)); - -// unsigned reduction=WW3D::Get_Texture_Reduction(); -// unsigned level_count=texture->GetLevelCount(); -// if (reduction>=level_count) reduction=level_count-1; -// texture->SetLOD(reduction); - - return texture; -} - -IDirect3DTexture8 * DX8Wrapper::_Create_DX8_Texture -( - const char *filename, - MipCountType mip_level_count -) -{ - DX8_THREAD_ASSERT(); - DX8_Assert(); - IDirect3DTexture8 *texture = NULL; - - // NOTE: If the original image format is not supported as a texture format, it will - // automatically be converted to an appropriate format. - // NOTE: It is possible to get the size and format of the original image file from this - // function as well, so if we later want to second-guess D3DX's format conversion decisions - // we can do so after this function is called.. - unsigned result = D3DXCreateTextureFromFileExA( - _Get_D3D_Device8(), - filename, - D3DX_DEFAULT, - D3DX_DEFAULT, - mip_level_count,//create_mipmaps ? 0 : 1, - 0, - D3DFMT_UNKNOWN, - D3DPOOL_MANAGED, - D3DX_FILTER_BOX, - D3DX_FILTER_BOX, - 0, - NULL, - NULL, - &texture); - - if (result != D3D_OK) { - return MissingTexture::_Get_Missing_Texture(); - } +IDirect3DBaseTexture8 * DX8Wrapper::Textures[MAX_TEXTURE_STAGES]; +RenderStateStruct DX8Wrapper::render_state; +unsigned DX8Wrapper::render_state_changed; - // Make sure texture wasn't paletted! - D3DSURFACE_DESC desc; - texture->GetLevelDesc(0,&desc); - if (desc.Format==D3DFMT_P8) { - texture->Release(); - return MissingTexture::_Get_Missing_Texture(); - } - return texture; -} +bool DX8Wrapper::FogEnable = false; +D3DCOLOR DX8Wrapper::FogColor = 0; -IDirect3DTexture8 * DX8Wrapper::_Create_DX8_Texture -( - IDirect3DSurface8 *surface, - MipCountType mip_level_count -) -{ - DX8_THREAD_ASSERT(); - DX8_Assert(); - IDirect3DTexture8 *texture = NULL; +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; - D3DSURFACE_DESC surface_desc; - ::ZeroMemory(&surface_desc, sizeof(D3DSURFACE_DESC)); - surface->GetDesc(&surface_desc); +unsigned DX8Wrapper::matrix_changes = 0; +unsigned DX8Wrapper::material_changes = 0; +unsigned DX8Wrapper::vertex_buffer_changes = 0; +unsigned DX8Wrapper::index_buffer_changes = 0; +unsigned DX8Wrapper::light_changes = 0; +unsigned DX8Wrapper::texture_changes = 0; +unsigned DX8Wrapper::render_state_changes = 0; +unsigned DX8Wrapper::texture_stage_state_changes = 0; +unsigned DX8Wrapper::draw_calls = 0; +unsigned DX8Wrapper::_MainThreadID = 0; +bool DX8Wrapper::CurrentDX8LightEnables[4]; +bool DX8Wrapper::IsDeviceLost; +int DX8Wrapper::ZBias; +float DX8Wrapper::ZNear; +float DX8Wrapper::ZFar; +Matrix4x4 DX8Wrapper::ProjectionMatrix; +Matrix4x4 DX8Wrapper::DX8Transforms[D3DTS_WORLD+1]; - // This function will create a texture with a different (but similar) format if the surface is - // not in a supported texture format. - WW3DFormat format=D3DFormat_To_WW3DFormat(surface_desc.Format); - texture = _Create_DX8_Texture(surface_desc.Width, surface_desc.Height, format, mip_level_count); +DX8Caps* DX8Wrapper::CurrentCaps = 0; - // Copy the surface to the texture - IDirect3DSurface8 *tex_surface = NULL; - texture->GetSurfaceLevel(0, &tex_surface); - DX8_ErrorCode(D3DXLoadSurfaceFromSurface(tex_surface, NULL, NULL, surface, NULL, NULL, D3DX_FILTER_BOX, 0)); - tex_surface->Release(); +// Hack test... this disables rendering of batches of too few polygons. +unsigned DX8Wrapper::DrawPolygonLowBoundLimit=0; - // Create mipmaps if needed - if (mip_level_count!=MIP_LEVELS_1) - { - DX8_ErrorCode(D3DXFilterTexture(texture, NULL, 0, D3DX_FILTER_BOX)); - } +D3DADAPTER_IDENTIFIER8 DX8Wrapper::CurrentAdapterIdentifier; - return texture; +unsigned long DX8Wrapper::FrameCount = 0; -} +bool _DX8SingleThreaded = false; -IDirect3DSurface8 * DX8Wrapper::_Create_DX8_Surface(unsigned int width, unsigned int height, WW3DFormat format) -{ - DX8_THREAD_ASSERT(); - DX8_Assert(); +unsigned number_of_DX8_calls = 0; +static unsigned last_frame_matrix_changes = 0; +static unsigned last_frame_material_changes = 0; +static unsigned last_frame_vertex_buffer_changes = 0; +static unsigned last_frame_index_buffer_changes = 0; +static unsigned last_frame_light_changes = 0; +static unsigned last_frame_texture_changes = 0; +static unsigned last_frame_render_state_changes = 0; +static unsigned last_frame_texture_stage_state_changes = 0; +static unsigned last_frame_number_of_DX8_calls = 0; +static unsigned last_frame_draw_calls = 0; - IDirect3DSurface8 *surface = NULL; +static D3DPRESENT_PARAMETERS _PresentParameters; +static DynamicVectorClass _RenderDeviceNameTable; +static DynamicVectorClass _RenderDeviceShortNameTable; +static DynamicVectorClass _RenderDeviceDescriptionTable; - // Paletted surfaces not supported! - WWASSERT(format!=D3DFMT_P8); - DX8CALL(CreateImageSurface(width, height, WW3DFormat_To_D3DFormat(format), &surface)); +typedef IDirect3D8* (WINAPI *Direct3DCreate8Type) (UINT SDKVersion); +Direct3DCreate8Type Direct3DCreate8Ptr = NULL; +HINSTANCE D3D8Lib = NULL; - return surface; -} +DX8_CleanupHook *DX8Wrapper::m_pCleanupHook=NULL; +#ifdef EXTENDED_STATS +DX8_Stats DX8Wrapper::stats; +#endif +/*********************************************************************************** +** +** DX8Wrapper Implementation +** +***********************************************************************************/ -IDirect3DSurface8 * DX8Wrapper::_Create_DX8_Surface(const char *filename_) +void Log_DX8_ErrorCode(unsigned res) { - DX8_THREAD_ASSERT(); - DX8_Assert(); - - // Note: Since there is no "D3DXCreateSurfaceFromFile" and no "GetSurfaceInfoFromFile" (the - // latter is supposed to be added to D3DX in a future version), we create a texture from the - // file (w/o mipmaps), check that its surface is equal to the original file data (which it - // will not be if the file is not in a texture-supported format or size). If so, copy its - // surface (we might be able to just get its surface and add a ref to it but I'm not sure so - // I'm not going to risk it) and release the texture. If not, create a surface according to - // the file data and use D3DXLoadSurfaceFromFile. This is a horrible hack, but it saves us - // having to write file loaders. Will fix this when D3DX provides us with the right functions. - // Create a surface the size of the file image data - IDirect3DSurface8 *surface = NULL; + char tmp[256]=""; - { + HRESULT new_res=D3DXGetErrorStringA( + res, + tmp, + sizeof(tmp)); - file_auto_ptr myfile(_TheFileFactory,filename_); - // If file not found, create a surface with missing texture in it - - if (!myfile->Is_Available()) { - // If file not found, try the dds format - // else create a surface with missing texture in it - char compressed_name[200]; - strncpy(compressed_name,filename_, ARRAY_SIZE(compressed_name)); - compressed_name[ARRAY_SIZE(compressed_name)-1] = '\0'; - char *ext = strstr(compressed_name, "."); - if ( ext && (strlen(ext)==4) && - ( (ext[1] == 't') || (ext[1] == 'T') ) && - ( (ext[2] == 'g') || (ext[2] == 'G') ) && - ( (ext[3] == 'a') || (ext[3] == 'A') ) ) { - ext[1]='d'; - ext[2]='d'; - ext[3]='s'; - } - file_auto_ptr myfile2(_TheFileFactory,compressed_name); - if (!myfile2->Is_Available()) - return MissingTexture::_Create_Missing_Surface(); - } + if (new_res==D3D_OK) { + WWDEBUG_SAY((tmp)); } - StringClass filename_string(filename_,true); - surface=TextureLoader::Load_Surface_Immediate( - filename_string, - WW3D_FORMAT_UNKNOWN, - true); - return surface; -} - - -/*********************************************************************************************** - * DX8Wrapper::_Update_Texture -- Copies a texture from system memory to video memory * - * * - * * - * * - * * - * INPUT: * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 4/26/2001 hy : Created. * - *=============================================================================================*/ -void DX8Wrapper::_Update_Texture(TextureClass *system, TextureClass *video) -{ - WWASSERT(system); - WWASSERT(video); - WWASSERT(system->Get_Pool()==TextureClass::POOL_SYSTEMMEM); - WWASSERT(video->Get_Pool()==TextureClass::POOL_DEFAULT); - DX8CALL(UpdateTexture(system->Peek_D3D_Base_Texture(),video->Peek_D3D_Base_Texture())); + WWASSERT(0); } -void DX8Wrapper::Compute_Caps(WW3DFormat display_format) +void Non_Fatal_Log_DX8_ErrorCode(unsigned res,const char * file,int line) { - DX8_THREAD_ASSERT(); - DX8_Assert(); - delete CurrentCaps; - CurrentCaps=new DX8Caps(_Get_D3D8(),D3DDevice,display_format,Get_Current_Adapter_Identifier()); -} + char tmp[256]=""; + HRESULT new_res=D3DXGetErrorStringA( + res, + tmp, + sizeof(tmp)); -void DX8Wrapper::Set_Light(unsigned index, const D3DLIGHT8* light) -{ - if (light) { - render_state.Lights[index]=*light; - render_state.LightEnable[index]=true; - } - else { - render_state.LightEnable[index]=false; + if (new_res==D3D_OK) { + WWDEBUG_SAY(("DX8 Error: %s, File: %s, Line: %d",tmp,file,line)); } - render_state_changed|=(LIGHT0_CHANGED< outer.right) + dx = outer.right-inner.right; + if (inner.left < outer.left) + dx = outer.left-inner.left; - light.Get_Diffuse(&temp); - temp*=light.Get_Intensity(); - dlight.Diffuse.r=temp.X; - dlight.Diffuse.g=temp.Y; - dlight.Diffuse.b=temp.Z; - dlight.Diffuse.a=1.0f; - - light.Get_Specular(&temp); - temp*=light.Get_Intensity(); - dlight.Specular.r=temp.X; - dlight.Specular.g=temp.Y; - dlight.Specular.b=temp.Z; - dlight.Specular.a=1.0f; - - light.Get_Ambient(&temp); - temp*=light.Get_Intensity(); - dlight.Ambient.r=temp.X; - dlight.Ambient.g=temp.Y; - dlight.Ambient.b=temp.Z; - dlight.Ambient.a=1.0f; - - temp=light.Get_Position(); - dlight.Position=*(D3DVECTOR*) &temp; - - light.Get_Spot_Direction(temp); - dlight.Direction=*(D3DVECTOR*) &temp; - - dlight.Range=light.Get_Attenuation_Range(); - dlight.Falloff=light.Get_Spot_Exponent(); - dlight.Theta=light.Get_Spot_Angle(); - dlight.Phi=light.Get_Spot_Angle(); - - // Inverse linear light 1/(1+D) - double a,b; - light.Get_Far_Attenuation_Range(a,b); - dlight.Attenuation0=1.0f; - if (fabs(a-b)<1e-5) - // if the attenuation range is too small assume uniform with cutoff - dlight.Attenuation1=0.0f; - else - // this will cause the light to drop to half intensity at the first far attenuation - dlight.Attenuation1=(float) 1.0/a; - dlight.Attenuation2=0.0f; + int dy = 0; + if (inner.bottom > outer.bottom) + dy = outer.bottom-inner.bottom; + if (inner.top < outer.top) + dy = outer.top-inner.top; - Set_Light(index,&dlight); + *x += dx; + *y += dy; } +#include "../../Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h" + + // ---------------------------------------------------------------------------- // // Set the light environment. This is a lighting model which used up to four @@ -2302,15 +446,47 @@ DX8Wrapper::Create_Render_Target (int width, int height, bool alpha) } -void -DX8Wrapper::Set_Render_Target -(TextureClass * texture) +//void +//DX8Wrapper::Set_Render_Target +//(TextureClass * texture) +//{ +// WWASSERT(texture != NULL); +// SurfaceClass * surf = texture->Get_Surface_Level(); +// WWASSERT(surf != NULL); +// Set_Render_Target(surf->Peek_D3D_Surface()); +// REF_PTR_RELEASE(surf); +//} + +/*! + * 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); + 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 @@ -2344,91 +520,238 @@ 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 (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) + if (DefaultRenderTarget != NULL) { - DX8CALL(SetRenderTarget (DefaultRenderTarget, depth_buffer)); - DefaultRenderTarget->Release (); + 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) + if (CurrentRenderTarget != NULL) { - CurrentRenderTarget->Release (); + CurrentRenderTarget->Release(); CurrentRenderTarget = NULL; } - } - else if (render_target != CurrentRenderTarget) + 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) + if (DefaultRenderTarget == NULL) { - DX8CALL(GetRenderTarget (&DefaultRenderTarget)); + DX8CALL(GetRenderTarget(&DefaultRenderTarget)); } // // Release our hold on the old "current" render target // - if (CurrentRenderTarget != NULL) + if (CurrentRenderTarget != NULL) { - CurrentRenderTarget->Release (); + CurrentRenderTarget->Release(); CurrentRenderTarget = NULL; } + if (CurrentDepthBuffer != NULL) + { + CurrentDepthBuffer->Release(); + CurrentDepthBuffer = NULL; + } + // // Keep a copy of the current render target (for housekeeping) // CurrentRenderTarget = render_target; - WWASSERT (CurrentRenderTarget != NULL); - if (CurrentRenderTarget != NULL) + WWASSERT(CurrentRenderTarget != NULL); + if (CurrentRenderTarget != NULL) { - CurrentRenderTarget->AddRef (); + CurrentRenderTarget->AddRef(); // // 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 ; + 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 +} IDirect3DSwapChain8 * DX8Wrapper::Create_Additional_Swap_Chain (HWND render_window) diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h index f3af7a9f259..e39aff48165 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h @@ -357,6 +357,35 @@ 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, @@ -448,9 +477,12 @@ class DX8Wrapper */ static TextureClass * Create_Render_Target (int width, int height, bool alpha=false); - static void Set_Render_Target (TextureBaseClass * texture); - static void Set_Render_Target (IDirect3DSurface8 *render_target); - static void Set_Render_Target (IDirect3DSwapChain8 *swap_chain); + static void Set_Render_Target_With_Z(TextureClass* texture, ZTextureClass* ztexture = NULL); + + 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(IDirect3DSwapChain8* swap_chain); static bool Is_Render_To_Texture(void) { return IsRenderToTexture; } // shader system udpates KJM v @@ -641,7 +673,9 @@ 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 ef95a7f6ad0..914d664eb04 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/texproject.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/texproject.cpp @@ -1111,45 +1111,56 @@ bool TexProjectClass::Compute_Ortho_Projection *=============================================================================================*/ bool TexProjectClass::Compute_Texture ( - RenderObjClass * model, - SpecialRenderInfoClass * context + RenderObjClass* model, + SpecialRenderInfoClass* context ) { - if ((model == NULL) || (context == NULL)) + if ((model == NULL) || (context == NULL)) { return false; } /* ** Render to texture */ - TextureClass * rtarget = Peek_Render_Target(); + TextureClass* rtarget = NULL; + ZTextureClass* ztarget = NULL; - if (rtarget != 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 */ Configure_Camera(context->Camera); - + /* ** Render the object */ - Vector3 color(0.0f,0.0f,0.0f); + Vector3 color(0.0f, 0.0f, 0.0f); if (Get_Flag(ADDITIVE) == false) { - color.Set(1.0f,1.0f,1.0f); + color.Set(1.0f, 1.0f, 1.0f); } - WW3D::Begin_Render(true,true,color); - WW3D::Render(*model,*context); + 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); + DX8Wrapper::Set_Render_Target((IDirect3DSurface8*)NULL); } @@ -1218,12 +1229,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; } diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/texproject.h b/Generals/Code/Libraries/Source/WWVegas/WW3D2/texproject.h index 994fec44321..d37d28eaa90 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/texproject.h +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/texproject.h @@ -58,7 +58,7 @@ class SpecialRenderInfoClass; class RenderObjClass; class MaterialPassClass; class SurfaceClass; - +class ZTextureClass; /** @@ -156,7 +156,7 @@ class TexProjectClass : public ProjectorClass, public CullableClass, public Mult bool Needs_Render_Target(void); void Set_Render_Target(TextureClass * render_target); - TextureClass * Peek_Render_Target(void); + TextureClass* Peek_Render_Target(TextureClass** rtarget = NULL, ZTextureClass** ztarget = NULL); bool Compute_Texture(RenderObjClass * model,SpecialRenderInfoClass * context); @@ -213,7 +213,8 @@ class TexProjectClass : public ProjectorClass, public CullableClass, public Mult 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. diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/texture.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/texture.cpp index 2ddbdb085e6..1abc2ef03e0 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/texture.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/texture.cpp @@ -1,5 +1,5 @@ /* -** Command & Conquer Generals(tm) +** Command & Conquer Generals Zero Hour(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify @@ -24,15 +24,19 @@ * * * $Archive:: /Commando/Code/ww3d2/texture.cpp $* * * - * $Author:: Jani_p $* + * $Org Author:: Steve_t $* * * - * $Modtime:: 8/29/01 7:06p $* + * Author : Kenny Mitchell * * * - * $Revision:: 65 $* + * $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 * + * FileListTextureClass::Load_Frame_Surface -- Load source texture * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #include "texture.h" @@ -52,6 +56,13 @@ #include "dx8caps.h" #include "dx8texman.h" #include "meshmatdesc.h" +#include "texturethumbnail.h" +#include "wwprofile.h" + + //#pragma optimize("", off) + //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes") + +const unsigned DEFAULT_INACTIVATION_TIME = 20000; /* ** Definitions of static members: @@ -59,337 +70,207 @@ static unsigned unused_texture_id; -// ---------------------------------------------------------------------------- - -static int Calculate_Texture_Memory_Usage(const TextureClass* texture,int red_factor=0) -{ - // Set performance statistics - - int size=0; - IDirect3DTexture8* d3d_texture=const_cast(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) - { - Dirty=true; - DX8TextureTrackerClass *track=W3DNEW 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) - : - 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) +//********************************************************************************************** +//! Base texture class destructor +/*! KJM +*/ +TextureBaseClass::~TextureBaseClass(void) { - 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; - } - - WWASSERT_PRINT(name && name[0], "TextureClass CTor: NULL or empty texture name"); - int len=strlen(name); - for (int i=0;iRelease(); + D3DTexture = NULL; } - LastAccessed=WW3D::Get_Sync_Time(); + + DX8TextureManagerClass::Remove(this); } -// ---------------------------------------------------------------------------- -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) + + +//********************************************************************************************** +//! Invalidate old unused textures +/*! +*/ +void TextureBaseClass::Invalidate_Old_Unused_Textures(unsigned invalidation_time_override) { - 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; + // (gth) If thumbnails are not enabled, then we don't run this code. + if (WW3D::Get_Thumbnail_Enabled() == false) { + return; } - - D3DTexture = DX8Wrapper::_Create_DX8_Texture(surface->Peek_D3D_Surface(), mip_level_count); - LastAccessed=WW3D::Get_Sync_Time(); -} -// ---------------------------------------------------------------------------- + // 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; -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) -{ - 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) + 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()) { - 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; - } + 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; - LastAccessed=WW3D::Get_Sync_Time(); + 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; + } + } + } + } } -// ---------------------------------------------------------------------------- -TextureClass::~TextureClass(void) + + + +//********************************************************************************************** +//! Invalidate this texture +/*! +*/ +void TextureBaseClass::Invalidate() { - TextureLoadTaskClass::Release_Instance(TextureLoadTask); - TextureLoadTask=NULL; + if (TextureLoadTask) { + return; + } + if (ThumbnailLoadTask) { + return; + } - 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); -} -// ---------------------------------------------------------------------------- + Initialized = false; -void TextureClass::Init() -{ - // If the texture has already been initialised we should exit now - if (Initialized) return; + LastAccessed = WW3D::Get_Sync_Time(); + /* was battlefield version// If the texture has already been initialised we should exit now + if (Initialized) return; - TextureLoader::Add_Load_Task(this); - LastAccessed=WW3D::Get_Sync_Time(); -} + WWPROFILE(("TextureClass::Init()")); -void TextureClass::Invalidate() -{ - // Don't invalidate procedural textures - if (IsProcedural) return; + // If the texture has recently been inactivated, increase the inactivation time (this texture obviously + // should not have been inactivated yet). - // Don't invalidate missing texture - if (Is_Missing_Texture()) return; + if (InactivationTime && LastInactivationSyncTime) { + if ((WW3D::Get_Sync_Time()-LastInactivationSyncTime)Release(); - D3DTexture = NULL; - } + if (ThumbnailLoadTask) + { + return; + } + + // Don't invalidate procedural textures + if (IsProcedural) + { + return; + } + + if (D3DTexture) + { + D3DTexture->Release(); + D3DTexture = NULL; + } - if (!WW3D::Is_Texturing_Enabled()) { - Initialized=true; - D3DTexture=0; - } - else if (WW3D::Get_Thumbnail_Enabled()==false || MipLevelCount==MIP_LEVELS_1) - { - Initialized=true; - D3DTexture=0; - TextureLoader::Request_High_Priority_Loading(this,MipLevelCount); - } - else { Initialized=false; - Load_Locked_Surface(); - } + + LastAccessed=WW3D::Get_Sync_Time();*/ } //********************************************************************************************** //! Returns a pointer to the d3d texture -/*! +/*! */ -IDirect3DBaseTexture8 * TextureClass::Peek_D3D_Base_Texture() const -{ - LastAccessed=WW3D::Get_Sync_Time(); - return D3DTexture; +IDirect3DBaseTexture8* TextureBaseClass::Peek_D3D_Base_Texture() const +{ + LastAccessed = WW3D::Get_Sync_Time(); + return D3DTexture; } //********************************************************************************************** //! 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. - LastAccessed=WW3D::Get_Sync_Time(); - + LastAccessed = WW3D::Get_Sync_Time(); + if (D3DTexture != NULL) { D3DTexture->Release(); } @@ -399,262 +280,241 @@ 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; + D3DTexture = 0; TextureLoader::Request_Thumbnail(this); - Initialized=false; + 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(); - - if(D3DTexture == missing_texture) + IDirect3DBaseTexture8* missing_texture = MissingTexture::_Get_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) -{ - 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(); + return flag; } -// ---------------------------------------------------------------------------- -void TextureClass::Get_Level_Description(SurfaceClass::SurfaceDescription &surface_desc, unsigned int level) +//********************************************************************************************** +//! Set texture name +/*! +*/ +void TextureBaseClass::Set_Texture_Name(const char* name) { - 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; + Name = name; } -// ---------------------------------------------------------------------------- -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 { - if (MipLevelCount==MIP_LEVELS_1) return 0; + // 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(); - if (MipLevelCount && reduction>MipLevelCount) { - reduction=MipLevelCount; + 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; + int total_locked_surface_size = 0; - HashTemplateIterator ite(WW3DAssetManager::Get_Instance()->Texture_Hash()); + 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(); - total_locked_surface_size+=tex->Get_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; + int total_texture_size = 0; - HashTemplateIterator ite(WW3DAssetManager::Get_Instance()->Texture_Hash()); + 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(); - total_texture_size+=tex->Get_Texture_Memory_Usage(); + TextureBaseClass* tex = ite.Peek_Value(); + total_texture_size += tex->Get_Texture_Memory_Usage(); } return 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; + int total_texture_size = 0; - HashTemplateIterator ite(WW3DAssetManager::Get_Instance()->Texture_Hash()); + 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()) { - total_texture_size+=tex->Get_Texture_Memory_Usage(); + 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; + int total_texture_size = 0; - HashTemplateIterator ite(WW3DAssetManager::Get_Instance()->Texture_Hash()); + 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()) { - total_texture_size+=tex->Get_Texture_Memory_Usage(); + 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; + int texture_count = 0; - HashTemplateIterator ite(WW3DAssetManager::Get_Instance()->Texture_Hash()); + 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++; } @@ -663,14 +523,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; + int texture_count = 0; - HashTemplateIterator ite(WW3DAssetManager::Get_Instance()->Texture_Hash()); + 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++; } } @@ -678,16 +545,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; + int texture_count = 0; - HashTemplateIterator ite(WW3DAssetManager::Get_Instance()->Texture_Hash()); + 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++; } } @@ -695,159 +566,615 @@ 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; + int texture_count = 0; - HashTemplateIterator ite(WW3DAssetManager::Get_Instance()->Texture_Hash()); + 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) + +/************************************************************************* +** 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) { - 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); -} -*/ + 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; + } -// Utility functions -TextureClass* Load_Texture(ChunkLoadClass & cload) -{ - // Assume failure - TextureClass *newtex = NULL; + 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); + } - char name[256]; - if (cload.Open_Chunk () && (cload.Cur_Chunk_ID () == W3D_CHUNK_TEXTURE)) + 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(); +} - 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(); +// ---------------------------------------------------------------------------- +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; } - cload.Close_Chunk(); + // 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; + } - /* - ** Get the texture from the asset manager - */ - if (hastexinfo) + WWASSERT_PRINT(name && name[0], "TextureClass CTor: NULL or empty texture name"); + int len = strlen(name); + for (int i = 0; i < len; ++i) + { + if (name[i] == '+') { + IsLightmap = true; - MipCountType mipcount; + // 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; + } + } + Set_Texture_Name(name); + Set_Full_Path(full_path); + WWASSERT(name[0] != '\0'); + if (!WW3D::Is_Texturing_Enabled()) + { + Initialized = true; + Poke_Texture(NULL); + } - bool no_lod = ((texinfo.Attributes & W3DTEXTURE_NO_LOD) == W3DTEXTURE_NO_LOD); + // Find original size from the thumbnail (but don't create thumbnail texture yet!) + ThumbnailClass* thumb = ThumbnailManagerClass::Peek_Thumbnail_Instance_From_Any_Manager(Get_Full_Path()); + if (thumb) + { + Width = thumb->Get_Original_Texture_Width(); + Height = thumb->Get_Original_Texture_Height(); + if (MipLevelCount != MIP_LEVELS_1) { + MipLevelCount = (MipCountType)thumb->Get_Original_Texture_Mip_Level_Count(); + } + } - if (no_lod) - { - mipcount = MIP_LEVELS_1; - } - else - { - switch (texinfo.Attributes & W3DTEXTURE_MIP_LEVELS_MASK) { + LastAccessed = WW3D::Get_Sync_Time(); - case W3DTEXTURE_MIP_LEVELS_ALL: - mipcount = MIP_LEVELS_ALL; - break; + // 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(); + } + } +} - case W3DTEXTURE_MIP_LEVELS_2: - mipcount = MIP_LEVELS_2; - break; +// ---------------------------------------------------------------------------- +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; - case W3DTEXTURE_MIP_LEVELS_3: - mipcount = MIP_LEVELS_3; - break; + 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; + } - case W3DTEXTURE_MIP_LEVELS_4: - mipcount = MIP_LEVELS_4; - break; + Poke_Texture + ( + DX8Wrapper::_Create_DX8_Texture + ( + surface->Peek_D3D_Surface(), + mip_level_count + ) + ); + LastAccessed = WW3D::Get_Sync_Time(); +} - default: - WWASSERT (false); - mipcount = MIP_LEVELS_ALL; - break; - } - } - newtex = WW3DAssetManager::Get_Instance()->Get_Texture (name, mipcount); +// ---------------------------------------------------------------------------- +TextureClass::TextureClass(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); + 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; + } - switch (texinfo.Attributes & W3DTEXTURE_TYPE_MASK) - { + LastAccessed = WW3D::Get_Sync_Time(); +} - case W3DTEXTURE_TYPE_COLORMAP: - // Do nothing. - break; +//********************************************************************************************** +//! Initialise the texture +/*! +*/ +void TextureClass::Init() +{ + // If the texture has already been initialised we should exit now + if (Initialized) return; - case W3DTEXTURE_TYPE_BUMPMAP: - { - TextureClass *releasetex = newtex; + WWPROFILE("TextureClass::Init"); - // 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; - } + // 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) < InactivationTime) + { + ExtendedInactivationTime = 3 * InactivationTime; + } + LastInactivationSyncTime = 0; + } - default: - WWASSERT (false); - break; - } - } else { - newtex = WW3DAssetManager::Get_Instance()->Get_Texture(name); + if (!Peek_D3D_Base_Texture()) + { + if (!WW3D::Get_Thumbnail_Enabled() || MipLevelCount == MIP_LEVELS_1) + { + // if (MipLevelCount==MIP_LEVELS_1) { + TextureLoader::Request_Foreground_Loading(this); + } + else + { + WW3DFormat format = TextureFormat; + Load_Locked_Surface(); + TextureFormat = format; } + } - WWASSERT(newtex); + if (!Initialized) + { + TextureLoader::Request_Background_Loading(this); } - // Return a pointer to the new texture - return newtex; + LastAccessed = WW3D::Get_Sync_Time(); } -// Utility function used by Save_Texture -void setup_texture_attributes(TextureClass * tex, W3dTextureInfoStruct * texinfo) +//********************************************************************************************** +//! Apply new surface to texture +/*! +*/ +void TextureClass::Apply_New_Surface +( + IDirect3DBaseTexture8* d3d_texture, + bool initialized, + bool disable_auto_invalidation +) { - texinfo->Attributes = 0; + 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); + 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; i < Peek_D3D_Texture()->GetLevelCount(); ++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; @@ -855,18 +1182,18 @@ void setup_texture_attributes(TextureClass * tex, W3dTextureInfoStruct * texinfo } -void Save_Texture(TextureClass * texture,ChunkSaveClass & csave) +void Save_Texture(TextureClass* texture, ChunkSaveClass& csave) { - const char * filename; + const char* filename; W3dTextureInfoStruct texinfo; - memset(&texinfo,0,sizeof(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.Write(filename, strlen(filename) + 1); csave.End_Chunk(); if ((texinfo.Attributes != 0) || (texinfo.AnimType != 0) || (texinfo.FrameCount != 0)) { @@ -876,18 +1203,711 @@ void Save_Texture(TextureClass * texture,ChunkSaveClass & csave) } } -// ---------------------------------------------------------------------------- -BumpmapTextureClass::BumpmapTextureClass(TextureClass* texture) - : -// TextureClass(texture->Get_Width(),texture->Get_Height(),texture->Get_Textur4e_Format(),MIP_LEVELS_1) - TextureClass(TextureLoader::Generate_Bumpmap(texture)) +/*! + * 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) { -// D3DTexture=TextureLoader::Generate_Bumpmap(texture); -// TextureLoader:::Generage_Bumpmap + 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; } -BumpmapTextureClass::~BumpmapTextureClass() +//********************************************************************************************** +//! Get texture memory usage +/*! +*/ +unsigned ZTextureClass::Get_Texture_Memory_Usage() const { + int size = 0; + if (!Peek_D3D_Texture()) return 0; + for (unsigned i = 0; i < Peek_D3D_Texture()->GetLevelCount(); ++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; i < len; ++i) + { + if (name[i] == '+') + { + IsLightmap = true; + + // 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; + } + } + Set_Texture_Name(name); + Set_Full_Path(full_path); + WWASSERT(name[0] != '\0'); + if (!WW3D::Is_Texturing_Enabled()) + { + Initialized = true; + Poke_Texture(NULL); + } + + // Find original size from the thumbnail (but don't create thumbnail texture yet!) + ThumbnailClass* thumb = ThumbnailManagerClass::Peek_Thumbnail_Instance_From_Any_Manager(Get_Full_Path()); + if (thumb) + { + Width = thumb->Get_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; i < len; ++i) + { + if (name[i] == '+') + { + IsLightmap = true; + + // 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; + } + } + Set_Texture_Name(name); + Set_Full_Path(full_path); + WWASSERT(name[0] != '\0'); + if (!WW3D::Is_Texturing_Enabled()) + { + Initialized = true; + Poke_Texture(NULL); + } + + // Find original size from the thumbnail (but don't create thumbnail texture yet!) + ThumbnailClass* thumb = ThumbnailManagerClass::Peek_Thumbnail_Instance_From_Any_Manager(Get_Full_Path()); + if (thumb) + { + Width = thumb->Get_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 index 7c6a4b36371..d1cf4f0e94d 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/texture.h +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/texture.h @@ -1,5 +1,5 @@ /* -** Command & Conquer Generals(tm) +** Command & Conquer Generals Zero Hour(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify @@ -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: * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -48,221 +53,432 @@ #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; + +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 texture class. For legacy reasons it contains some +** 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 W3DMPO, public RefCountClass +class TextureClass : public TextureBaseClass { W3DMPO_GLUE(TextureClass) + // friend DX8Wrapper; - friend class DX8TextureTrackerClass; //(gth) so it can call Poke_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); - - // Create texture from a surface. - TextureClass( - SurfaceClass *surface, - MipCountType mip_level_count=MIP_LEVELS_ALL); - - TextureClass(IDirect3DTexture8* d3d_texture); - - virtual TexAssetType Get_Asset_Type() const { return TEX_REGULAR; } - - virtual ~TextureClass(void); - - // 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); - - // 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; - } - - // 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); - - TextureFilterClass& Get_Filter() { return Filter; } - - // Get the surface of one of the mipmap levels (defaults to highest-resolution one) - SurfaceClass *Get_Surface_Level(unsigned int level = 0); - - // 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 - unsigned Get_Texture_Memory_Usage() const; - bool Is_Initialized() const { return Initialized; } - bool Is_Lightmap() const { return IsLightmap; } - bool Is_Procedural() const { return IsProcedural; } - - 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(); - - 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); - - // This utility function processes the texture reduction (used during rendering) - void Invalidate(); - - IDirect3DTexture8 *Peek_D3D_Texture() const { return (IDirect3DTexture8 *)Peek_D3D_Base_Texture(); } - - // 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; }; - - unsigned Get_Reduction() const; - WW3DFormat Get_Texture_Format() const { return TextureFormat; } - bool Is_Compression_Allowed() const { return IsCompressionAllowed; } - - protected: - void Poke_Texture(IDirect3DBaseTexture8* tex) { D3DTexture = tex; } - - // Apply this texture's settings into D3D - virtual void Apply(unsigned int stage); - void Load_Locked_Surface(); - - void Init(); +public: - // Apply a Null texture's settings into D3D - static void Apply_Null(unsigned int stage); + // 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; +}; - // State not contained in the Direct3D texture object: - 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 + ); - // Direct3D texture object - IDirect3DBaseTexture8 *D3DTexture; - bool Initialized; + WW3DZFormat Get_Texture_Format() const { return DepthStencilTextureFormat; } - // Name - StringClass Name; - StringClass FullPath; + virtual TexAssetType Get_Asset_Type() const { return TEX_REGULAR; } - // Unique id - unsigned texture_id; + virtual void Init() {} - // 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. + // 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 - // For debug purposes the texture sets this true if it is a lightmap texture - bool IsLightmap; - bool IsProcedural; - bool IsCompressionAllowed; + virtual void Apply(unsigned int stage); - mutable unsigned LastAccessed; - WW3DFormat TextureFormat; + IDirect3DSurface8* Get_D3D_Surface_Level(unsigned int level = 0); + virtual unsigned Get_Texture_Memory_Usage() const; - int Width; - int Height; +private: - // Support for self-managed textures + WW3DZFormat DepthStencilTextureFormat; +}; - PoolType Pool; - bool Dirty; +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; +TextureClass* Load_Texture(ChunkLoadClass& cload); +void Save_Texture(TextureClass* texture, ChunkSaveClass& csave); #endif //TEXTURE_H diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/textureloader.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/textureloader.cpp index 341d8e4c450..5d4e4ca4572 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/textureloader.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/textureloader.cpp @@ -1,5 +1,5 @@ /* -** Command & Conquer Generals(tm) +** Command & Conquer Generals Zero Hour(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify @@ -16,6 +16,28 @@ ** 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" @@ -38,264 +60,462 @@ #include "texturethumbnail.h" #include "ddsfile.h" #include "bitmaphandler.h" +#include "wwprofile.h" + + + //#pragma optimize("", off) + //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes") + +bool TextureLoader::TextureLoadSuspended; +int TextureLoader::TextureInactiveOverrideTime = 0; -static TextureLoadTaskClass* LoadListHead; -static TextureLoadTaskClass* DeferredListHead; -static TextureLoadTaskClass* FinishedListHead; -static TextureLoadTaskClass* ThumbnailListHead; -static TextureLoadTaskClass* DeleteTaskListHead; +#define USE_MANAGED_TEXTURES -TextureLoadTaskClass* TextureLoadTaskClass::FreeTaskListHead; +//////////////////////////////////////////////////////////////////////////////// +// +// TextureLoadTaskListClass implementation +// +//////////////////////////////////////////////////////////////////////////////// -static bool Is_Format_Compressed(WW3DFormat texture_format,bool allow_compression) +TextureLoadTaskListClass::TextureLoadTaskListClass(void) + : Root() { - // Verify that the user isn't requesting compressed texture without hardware support + Root.Next = Root.Prev = &Root; +} - 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; - } +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; } - // 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); + // otherwise, grab first task and remove it. + TextureLoadTaskClass* task = (TextureLoadTaskClass*)Root.Next; + Remove(task); + return task; - return compressed; } -// ---------------------------------------------------------------------------- +TextureLoadTaskClass* TextureLoadTaskListClass::Pop_Back(void) +{ + // exit early if list is empty + if (Is_Empty()) { + return 0; + } -static CriticalSectionClass mutex; -static class LoaderThreadClass : public ThreadClass + // 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) { - TextureLoadTaskClass* Get_Task_From_Load_List(); + 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); +} + - static void Add_Task_To_Finished_List(TextureLoadTaskClass* 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: - LoaderThreadClass() : ThreadClass() {} +#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; - static void Add_Task_To_Load_List(TextureLoadTaskClass* task); + unsigned width = dds_file.Get_Width(0); + unsigned height = dds_file.Get_Height(0); + unsigned mips = dds_file.Get_Mip_Level_Count(); -} thread; + // 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; level < mips; ++level) { + IDirect3DSurface8* d3d_surface = NULL; + WWASSERT(d3d_texture); + DX8_ErrorCode(d3d_texture->GetSurfaceLevel(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(!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(); - ThumbnailClass::Deinit(); + 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) +void TextureLoader::Validate_Texture_Size +( + unsigned& width, + unsigned& height, + unsigned& depth +) { - const D3DCAPS8& dx8caps=DX8Wrapper::Get_Current_Caps()->Get_DX8_Caps(); + const D3DCAPS8& dx8caps = DX8Wrapper::Get_Current_Caps()->Get_DX8_Caps(); unsigned poweroftwowidth = 1; - while (poweroftwowidth < width) { + while (poweroftwowidth < width) + { poweroftwowidth <<= 1; } unsigned poweroftwoheight = 1; - while (poweroftwoheight < height) { + while (poweroftwoheight < height) + { poweroftwoheight <<= 1; } -// unsigned size = MAX (width, height); -// unsigned poweroftwosize = 1; -// while (poweroftwosize < size) { -// poweroftwosize <<= 1; -// } + unsigned poweroftwodepth = 1; + while (poweroftwodepth < depth) + { + poweroftwodepth <<= 1; + } - if (poweroftwowidth>dx8caps.MaxTextureWidth) { - poweroftwowidth=dx8caps.MaxTextureWidth; + if (poweroftwowidth > dx8caps.MaxTextureWidth) + { + poweroftwowidth = dx8caps.MaxTextureWidth; + } + if (poweroftwoheight > dx8caps.MaxTextureHeight) + { + poweroftwoheight = dx8caps.MaxTextureHeight; } - if (poweroftwoheight>dx8caps.MaxTextureHeight) { - poweroftwoheight=dx8caps.MaxTextureHeight; + if (poweroftwodepth > dx8caps.MaxVolumeExtent) + { + poweroftwodepth = dx8caps.MaxVolumeExtent; } - if (poweroftwowidth>poweroftwoheight) { - while (poweroftwowidth/poweroftwoheight>8) { - poweroftwoheight*=2; + if (poweroftwowidth > poweroftwoheight) + { + while (poweroftwowidth / poweroftwoheight > 8) + { + poweroftwoheight *= 2; } } - else { - while (poweroftwoheight/poweroftwowidth>8) { - poweroftwowidth*=2; + else + { + while (poweroftwoheight / poweroftwowidth > 8) + { + poweroftwowidth *= 2; } } -// width = height = poweroftwosize; - width=poweroftwowidth; - height=poweroftwoheight; + 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); -IDirect3DTexture8* TextureLoader::Load_Thumbnail(const StringClass& filename,WW3DFormat texture_format) -{ - ThumbnailClass* thumb=ThumbnailClass::Peek_Instance(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; - if (texture_format==WW3D_FORMAT_UNKNOWN) { - dest_format=Get_Valid_Texture_Format(WW3D_FORMAT_A8R8G8B8,false); // no compressed formats please + 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); + 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); + unsigned level = 0; + D3DLOCKED_RECT locked_rects[12] = { 0 }; + WWASSERT(sysmem_texture->GetLevelCount() <= 12); // Lock all surfaces - for (level=0;levelGetLevelCount();++level) { + for (level = 0; level < sysmem_texture->GetLevelCount(); ++level) { DX8_ErrorCode( - d3d_texture->LockRect( + sysmem_texture->LockRect( level, &locked_rects[level], NULL, 0)); } - unsigned char* src_surface=thumb->Peek_Bitmap(); - WW3DFormat src_format=WW3D_FORMAT_A8R8G8B8; - unsigned width=thumb->Get_Width(); - unsigned height=thumb->Get_Height(); + unsigned char* src_surface = thumb->Peek_Bitmap(); + 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; level < sysmem_texture->GetLevelCount() - 1; ++level) { BitmapHandlerClass::Copy_Image_Generate_Mipmap( width, height, - (unsigned char*)locked_rects[level].pBits, + (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);// mipmap - - src_format=dest_format; - src_surface=(unsigned char*)locked_rects[level].pBits; - src_pitch=locked_rects[level].Pitch; - width>>=1; - height>>=1; + (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(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; level < sysmem_texture->GetLevelCount(); ++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 @@ -308,13 +528,15 @@ IDirect3DSurface8* TextureLoader::Load_Surface_Immediate( WW3DFormat texture_format, bool allow_compression) { - bool compressed=Is_Format_Compressed(texture_format,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); + 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)); + IDirect3DSurface8* d3d_surface = NULL; + DX8_ErrorCode(comp_tex->GetSurfaceLevel(0, &d3d_surface)); comp_tex->Release(); return d3d_surface; } @@ -322,63 +544,63 @@ IDirect3DSurface8* TextureLoader::Load_Surface_Immediate( // 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(); + 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); + 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; + 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; + 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]; + char palette[256 * 4]; targa.SetPalette(palette); - if (TARGA_ERROR_HANDLER(targa.Load(filename, TGAF_IMAGE, false),filename)) return MissingTexture::_Create_Missing_Surface(); + if (TARGA_ERROR_HANDLER(targa.Load(filename, TGAF_IMAGE, false), filename)) return MissingTexture::_Create_Missing_Surface(); - unsigned char* src_surface=(unsigned char*)targa.GetImage(); + 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); + 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, + converted_surface, width, height, - width*4, + width * 4, WW3D_FORMAT_A8R8G8B8,//dest_format, src_surface, src_width, src_height, - src_width*src_bpp, + src_width * src_bpp, src_format, (unsigned char*)targa.GetPalette(), - targa.Header.CMapDepth>>3, + 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); + 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; + unsigned src_pitch = src_width * src_bpp; - IDirect3DSurface8* d3d_surface = DX8Wrapper::_Create_DX8_Surface(width,height,dest_format); + IDirect3DSurface8* d3d_surface = DX8Wrapper::_Create_DX8_Surface(width, height, dest_format); WWASSERT(d3d_surface); D3DLOCKED_RECT locked_rect; DX8_ErrorCode( @@ -388,7 +610,7 @@ IDirect3DSurface8* TextureLoader::Load_Surface_Immediate( 0)); BitmapHandlerClass::Copy_Image( - (unsigned char*)locked_rect.pBits, + (unsigned char*)locked_rect.pBits, width, height, locked_rect.Pitch, @@ -399,7 +621,7 @@ IDirect3DSurface8* TextureLoader::Load_Surface_Immediate( src_pitch, src_format, (unsigned char*)targa.GetPalette(), - targa.Header.CMapDepth>>3, + targa.Header.CMapDepth >> 3, false); // No mipmap DX8_ErrorCode(d3d_surface->UnlockRect()); @@ -410,967 +632,2206 @@ 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; } - 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) -{ - if (!task->Get_Mip_Level_Count()) return false; - TextureBaseClass* texture=task->Peek_Texture(); + TextureLoadTaskClass* task = tc->ThumbnailLoadTask; - Targa targa; - if (TARGA_ERROR_HANDLER(targa.Open(texture->Get_Full_Path(), TGA_READMODE),texture->Get_Full_Path())) { - task->Set_Fail(true); - return false; - } - // DX8 uses image upside down compared to TGA - targa.Header.ImageDescriptor ^= TGAIDF_YORIGIN; + if (Is_DX8_Thread()) { + // load the thumbnail immediately + TextureLoader::Load_Thumbnail(tc); - 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 + // clear any pending thumbnail load + if (task) { + _ForegroundQueue.Remove(task); + task->Destroy(); + } - char palette[256*4]; - targa.SetPalette(palette); + } + else { + TextureLoadTaskClass* load_task = tc->TextureLoadTask; - unsigned src_width=targa.Header.Width; - unsigned src_height=targa.Header.Height; - unsigned width=task->Get_Width(); - unsigned height=task->Get_Height(); + // 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)) { - // 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; + // create a thumbnail load task and add to foreground queue. + task = TextureLoadTaskClass::Create(tc, TextureLoadTaskClass::TASK_THUMBNAIL, TextureLoadTaskClass::PRIORITY_LOW); + _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); - } - unsigned src_pitch=src_width*src_bpp; +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; + } - 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); + TextureLoadTaskClass* task = tc->TextureLoadTask; - width>>=1; - height>>=1; - src_width>>=1; - src_height>>=1; - if (!width || !height || !src_width || !src_height) break; + // if texture already has a load task, we don't need to create another one. + if (task) { + return; } - if (converted_surface) delete[] converted_surface; + task = TextureLoadTaskClass::Create(tc, TextureLoadTaskClass::TASK_LOAD, TextureLoadTaskClass::PRIORITY_LOW); - return true; + if (Is_DX8_Thread()) { + Begin_Load_And_Queue(task); + } + else { + _ForegroundQueue.Push_Back(task); + } } -// ---------------------------------------------------------------------------- -// -// Return a task from the load list head. The loading thread uses this function -// to retrieve tasks from the load list. -// -// ---------------------------------------------------------------------------- -TextureLoadTaskClass* LoaderThreadClass::Get_Task_From_Load_List() +void TextureLoader::Request_Foreground_Loading(TextureBaseClass* tc) { - CriticalSectionClass::LockClass m(mutex); - - TextureLoadTaskClass* task=LoadListHead; - if (task) { - LoadListHead=task->Peek_Succ(); - task->Set_Succ(NULL); + 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; } - 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. -// -// ---------------------------------------------------------------------------- + TextureLoadTaskClass* task = tc->TextureLoadTask; + TextureLoadTaskClass* task_thumb = tc->ThumbnailLoadTask; -void LoaderThreadClass::Add_Task_To_Load_List(TextureLoadTaskClass* task) -{ - CriticalSectionClass::LockClass m(mutex); + if (Is_DX8_Thread()) { - WWASSERT(task->Peek_Succ()==NULL); + // since we're in the DX8 thread, we can load the entire + // texture right now. - task->Set_Succ(LoadListHead); - LoadListHead=task; -} + // if we have a thumbnail task waiting, kill it. + if (task_thumb) { + _ForegroundQueue.Remove(task_thumb); + task_thumb->Destroy(); + } -// ---------------------------------------------------------------------------- -// -// 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. -// -// ---------------------------------------------------------------------------- + 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); + } -void LoaderThreadClass::Add_Task_To_Finished_List(TextureLoadTaskClass* task) -{ - CriticalSectionClass::LockClass m(mutex); + // finish loading the task and destroy it. + task->Finish_Load(); + task->Destroy(); - WWASSERT(task->Peek_Succ()==NULL); + } + 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); + } - task->Set_Succ(FinishedListHead); - FinishedListHead=task; -} + 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) { -// ---------------------------------------------------------------------------- -// -// 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. -// -// ---------------------------------------------------------------------------- + // remove task from list + _BackgroundQueue.Remove(task); -bool Is_Load_List_Empty() -{ - return !LoadListHead; -} -// ---------------------------------------------------------------------------- -// -// Texture loading thread loads textures that appear in loading_task_list. -// If the list is empty the thread sleeps. -// -// ---------------------------------------------------------------------------- + // add to foreground queue. + _ForegroundQueue.Push_Back(task); + } + + // upgrade the task priority + task->Set_Priority(TextureLoadTaskClass::PRIORITY_HIGH); -void LoaderThreadClass::Thread_Function() -{ - while (running) { - TextureLoadTaskClass* task=Get_Task_From_Load_List(); - if (task) { - TextureLoader::Load_Mipmap_Levels(task); - Add_Task_To_Finished_List(task); } + else { + // allocate high priority load task + task = TextureLoadTaskClass::Create(tc, TextureLoadTaskClass::TASK_LOAD, TextureLoadTaskClass::PRIORITY_HIGH); - Switch_Thread(); + // add to back of foreground queue. + _ForegroundQueue.Push_Back(task); + } } } -// ---------------------------------------------------------------------------- -// -// Update refreshes all completed texture loading tasks -// -// ---------------------------------------------------------------------------- -TextureLoadTaskClass* Get_Finished_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()); - TextureLoadTaskClass* task=FinishedListHead; - if (task) { - FinishedListHead=task->Peek_Succ(); - task->Set_Succ(NULL); - } - return task; -} + for (;;) { + bool done = false; -TextureLoadTaskClass* Get_Thumbnail_Task() -{ - CriticalSectionClass::LockClass m(mutex); + { + // 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(); + } - TextureLoadTaskClass* task=ThumbnailListHead; - if (task) { - ThumbnailListHead=task->Peek_Succ(); - task->Set_Succ(NULL); + // exit loop if no entries in list + if (done) { + break; + } + + Update(); + ThreadClass::Switch_Thread(); } - return task; } -void Add_Thumbnail_Task(TextureLoadTaskClass* task) -{ - CriticalSectionClass::LockClass m(mutex); - - WWASSERT(task->Peek_Succ()==NULL); - task->Set_Succ(ThumbnailListHead); - ThumbnailListHead=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; \ + } \ + } \ -} - -// ---------------------------------------------------------------------------- -// -// The main thread's update function deletes tasks from the load task list -// once a frame. -// -// ---------------------------------------------------------------------------- -TextureLoadTaskClass* Get_Task_From_Delete_List() +void TextureLoader::Update(void (*network_callback)(void)) { - WWASSERT(ThreadClass::_Get_Current_Thread_ID()==DX8Wrapper::_Get_Main_Thread_ID()); + WWASSERT_PRINT(Is_DX8_Thread(), "TextureLoader::Update must be called from the main thread!"); - TextureLoadTaskClass* task=DeleteTaskListHead; - if (task) { - DeleteTaskListHead=task->Peek_Succ(); - task->Set_Succ(NULL); + if (TextureLoadSuspended) { + return; } - 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. -// -// ---------------------------------------------------------------------------- + // grab foreground lock to prevent any other thread from + // modifying texture tasks. + FastCriticalSectionClass::LockClass lock(_ForegroundCriticalSection); -void Add_Task_To_Delete_List(TextureLoadTaskClass* task) -{ - WWASSERT(ThreadClass::_Get_Current_Thread_ID()==DX8Wrapper::_Get_Main_Thread_ID()); + 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; - WWASSERT(task->Peek_Succ()==NULL); + case TextureLoadTaskClass::TASK_LOAD: + Process_Foreground_Load(task); + break; + } + } - task->Set_Succ(DeleteTaskListHead); - DeleteTaskListHead=task; + TextureBaseClass::Invalidate_Old_Unused_Textures(TextureInactiveOverrideTime); } -TextureLoadTaskClass* Get_Deferred_Task() +void TextureLoader::Suspend_Texture_Load() { - CriticalSectionClass::LockClass m(mutex); - - TextureLoadTaskClass* task=DeferredListHead; - if (task) { - DeferredListHead=task->Peek_Succ(); - task->Set_Succ(NULL); - } - return task; + WWASSERT_PRINT(Is_DX8_Thread(), "TextureLoader::Suspend_Texture_Load must be called from the main thread!"); + TextureLoadSuspended = true; } -void Add_Deferred_Task(TextureLoadTaskClass* task) +void TextureLoader::Continue_Texture_Load() { - CriticalSectionClass::LockClass m(mutex); - - WWASSERT(task->Peek_Succ()==NULL); - task->Set_Succ(DeferredListHead); - DeferredListHead=task; + WWASSERT_PRINT(Is_DX8_Thread(), "TextureLoader::Continue_Texture_Load must be called from the main thread!"); + TextureLoadSuspended = false; } -void TextureLoader::Flush_Pending_Load_Tasks() +void TextureLoader::Process_Foreground_Thumbnail(TextureLoadTaskClass* task) { - while (!Is_Load_List_Empty()) { - Update(); - ThreadClass::Switch_Thread(); + 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::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 +void TextureLoader::Process_Foreground_Load(TextureLoadTaskClass* task) +{ + // Is high-priority task? + if (task->Get_Priority() == TextureLoadTaskClass::PRIORITY_HIGH) { + task->Finish_Load(); + task->Destroy(); + return; } - while (TextureLoadTaskClass* task=Get_Finished_Task()) { - task->End_Load(); - task->Apply(true); - TextureLoadTaskClass::Release_Instance(task); - } + // otherwise, must be a low-priority task. - while (TextureLoadTaskClass* task=Get_Thumbnail_Task()) { - task->Begin_Thumbnail_Load(); - } + switch (task->Get_State()) { + case TextureLoadTaskClass::STATE_NONE: + Begin_Load_And_Queue(task); + break; - while (TextureLoadTaskClass* task=Get_Task_From_Delete_List()) { -// delete task; - TextureLoadTaskClass::Release_Instance(task); + case TextureLoadTaskClass::STATE_LOAD_MIPMAP: + task->End_Load(); + task->Destroy(); + break; } } -// ---------------------------------------------------------------------------- - -static DWORD VectortoRGBA( D3DXVECTOR3* v, FLOAT fHeight ) -{ - 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 ); - - return( (a<<24L) + (r<<16L) + (g<<8L) + (b<<0L) ); -} -IDirect3DTexture8* TextureLoader::Generate_Bumpmap(TextureBaseClass* texture) +void TextureLoader::Begin_Load_And_Queue(TextureLoadTaskClass* task) { - WW3DFormat bump_format=WW3D_FORMAT_U8V8; - if (!DX8Wrapper::Get_Current_Caps()->Support_Texture_Format(bump_format)) { - return MissingTexture::_Get_Missing_Texture(); + // 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(); + } +} - 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; - - IDirect3DTexture8* d3d_texture = DX8Wrapper::_Create_DX8_Texture( - width, - height, - bump_format, - MIP_LEVELS_1); - - D3DLOCKED_RECT src_locked_rect; - DX8_ErrorCode( - texture->Peek_D3D_Texture()->LockRect( - 0, - &src_locked_rect, - NULL, - D3DLOCK_READONLY)); - D3DLOCKED_RECT dest_locked_rect; - DX8_ErrorCode( - d3d_texture->LockRect( - 0, - &dest_locked_rect, - NULL, - 0)); +void TextureLoader::Load_Thumbnail(TextureBaseClass* tc) +{ + // All D3D operations must run from main thread + WWASSERT(Is_DX8_Thread()); - WW3DFormat format=D3DFormat_To_WW3DFormat(desc.Format); - unsigned bpp=Get_Bytes_Per_Pixel(format); + // load thumbnail texture + IDirect3DTexture8* d3d_texture = Load_Thumbnail(tc->Get_Full_Path(), tc->Get_HSV_Shift()); - for( unsigned y=0; yGet_Asset_Type() == TextureBaseClass::TEX_REGULAR) { - unsigned char* dest_ptr = (unsigned char*)dest_locked_rect.pBits; - dest_ptr+=y*dest_locked_rect.Pitch; - unsigned char* src_ptr_mid = (unsigned char*)src_locked_rect.pBits; - src_ptr_mid+=y*src_locked_rect.Pitch; - unsigned char* src_ptr_next_line = ( src_ptr_mid + src_locked_rect.Pitch ); - unsigned char* src_ptr_prev_line = ( src_ptr_mid - src_locked_rect.Pitch ); - - 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; - - for( unsigned x=0; x1 ) ? 63 : 127; + tc->Apply_New_Surface(d3d_texture, false); + } - switch( bump_format ) - { - case WW3D_FORMAT_U8V8: - *dest_ptr++ = (unsigned char)iDu; - *dest_ptr++ = (unsigned char)iDv; - break; + // release our reference to thumbnail texture + d3d_texture->Release(); + d3d_texture = 0; +} - 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; - case WW3D_FORMAT_X8L8V8U8: - *dest_ptr++ = (unsigned char)iDu; - *dest_ptr++ = (unsigned char)iDv; - *dest_ptr++ = (unsigned char)uL; - *dest_ptr++ = (unsigned char)0L; - break; +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); } - - // Move one pixel to the left (src is 32-bpp) - src_ptr_mid+=bpp; - src_ptr_prev_line+=bpp; - src_ptr_next_line+=bpp; } - } - DX8_ErrorCode(d3d_texture->UnlockRect(0)); - DX8_ErrorCode(texture->Peek_D3D_Texture()->UnlockRect(0)); - return d3d_texture; + Switch_Thread(); + } } -// ---------------------------------------------------------------------------- -// -// Public texture request functions. These functions can be used to request -// texture loading. -// -// ---------------------------------------------------------------------------- -void TextureLoader::Add_Load_Task(TextureBaseClass* tc) +//////////////////////////////////////////////////////////////////////////////// +// +// 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) { - // If the texture is already being loaded we just exit here. - if (tc->TextureLoadTask) return; + // 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(). - TextureLoadTaskClass* task=TextureLoadTaskClass::Get_Instance(tc,false); - task->Begin_Texture_Load(); + for (int i = 0; i < MIP_LEVELS_MAX; ++i) { + LockedSurfacePtr[i] = NULL; + LockedSurfacePitch[i] = 0; + } } -// ---------------------------------------------------------------------------- -void TextureLoader::Request_High_Priority_Loading( - TextureBaseClass* tc, - MipCountType mip_level_count) +TextureLoadTaskClass::~TextureLoadTaskClass(void) { - TextureLoadTaskClass* task=TextureLoadTaskClass::Get_Instance(tc,true); - task->Begin_Texture_Load(); + Deinit(); } -// ---------------------------------------------------------------------------- -void TextureLoader::Request_Thumbnail(TextureBaseClass* tc) +TextureLoadTaskClass* TextureLoadTaskClass::Create(TextureBaseClass* tc, TaskType type, PriorityType priority) { - // If the texture is already being loaded we just exit here. - if (tc->TextureLoadTask) return; + // recycle or create a new texture load task with the given type + // and priority, then associate the texture with the task. - TextureLoadTaskClass* task=TextureLoadTaskClass::Get_Instance(tc,false); - task->Begin_Thumbnail_Load(); + // 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; } -// ---------------------------------------------------------------------------- -// -// Texture loader task handler -// -// ---------------------------------------------------------------------------- -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) +void TextureLoadTaskClass::Destroy(void) { + // detach the task from its texture, and return to free pool. + Deinit(); + _TexLoadFreeList.Push_Front(this); } -// ---------------------------------------------------------------------------- -// -// 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. -// -// ---------------------------------------------------------------------------- -TextureLoadTaskClass::~TextureLoadTaskClass() +void TextureLoadTaskClass::Delete_Free_Pool(void) { - Deinit(); + // (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,bool high_priority) + +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. - REF_PTR_SET(Texture,tc); - //WWASSERT(Texture->Get_Full_Path() != NULL); + WWASSERT(Texture->Get_Full_Path() != ""); - 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(); + Type = type; + Priority = priority; + State = STATE_NONE; - Texture->TextureLoadTask=this; - for (int i=0;iAs_TextureClass(); + + if (tex) + { + Format = tex->Get_Texture_Format(); // don't assume format yet KM } - if (Texture) { - WWASSERT(Texture->TextureLoadTask==this); - Texture->TextureLoadTask=NULL; + else + { + Format = WW3D_FORMAT_UNKNOWN; } - REF_PTR_RELEASE(Texture); - WWASSERT(!D3DTexture); + 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::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, height; - width=dds_file.Get_Width(0); - 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 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; - } - } +void TextureLoadTaskClass::Deinit() +{ + // task should not be on any list when it is being detached from texture. + WWASSERT(Next == NULL); + WWASSERT(Prev == NULL); - 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; - } + WWASSERT(D3DTexture == NULL); + for (int i = 0; i < MIP_LEVELS_MAX; ++i) { + WWASSERT(LockedSurfacePtr[i] == NULL); + } - 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())); - } + if (Texture) { + switch (Type) { + case TASK_THUMBNAIL: + WWASSERT(Texture->ThumbnailLoadTask == this); + Texture->ThumbnailLoadTask = NULL; + break; - // 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_Dimension()) - ReductionFactor=0; - else - { int mipToDrop=MipLevels-WW3D::Get_Texture_Min_Dimension(); - if (ReductionFactor >= mipToDrop) - ReductionFactor=mipToDrop; - } + case TASK_LOAD: + WWASSERT(Texture->TextureLoadTask == this); + Texture->TextureLoadTask = NULL; + break; + } - 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().str(),ow,oh,width,height)); - } + // NOTE: we must be in main thread to avoid corrupting Texture's refcount. + WWASSERT(TextureLoader::Is_DX8_Thread()); + REF_PTR_RELEASE(Texture); + } +} - IsLoading=true; - Width=width; - Height=height; - if (Format==WW3D_FORMAT_UNKNOWN) { - Format=Get_Valid_Texture_Format(dest_format,false); - } - else { - Format=Get_Valid_Texture_Format(Format,false); - } +bool TextureLoadTaskClass::Begin_Load(void) +{ + WWASSERT(TextureLoader::Is_DX8_Thread()); - D3DTexture=DX8Wrapper::_Create_DX8_Texture(Width,Height,Format,Texture->MipLevelCount); - } + bool loaded = false; - 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; - } + // if allowed, begin a compressed load + if (Texture->Is_Compression_Allowed()) { + loaded = Begin_Compressed_Load(); + } - if (HighPriorityRequested) { - TextureLoader::Load_Mipmap_Levels(this); - End_Load(); - Apply(true); - Add_Task_To_Delete_List(this); - } - else { - LoaderThreadClass::Add_Task_To_Load_List(this); - } + // otherwise, begin an uncompressed load + if (!loaded) { + loaded = Begin_Uncompressed_Load(); } - // Otherwise add to deferred list which will be handled by main thread - else { - Add_Deferred_Task(this); + + // if not loaded, abort. + if (!loaded) { + return false; } -} -/* 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(); + // lock surfaces in preparation for copy + Lock_Surfaces(); - 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; + 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()); -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; - } - D3DTexture=TextureLoader::Load_Thumbnail(Texture->Get_Full_Path(),format); + bool loaded = false; - // Thumbnail loads are always high priority, so apply immediatelly - End_Load(); - Apply(false); - Add_Task_To_Delete_List(this); - return; + // if allowed, try to load compressed mipmaps + if (Texture->Is_Compression_Allowed()) { + loaded = Load_Compressed_Mipmap(); } - else { - Add_Thumbnail_Task(this); + + // otherwise, load uncompressed mipmaps + if (!loaded) { + loaded = Load_Uncompressed_Mipmap(); } + + State = STATE_LOAD_MIPMAP; + + return loaded; } -// ---------------------------------------------------------------------------- -// -// Deinit can be called multiple times. If any surfaces are locked this call -// can only be called from the main thread. -// -// ---------------------------------------------------------------------------- -void TextureLoadTaskClass::End_Load() +void TextureLoadTaskClass::End_Load(void) { - for (unsigned i=0;iUnlockRect(i)); - } - LockedSurfacePtr[i]=NULL; - } - IsLoading=false; + WWASSERT(TextureLoader::Is_DX8_Thread()); + + Unlock_Surfaces(); + Apply(true); + State = STATE_LOAD_COMPLETE; } -// ---------------------------------------------------------------------------- -// -// 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. -// -// ---------------------------------------------------------------------------- -void TextureLoadTaskClass::Set_Succ(TextureLoadTaskClass* succ) +void TextureLoadTaskClass::Finish_Load(void) { - WWASSERT((succ && !Succ) || (!succ)); // Can't set successor pointer if it has been set already - Succ=succ; -} + 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::Set_D3D_Texture(IDirect3DTexture8* texture) + +void TextureLoadTaskClass::Apply_Missing_Texture(void) { - WWASSERT(D3DTexture==0); - D3DTexture=texture; + WWASSERT(TextureLoader::Is_DX8_Thread()); + WWASSERT(!D3DTexture); + + D3DTexture = MissingTexture::_Get_Missing_Texture(); + Apply(true); } -// ---------------------------------------------------------------------------- -// -// Apply the D3D texture surface to the client texture. The parameter 'initialize' -// determines whether the client texture will be set to initialized state or -// not. Generally thumbnail tasks will not set texture to initialised state but -// all other loads do. -// -// ---------------------------------------------------------------------------- void TextureLoadTaskClass::Apply(bool initialize) { WWASSERT(D3DTexture); + // Verify that none of the mip levels are locked - for (unsigned i=0;iApply_New_Surface(initialize); + Texture->Apply_New_Surface(D3DTexture, initialize); D3DTexture->Release(); - D3DTexture=NULL; + 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; } -// ---------------------------------------------------------------------------- -// -// 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. -// -// ---------------------------------------------------------------------------- -unsigned char* TextureLoadTaskClass::Get_Locked_Surface_Ptr(unsigned level) +bool TextureLoadTaskClass::Begin_Compressed_Load(void) { - WWASSERT(levelGet_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; } -// ---------------------------------------------------------------------------- -// -// 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. -// -// ---------------------------------------------------------------------------- +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; +} -unsigned TextureLoadTaskClass::Get_Locked_Surface_Pitch(unsigned level) const +/* +bool TextureLoadTaskClass::Begin_Compressed_Load(void) { - WWASSERT(levelGet_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; } -// ---------------------------------------------------------------------------- -// -// 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 TextureLoadTaskClass::Begin_Uncompressed_Load(void) { - CriticalSectionClass::LockClass m(mutex); + Targa targa; + if (TARGA_ERROR_HANDLER(targa.Open(Texture->Get_Full_Path(), TGA_READMODE), Texture->Get_Full_Path())) { + return false; + } - TextureLoadTaskClass* task=FreeTaskListHead; - if (task) { - FreeTaskListHead=task->Peek_Succ(); - task->Set_Succ(NULL); + 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())); } - else { - task=W3DNEW TextureLoadTaskClass(); + + // 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; } - task->Init(tc,high_priority); - return task; + + 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 + } -// ---------------------------------------------------------------------------- -// -// When task is no longer needed it is returned to the pool. -// -// ---------------------------------------------------------------------------- -void TextureLoadTaskClass::Release_Instance(TextureLoadTaskClass* task) +bool TextureLoadTaskClass::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); + // 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; + } + } - task->Deinit(); + 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 + ); - // Task must not be in any list when it is being freed - WWASSERT(task->Peek_Succ()==NULL); + width >>= 1; + height >>= 1; + } - task->Set_Succ(FreeTaskListHead); - FreeTaskListHead=task; + 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; + } + } + + if (converted_surface) { + delete[] converted_surface; + } + + return true; +} + + +unsigned char* TextureLoadTaskClass::Get_Locked_Surface_Ptr(unsigned int level) +{ + WWASSERT(level < MipLevelCount); + WWASSERT(LockedSurfacePtr[level]); + return LockedSurfacePtr[level]; +} + +// ---------------------------------------------------------------------------- +// +// 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 int TextureLoadTaskClass::Get_Locked_Surface_Pitch(unsigned int level) const +{ + WWASSERT(level < MipLevelCount); + WWASSERT(LockedSurfacePtr[level]); + return LockedSurfacePitch[level]; +} + + + + + +// CubeTextureLoadTaskClass +CubeTextureLoadTaskClass::CubeTextureLoadTaskClass() + : TextureLoadTaskClass() +{ + // 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 f = 0; f < 6; f++) + { + for (int i = 0; i < MIP_LEVELS_MAX; ++i) + { + LockedCubeSurfacePtr[f][i] = NULL; + LockedCubeSurfacePitch[f][i] = 0; + } + } +} + +void CubeTextureLoadTaskClass::Destroy(void) +{ + // detach the task from its texture, and return to free pool. + Deinit(); + _CubeTexLoadFreeList.Push_Front(this); +} + + +void CubeTextureLoadTaskClass::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() != ""); + + 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; i < MipLevelCount; i++) + { + D3DLOCKED_RECT locked_rect; + DX8_ErrorCode + ( + Peek_D3D_Cube_Texture()->LockRect + ( + (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 < Get_Mip_Level_Count(); level++) + { + WWASSERT(width && height); + + // get cube map surface + dds_file.Copy_CubeMap_Level_To_Surface + ( + face, + level, + Get_Format(), + width, + height, + Get_Locked_CubeMap_Surface_Pointer(face, level), + Get_Locked_CubeMap_Surface_Pitch(face, level), + HSVShift + ); + + width >>= 1; + height >>= 1; + } + } + + return true; +} + +unsigned char* CubeTextureLoadTaskClass::Get_Locked_CubeMap_Surface_Pointer(unsigned int face, unsigned int level) +{ + WWASSERT(face < 6 && level < MipLevelCount); + WWASSERT(LockedCubeSurfacePtr[face][level]); + return LockedCubeSurfacePtr[face][level]; +} + +unsigned int CubeTextureLoadTaskClass::Get_Locked_CubeMap_Surface_Pitch(unsigned int face, unsigned int level) const +{ + WWASSERT(face < 6 && level < MipLevelCount); + WWASSERT(LockedCubeSurfacePitch[face][level]); + return LockedCubeSurfacePitch[face][level]; +} + + + + + + + +// VolumeTextureLoadTaskClass +VolumeTextureLoadTaskClass::VolumeTextureLoadTaskClass() + : TextureLoadTaskClass() +{ + // 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; + LockedSurfaceSlicePitch[i] = 0; + } +} + +void VolumeTextureLoadTaskClass::Destroy(void) +{ + // detach the task from its texture, and return to free pool. + Deinit(); + _VolTexLoadFreeList.Push_Front(this); +} + +void VolumeTextureLoadTaskClass::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() != ""); + + 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; i < MipLevelCount; i++) + { + D3DLOCKED_BOX locked_box; + DX8_ErrorCode + ( + Peek_D3D_Volume_Texture()->LockBox + ( + 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 < Get_Mip_Level_Count(); level++) + { + if (width < 1) width = 1; + if (height < 1) height = 1; + if (depth < 1) depth = 1; + + // get volume + dds_file.Copy_Volume_Level_To_Surface + ( + level, + depth, + Get_Format(), + width, + height, + Get_Locked_Volume_Pointer(level), + Get_Locked_Volume_Row_Pitch(level), + Get_Locked_Volume_Slice_Pitch(level), + HSVShift + ); + + width >>= 1; + height >>= 1; + depth >>= 1; + } + + return true; +} + +unsigned char* VolumeTextureLoadTaskClass::Get_Locked_Volume_Pointer(unsigned int level) +{ + WWASSERT(level < MipLevelCount); + WWASSERT(LockedSurfacePtr[level]); + return LockedSurfacePtr[level]; +} + +unsigned int VolumeTextureLoadTaskClass::Get_Locked_Volume_Row_Pitch(unsigned int level) +{ + WWASSERT(level < MipLevelCount); + WWASSERT(LockedSurfacePtr[level]); + return LockedSurfacePitch[level]; +} + +unsigned int VolumeTextureLoadTaskClass::Get_Locked_Volume_Slice_Pitch(unsigned int level) +{ + WWASSERT(level < MipLevelCount); + WWASSERT(LockedSurfacePtr[level]); + return LockedSurfaceSlicePitch[level]; +} diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/textureloader.h b/Generals/Code/Libraries/Source/WWVegas/WW3D2/textureloader.h index 7fd9091edb1..434fb917afd 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/textureloader.h +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/textureloader.h @@ -1,5 +1,5 @@ /* -** Command & Conquer Generals(tm) +** Command & Conquer Generals Zero Hour(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify @@ -16,6 +16,28 @@ ** 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:: 06/27/02 1:27p $* + * * + * $Revision:: 2 $* + * * + * 06/27/02 KM Texture class abstraction * + *---------------------------------------------------------------------------------------------* + * Functions: * + * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + #ifndef TEXTURELOADER_H #define TEXTURELOADER_H @@ -32,111 +54,281 @@ 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); + 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); + 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_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); - static void Update(); - static void Flush_Pending_Load_Tasks(); + // returns true if current thread of execution is allowed to make DX8 calls. + static bool Is_DX8_Thread(void); - static IDirect3DTexture8* Generate_Bumpmap(TextureBaseClass* texture); + 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; }; -// ---------------------------------------------------------------------------- -// -// Texture loader task handler -// -// ---------------------------------------------------------------------------- +class TextureLoadTaskListNodeClass +{ + friend class TextureLoadTaskListClass; -class TextureLoadTaskClass : public W3DMPO +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 { - W3DMPO_GLUE(TextureLoadTaskClass) + // This class added thread-safety to the basic TextureLoadTaskListClass. - static TextureLoadTaskClass* FreeTaskListHead; +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; - IDirect3DTexture8 *D3DTexture; - unsigned Width; - unsigned Height; - WW3DFormat Format; + 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 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;} }; + unsigned int LockedSurfacePitch[MIP_LEVELS_MAX]; - void Init(TextureBaseClass* tc,bool high_priority); - void Deinit(); + TaskType Type; + PriorityType Priority; + StateType State; +}; - 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; } +class CubeTextureLoadTaskClass : public TextureLoadTaskClass +{ +public: + CubeTextureLoadTaskClass(); - unsigned char* Get_Locked_Surface_Ptr(unsigned level); - unsigned Get_Locked_Surface_Pitch(unsigned level) const; + virtual void Destroy(void); + virtual void Init(TextureBaseClass* tc, TaskType type, PriorityType priority); + virtual void Deinit(void); - bool Has_Failed() const { return HasFailed; } - void Set_Fail(bool b) { HasFailed=b; } +protected: + virtual bool Begin_Compressed_Load(void); + virtual bool Begin_Uncompressed_Load(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 bool Load_Compressed_Mipmap(void); + // virtual bool Load_Uncompressed_Mipmap(void); - void Apply(bool initialize); + virtual void Lock_Surfaces(void); + virtual void Unlock_Surfaces(void); - TextureLoadTaskClass* Peek_Succ() { return Succ; } - void Set_Succ(TextureLoadTaskClass* succ); +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; - TextureBaseClass* Peek_Texture() { return Texture; } - IDirect3DTexture8* Peek_D3D_Texture() { return D3DTexture; } + IDirect3DCubeTexture8* Peek_D3D_Cube_Texture(void) { return (IDirect3DCubeTexture8*)D3DTexture; } - void Set_D3D_Texture(IDirect3DTexture8* texture); + unsigned char* LockedCubeSurfacePtr[6][MIP_LEVELS_MAX]; + unsigned int LockedCubeSurfacePitch[6][MIP_LEVELS_MAX]; }; -#endif +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; +}; + +#endif diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/texturethumbnail.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/texturethumbnail.cpp index 4a9ebd2f2a0..02e282f6e76 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/texturethumbnail.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/texturethumbnail.cpp @@ -26,20 +26,54 @@ #include "bitmaphandler.h" #include "ffactory.h" +#include "RAWFILE.H" +#include "wwprofile.h" +#include + +static DLListClass ThumbnailManagerList; +static ThumbnailManagerClass* GlobalThumbnailManager; +bool ThumbnailManagerClass::CreateThumbnailIfNotFound = false; + static HashTemplateClass thumbnail_hash; static bool _ThumbHashModified; static unsigned char* _ThumbnailMemory; static const char *THUMBNAIL_FILENAME = "thumbnails.dat"; -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()); +} + +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) : - Name(name), - Bitmap(bitmap), + 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,80 +85,154 @@ ThumbnailClass::ThumbnailClass(const char* name, unsigned char* bitmap, unsigned // // ---------------------------------------------------------------------------- -ThumbnailClass::ThumbnailClass(const StringClass& filename) +ThumbnailClass::ThumbnailClass(ThumbnailManagerClass* manager, const StringClass& filename) : - Bitmap(0), - Name(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) { - unsigned reduction_factor=3; + WWPROFILE(("ThumbnailClass::ThumbnailClass")); + unsigned reduction_factor = 3; // First, try loading image from a DDS file - DDSFileClass dds_file(filename,reduction_factor); + DDSFileClass dds_file(filename, reduction_factor); if (dds_file.Is_Available() && dds_file.Load()) { - Width=dds_file.Get_Width(0); - Height=dds_file.Get_Height(0); - Bitmap=W3DNEWARRAY unsigned char[Width*Height*4]; - Allocated=true; + 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_A8R8G8B8, - Width, - Height, - Bitmap, - Width*4); + 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; + 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(dest_format,src_format,src_bpp,targa); + 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... - Width=targa.Header.Width>>reduction_factor; - Height=targa.Header.Height>>reduction_factor; - TextureLoader::Validate_Texture_Size(Width,Height); - unsigned src_width=targa.Header.Width; - unsigned src_height=targa.Header.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 (iw < OriginalTextureWidth && ih < OriginalTextureHeight) { + iw += iw; + ih += ih; + OriginalTextureMipLevelCount++; + } + + while (Width > 32 || 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]; + char palette[256 * 4]; targa.SetPalette(palette); - if (TARGA_ERROR_HANDLER(targa.Load(filename, TGAF_IMAGE, false),filename)) return; + 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(); + unsigned char* src_surface = (unsigned char*)targa.GetImage(); - Bitmap=W3DNEWARRAY unsigned char[Width*Height*4]; - Allocated=true; + int len = Name.Get_Length(); + WWASSERT(len > 4); + Name[len - 3] = 't'; + Name[len - 2] = 'g'; + Name[len - 1] = 'a'; - dest_format=WW3D_FORMAT_A8R8G8B8; + Bitmap = W3DNEWARRAY unsigned char[Width * Height * 2]; + Allocated = true; + + dest_format = WW3D_FORMAT_A8R8G8B8; BitmapHandlerClass::Copy_Image( - Bitmap, + Bitmap, Width, Height, - Width*4, - WW3D_FORMAT_A8R8G8B8, + Width * 2, + WW3D_FORMAT_A4R4G4B4, src_surface, src_width, src_height, - src_width*src_bpp, + src_width * src_bpp, src_format, (unsigned char*)targa.GetPalette(), - targa.Header.CMapDepth>>3, + targa.Header.CMapDepth >> 3, false); } - _ThumbHashModified=true; - thumbnail_hash.Insert(Name,this); + Manager->Insert_To_Hash(this); } ThumbnailClass::~ThumbnailClass() @@ -287,4 +395,158 @@ void ThumbnailClass::Deinit() delete [] _ThumbnailMemory; _ThumbnailMemory=NULL; -} \ No newline at end of file +} + +// ---------------------------------------------------------------------------- +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(); + } + + if (ThumbnailMemory) 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; + } + if (GlobalThumbnailManager) { + 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 905517e5e48..983d1d12365 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/texturethumbnail.h +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/texturethumbnail.h @@ -26,6 +26,14 @@ #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 @@ -34,15 +42,39 @@ class ThumbnailClass 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; public: - ThumbnailClass(const char* name, unsigned char* bitmap, unsigned w, unsigned h, bool allocated); - ThumbnailClass(const StringClass& filename); + 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(); 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; } const StringClass& Get_Name() const { return Name; } static ThumbnailClass* Peek_Instance(const StringClass& name); @@ -52,4 +84,49 @@ class ThumbnailClass // ---------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- + +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(); +}; + +// ---------------------------------------------------------------------------- + + #endif diff --git a/Generals/Code/Tools/WorldBuilder/src/ObjectPreview.cpp b/Generals/Code/Tools/WorldBuilder/src/ObjectPreview.cpp index e0b138657ef..12117f460f4 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 8c853cea4b1..3729546dbe6 100644 --- a/Generals/Code/Tools/WorldBuilder/src/WorldBuilder.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/WorldBuilder.cpp @@ -629,7 +629,6 @@ int CWorldBuilderApp::ExitInstance() delete TheFileSystem; TheFileSystem = NULL; - TextureLoadTaskClass::shutdown(); delete TheW3DFileSystem; TheW3DFileSystem = NULL; diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 5dd00ab1eef..aafb7b2bc41 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -273,2265 +273,6 @@ void MoveRectIntoOtherRect(const RECT& inner, const RECT& outer, int* x, int* y) -bool DX8Wrapper::Set_Any_Render_Device(void) -{ - // Then fullscreen - int dev_number = 0; - for (; dev_number < _RenderDeviceNameTable.Count(); dev_number++) { - if (Set_Render_Device(dev_number,-1,-1,-1,0,false)) { - return true; - } - } - - // Try windowed first - for (dev_number = 0; dev_number < _RenderDeviceNameTable.Count(); dev_number++) { - if (Set_Render_Device(dev_number,-1,-1,-1,1,false)) { - return true; - } - } - - return false; -} - -bool DX8Wrapper::Set_Render_Device -( - const char * dev_name, - int width, - int height, - int bits, - int windowed, - bool resize_window -) -{ - for ( int dev_number = 0; dev_number < _RenderDeviceNameTable.Count(); dev_number++) { - if ( strcmp( dev_name, _RenderDeviceNameTable[dev_number]) == 0) { - return Set_Render_Device( dev_number, width, height, bits, windowed, resize_window ); - } - - if ( strcmp( dev_name, _RenderDeviceShortNameTable[dev_number]) == 0) { - return Set_Render_Device( dev_number, width, height, bits, windowed, resize_window ); - } - } - return false; -} - -void DX8Wrapper::Get_Format_Name(unsigned int format, StringClass *tex_format) -{ - *tex_format="Unknown"; - switch (format) { - case D3DFMT_A8R8G8B8: *tex_format="D3DFMT_A8R8G8B8"; break; - case D3DFMT_R8G8B8: *tex_format="D3DFMT_R8G8B8"; break; - case D3DFMT_A4R4G4B4: *tex_format="D3DFMT_A4R4G4B4"; break; - case D3DFMT_A1R5G5B5: *tex_format="D3DFMT_A1R5G5B5"; break; - case D3DFMT_R5G6B5: *tex_format="D3DFMT_R5G6B5"; break; - case D3DFMT_L8: *tex_format="D3DFMT_L8"; break; - case D3DFMT_A8: *tex_format="D3DFMT_A8"; break; - case D3DFMT_P8: *tex_format="D3DFMT_P8"; break; - case D3DFMT_X8R8G8B8: *tex_format="D3DFMT_X8R8G8B8"; break; - case D3DFMT_X1R5G5B5: *tex_format="D3DFMT_X1R5G5B5"; break; - case D3DFMT_R3G3B2: *tex_format="D3DFMT_R3G3B2"; break; - case D3DFMT_A8R3G3B2: *tex_format="D3DFMT_A8R3G3B2"; break; - case D3DFMT_X4R4G4B4: *tex_format="D3DFMT_X4R4G4B4"; break; - case D3DFMT_A8P8: *tex_format="D3DFMT_A8P8"; break; - case D3DFMT_A8L8: *tex_format="D3DFMT_A8L8"; break; - case D3DFMT_A4L4: *tex_format="D3DFMT_A4L4"; break; - case D3DFMT_V8U8: *tex_format="D3DFMT_V8U8"; break; - case D3DFMT_L6V5U5: *tex_format="D3DFMT_L6V5U5"; break; - case D3DFMT_X8L8V8U8: *tex_format="D3DFMT_X8L8V8U8"; break; - case D3DFMT_Q8W8V8U8: *tex_format="D3DFMT_Q8W8V8U8"; break; - case D3DFMT_V16U16: *tex_format="D3DFMT_V16U16"; break; - case D3DFMT_W11V11U10: *tex_format="D3DFMT_W11V11U10"; break; - case D3DFMT_UYVY: *tex_format="D3DFMT_UYVY"; break; - case D3DFMT_YUY2: *tex_format="D3DFMT_YUY2"; break; - case D3DFMT_DXT1: *tex_format="D3DFMT_DXT1"; break; - case D3DFMT_DXT2: *tex_format="D3DFMT_DXT2"; break; - case D3DFMT_DXT3: *tex_format="D3DFMT_DXT3"; break; - case D3DFMT_DXT4: *tex_format="D3DFMT_DXT4"; break; - case D3DFMT_DXT5: *tex_format="D3DFMT_DXT5"; break; - case D3DFMT_D16_LOCKABLE: *tex_format="D3DFMT_D16_LOCKABLE"; break; - case D3DFMT_D32: *tex_format="D3DFMT_D32"; break; - case D3DFMT_D15S1: *tex_format="D3DFMT_D15S1"; break; - case D3DFMT_D24S8: *tex_format="D3DFMT_D24S8"; break; - case D3DFMT_D16: *tex_format="D3DFMT_D16"; break; - case D3DFMT_D24X8: *tex_format="D3DFMT_D24X8"; break; - case D3DFMT_D24X4S4: *tex_format="D3DFMT_D24X4S4"; break; - default: break; - } -} - -void DX8Wrapper::Resize_And_Position_Window() -{ - // Get the current dimensions of the 'render area' of the window - RECT rect = { 0 }; - ::GetClientRect (_Hwnd, &rect); - - // Is the window the correct size for this resolution? - if ((rect.right-rect.left) != ResolutionWidth || - (rect.bottom-rect.top) != ResolutionHeight) { - - // Calculate what the main window's bounding rectangle should be to - // accommodate this resolution - rect.left = 0; - rect.top = 0; - rect.right = ResolutionWidth; - rect.bottom = ResolutionHeight; - DWORD dwstyle = ::GetWindowLong (_Hwnd, GWL_STYLE); - AdjustWindowRect (&rect, dwstyle, FALSE); - int width = rect.right-rect.left; - int height = rect.bottom-rect.top; - - // Resize the window to fit this resolution - if (!IsWindowed) - { - ::SetWindowPos(_Hwnd, HWND_TOPMOST, 0, 0, width, height, SWP_NOSIZE | SWP_NOMOVE); - - DEBUG_LOG(("Window resized to w:%d h:%d", width, height)); - } - else - { - // TheSuperHackers @feature helmutbuhler 14/04/2025 - // Center the window in the workarea of the monitor it is on. - MONITORINFO mi = {sizeof(MONITORINFO)}; - GetMonitorInfo(MonitorFromWindow(_Hwnd, MONITOR_DEFAULTTOPRIMARY), &mi); - int left = (mi.rcWork.left + mi.rcWork.right - width) / 2; - int top = (mi.rcWork.top + mi.rcWork.bottom - height) / 2; - - // TheSuperHackers @feature helmutbuhler 14/04/2025 - // Move the window to try fit it into the monitor area, if one of its dimensions is larger than the work area. - // Otherwise align the window to the top left edges, if it is even larger than the monitor area. - RECT rectClient; - rectClient.left = left - rect.left; - rectClient.top = top - rect.top; - rectClient.right = rectClient.left + ResolutionWidth; - rectClient.bottom = rectClient.top + ResolutionHeight; - MoveRectIntoOtherRect(rectClient, mi.rcMonitor, &left, &top); - - ::SetWindowPos (_Hwnd, NULL, left, top, width, height, SWP_NOZORDER); - - DEBUG_LOG(("Window positioned to x:%d y:%d, resized to w:%d h:%d", left, top, width, height)); - } - } -} - -bool DX8Wrapper::Set_Render_Device(int dev, int width, int height, int bits, int windowed, - bool resize_window,bool reset_device, bool restore_assets) -{ - WWASSERT(IsInitted); - WWASSERT(dev >= -1); - WWASSERT(dev < _RenderDeviceNameTable.Count()); - - /* - ** If user has never selected a render device, start out with device 0 - */ - if ((CurRenderDevice == -1) && (dev == -1)) { - CurRenderDevice = 0; - } else if (dev != -1) { - CurRenderDevice = dev; - } - - /* - ** If user doesn't want to change res, set the res variables to match the - ** current resolution - */ - if (width != -1) ResolutionWidth = width; - if (height != -1) ResolutionHeight = height; - - // Initialize Render2DClass Screen Resolution - Render2DClass::Set_Screen_Resolution( RectClass( 0, 0, ResolutionWidth, ResolutionHeight ) ); - - if (bits != -1) BitDepth = bits; - if (windowed != -1) IsWindowed = (windowed != 0); - DX8Wrapper_IsWindowed = IsWindowed; - - WWDEBUG_SAY(("Attempting Set_Render_Device: name: %s (%s:%s), width: %d, height: %d, windowed: %d", - _RenderDeviceNameTable[CurRenderDevice].str(),_RenderDeviceDescriptionTable[CurRenderDevice].Get_Driver_Name(), - _RenderDeviceDescriptionTable[CurRenderDevice].Get_Driver_Version(),ResolutionWidth,ResolutionHeight,(IsWindowed ? 1 : 0))); - -#ifdef _WINDOWS - // PWG 4/13/2000 - changed so that if you say to resize the window it resizes - // regardless of whether its windowed or not as OpenGL resizes its self around - // the caption and edges of the window type you provide, so its important to - // push the client area to be the size you really want. - // if ( resize_window && windowed ) { - if (resize_window) { - Resize_And_Position_Window(); - } -#endif - //must be either resetting existing device or creating a new one. - WWASSERT(reset_device || D3DDevice == NULL); - - /* - ** Initialize values for D3DPRESENT_PARAMETERS members. - */ - ::ZeroMemory(&_PresentParameters, sizeof(D3DPRESENT_PARAMETERS)); - - _PresentParameters.BackBufferWidth = ResolutionWidth; - _PresentParameters.BackBufferHeight = ResolutionHeight; - _PresentParameters.BackBufferCount = IsWindowed ? 1 : 2; - - _PresentParameters.MultiSampleType = D3DMULTISAMPLE_NONE; - //I changed this to discard all the time (even when full-screen) since that the most efficient. 07-16-03 MW: - _PresentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;//IsWindowed ? D3DSWAPEFFECT_DISCARD : D3DSWAPEFFECT_FLIP; // Shouldn't this be D3DSWAPEFFECT_FLIP? - _PresentParameters.hDeviceWindow = _Hwnd; - _PresentParameters.Windowed = IsWindowed; - - _PresentParameters.EnableAutoDepthStencil = TRUE; // Driver will attempt to match Z-buffer depth - _PresentParameters.Flags=0; // We're not going to lock the backbuffer - - _PresentParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; - _PresentParameters.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT; - - /* - ** Set up the buffer formats. Several issues here: - ** - if in windowed mode, the backbuffer must use the current display format. - ** - the depth buffer must use - */ - if (IsWindowed) { - - D3DDISPLAYMODE desktop_mode; - ::ZeroMemory(&desktop_mode, sizeof(D3DDISPLAYMODE)); - D3DInterface->GetAdapterDisplayMode( CurRenderDevice, &desktop_mode ); - - DisplayFormat=_PresentParameters.BackBufferFormat = desktop_mode.Format; - - // In windowed mode, define the bitdepth from desktop mode (as it can't be changed) - switch (_PresentParameters.BackBufferFormat) { - case D3DFMT_X8R8G8B8: - case D3DFMT_A8R8G8B8: - case D3DFMT_R8G8B8: BitDepth=32; break; - case D3DFMT_A4R4G4B4: - case D3DFMT_A1R5G5B5: - case D3DFMT_R5G6B5: BitDepth=16; break; - case D3DFMT_L8: - case D3DFMT_A8: - case D3DFMT_P8: BitDepth=8; break; - default: - // Unknown backbuffer format probably means the device can't do windowed - return false; - } - - if (BitDepth==32 && D3DInterface->CheckDeviceType(0,D3DDEVTYPE_HAL,desktop_mode.Format,D3DFMT_A8R8G8B8, TRUE) == D3D_OK) - { //promote 32-bit modes to include destination alpha - _PresentParameters.BackBufferFormat = D3DFMT_A8R8G8B8; - } - - /* - ** Find a appropriate Z buffer - */ - if (!Find_Z_Mode(DisplayFormat,_PresentParameters.BackBufferFormat,&_PresentParameters.AutoDepthStencilFormat)) - { - // If opening 32 bit mode failed, try 16 bit, even if the desktop happens to be 32 bit - if (BitDepth==32) { - BitDepth=16; - _PresentParameters.BackBufferFormat=D3DFMT_R5G6B5; - if (!Find_Z_Mode(_PresentParameters.BackBufferFormat,_PresentParameters.BackBufferFormat,&_PresentParameters.AutoDepthStencilFormat)) { - _PresentParameters.AutoDepthStencilFormat=D3DFMT_UNKNOWN; - } - } - else { - _PresentParameters.AutoDepthStencilFormat=D3DFMT_UNKNOWN; - } - } - - } else { - - /* - ** Try to find a mode that matches the user's desired bit-depth. - */ - Find_Color_And_Z_Mode(ResolutionWidth,ResolutionHeight,BitDepth,&DisplayFormat, - &_PresentParameters.BackBufferFormat,&_PresentParameters.AutoDepthStencilFormat); - } - - /* - ** Time to actually create the device. - */ - if (_PresentParameters.AutoDepthStencilFormat==D3DFMT_UNKNOWN) { - if (BitDepth==32) { - _PresentParameters.AutoDepthStencilFormat=D3DFMT_D32; - } - else { - _PresentParameters.AutoDepthStencilFormat=D3DFMT_D16; - } - } - - StringClass displayFormat; - StringClass backbufferFormat; - - Get_Format_Name(DisplayFormat,&displayFormat); - Get_Format_Name(_PresentParameters.BackBufferFormat,&backbufferFormat); - - WWDEBUG_SAY(("Using Display/BackBuffer Formats: %s/%s",displayFormat.str(),backbufferFormat.str())); - - bool ret; - - if (reset_device) - { - WWDEBUG_SAY(("DX8Wrapper::Set_Render_Device is resetting the device.")); - ret = Reset_Device(restore_assets); //reset device without restoring data - we're likely switching out of the app. - } - else - ret = Create_Device(); - - WWDEBUG_SAY(("Reset/Create_Device done, reset_device=%d, restore_assets=%d", reset_device, restore_assets)); - - return ret; -} - -bool DX8Wrapper::Set_Next_Render_Device(void) -{ - int new_dev = (CurRenderDevice + 1) % _RenderDeviceNameTable.Count(); - return Set_Render_Device(new_dev); -} - -bool DX8Wrapper::Toggle_Windowed(void) -{ -#ifdef WW3D_DX8 - // State OK? - assert (IsInitted); - if (IsInitted) { - - // Get information about the current render device's resolutions - const RenderDeviceDescClass &render_device = Get_Render_Device_Desc (); - const DynamicVectorClass &resolutions = render_device.Enumerate_Resolutions (); - - // Loop through all the resolutions supported by the current device. - // If we aren't currently running under one of these resolutions, - // then we should probably to the closest resolution before - // toggling the windowed state. - int curr_res = -1; - for (int res = 0; - (res < resolutions.Count ()) && (curr_res == -1); - res ++) { - - // Is this the resolution we are looking for? - if ((resolutions[res].Width == ResolutionWidth) && - (resolutions[res].Height == ResolutionHeight) && - (resolutions[res].BitDepth == BitDepth)) { - curr_res = res; - } - } - - if (curr_res == -1) { - - // We don't match any of the standard resolutions, - // so set the first resolution and toggle the windowed state. - return Set_Device_Resolution (resolutions[0].Width, - resolutions[0].Height, - resolutions[0].BitDepth, - !IsWindowed, true); - } else { - - // Toggle the windowed state - return Set_Device_Resolution (-1, -1, -1, !IsWindowed, true); - } - } -#endif //WW3D_DX8 - - return false; -} - -void DX8Wrapper::Set_Swap_Interval(int swap) -{ - switch (swap) { - case 0: _PresentParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; break; - case 1: _PresentParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_ONE ; break; - case 2: _PresentParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_TWO; break; - case 3: _PresentParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_THREE; break; - default: _PresentParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_ONE ; break; - } - - WWDEBUG_SAY(("DX8Wrapper::Set_Swap_Interval is resetting the device.")); - Reset_Device(); -} - -int DX8Wrapper::Get_Swap_Interval(void) -{ - return _PresentParameters.FullScreen_PresentationInterval; -} - -bool DX8Wrapper::Has_Stencil(void) -{ - bool has_stencil = (_PresentParameters.AutoDepthStencilFormat == D3DFMT_D24S8 || - _PresentParameters.AutoDepthStencilFormat == D3DFMT_D24X4S4); - return has_stencil; -} - -int DX8Wrapper::Get_Render_Device_Count(void) -{ - return _RenderDeviceNameTable.Count(); - -} -int DX8Wrapper::Get_Render_Device(void) -{ - assert(IsInitted); - return CurRenderDevice; -} - -const RenderDeviceDescClass & DX8Wrapper::Get_Render_Device_Desc(int deviceidx) -{ - WWASSERT(IsInitted); - - if ((deviceidx == -1) && (CurRenderDevice == -1)) { - CurRenderDevice = 0; - } - - // if the device index is -1 then we want the current device - if (deviceidx == -1) { - WWASSERT(CurRenderDevice >= 0); - WWASSERT(CurRenderDevice < _RenderDeviceNameTable.Count()); - return _RenderDeviceDescriptionTable[CurRenderDevice]; - } - - // We can only ask for multiple device information if the devices - // have been detected. - WWASSERT(deviceidx >= 0); - WWASSERT(deviceidx < _RenderDeviceNameTable.Count()); - return _RenderDeviceDescriptionTable[deviceidx]; -} - -const char * DX8Wrapper::Get_Render_Device_Name(int device_index) -{ - device_index = device_index % _RenderDeviceShortNameTable.Count(); - return _RenderDeviceShortNameTable[device_index]; -} - -bool DX8Wrapper::Set_Device_Resolution(int width,int height,int bits,int windowed, bool resize_window) -{ - if (D3DDevice != NULL) { - - if (width != -1) { - _PresentParameters.BackBufferWidth = ResolutionWidth = width; - } - if (height != -1) { - _PresentParameters.BackBufferHeight = ResolutionHeight = height; - } - if (resize_window) - { - Resize_And_Position_Window(); - } -#pragma message("TODO: support changing windowed status and changing the bit depth") - WWDEBUG_SAY(("DX8Wrapper::Set_Device_Resolution is resetting the device.")); - return Reset_Device(); - } else { - return false; - } -} - -void DX8Wrapper::Get_Device_Resolution(int & set_w,int & set_h,int & set_bits,bool & set_windowed) -{ - WWASSERT(IsInitted); - - set_w = ResolutionWidth; - set_h = ResolutionHeight; - set_bits = BitDepth; - set_windowed = IsWindowed; - - return ; -} - -void DX8Wrapper::Get_Render_Target_Resolution(int & set_w,int & set_h,int & set_bits,bool & set_windowed) -{ - WWASSERT(IsInitted); - - if (CurrentRenderTarget != NULL) { - D3DSURFACE_DESC info; - CurrentRenderTarget->GetDesc (&info); - - set_w = info.Width; - set_h = info.Height; - set_bits = BitDepth; // should we get the actual bit depth of the target? - set_windowed = IsWindowed; // this doesn't really make sense for render targets (shouldn't matter)... - - } else { - Get_Device_Resolution (set_w, set_h, set_bits, set_windowed); - } - - return ; -} - -bool DX8Wrapper::Registry_Save_Render_Device( const char * sub_key ) -{ - int width, height, depth; - bool windowed; - Get_Device_Resolution(width, height, depth, windowed); - return Registry_Save_Render_Device(sub_key, CurRenderDevice, ResolutionWidth, ResolutionHeight, BitDepth, IsWindowed, TextureBitDepth); -} - -bool DX8Wrapper::Registry_Save_Render_Device( const char *sub_key, int device, int width, int height, int depth, bool windowed, int texture_depth) -{ - RegistryClass * registry = W3DNEW RegistryClass( sub_key ); - WWASSERT( registry ); - - if ( !registry->Is_Valid() ) { - delete registry; - WWDEBUG_SAY(( "Error getting Registry" )); - return false; - } - - registry->Set_String( VALUE_NAME_RENDER_DEVICE_NAME, - _RenderDeviceShortNameTable[device] ); - registry->Set_Int( VALUE_NAME_RENDER_DEVICE_WIDTH, width ); - registry->Set_Int( VALUE_NAME_RENDER_DEVICE_HEIGHT, height ); - registry->Set_Int( VALUE_NAME_RENDER_DEVICE_DEPTH, depth ); - registry->Set_Int( VALUE_NAME_RENDER_DEVICE_WINDOWED, windowed ); - registry->Set_Int( VALUE_NAME_RENDER_DEVICE_TEXTURE_DEPTH, texture_depth ); - - delete registry; - return true; -} - -bool DX8Wrapper::Registry_Load_Render_Device( const char * sub_key, bool resize_window ) -{ - char name[ 200 ]; - int width,height,depth,windowed; - - if ( Registry_Load_Render_Device( sub_key, - name, - sizeof(name), - width, - height, - depth, - windowed, - TextureBitDepth) && - (*name != 0)) - { - WWDEBUG_SAY(( "Device %s (%d X %d) %d bit windowed:%d", name,width,height,depth,windowed)); - - if (TextureBitDepth==16 || TextureBitDepth==32) { -// WWDEBUG_SAY(( "Texture depth %d", TextureBitDepth)); - } else { - WWDEBUG_SAY(( "Invalid texture depth %d, switching to 16 bits", TextureBitDepth)); - TextureBitDepth=16; - } - - -// _RenderDeviceDescriptionTable. - - - if ( Set_Render_Device( name, width,height,depth,windowed, resize_window ) != true) { - if (depth==16) depth=32; - else depth=16; - if ( Set_Render_Device( name, width,height,depth,windowed, resize_window ) == true) { - return true; - } - if (depth==16) depth=32; - else depth=16; - // we'll test resolutions down, so if start is 640, increase to begin with... - if (width==640) { - width=1024; - height=768; - } - for(;;) { - if (width>2048) { - width=2048; - height=1536; - } - else if (width>1920) { - width=1920; - height=1440; - } - else if (width>1600) { - width=1600; - height=1200; - } - else if (width>1280) { - width=1280; - height=1024; - } - else if (width>1024) { - width=1024; - height=768; - } - else if (width>800) { - width=800; - height=600; - } - else if (width!=640) { - width=640; - height=480; - } - else { - return Set_Any_Render_Device(); - } - for (int i=0;i<2;++i) { - if ( Set_Render_Device( name, width,height,depth,windowed, resize_window ) == true) { - return true; - } - if (depth==16) depth=32; - else depth=16; - } - } - } - - return true; - } - - WWDEBUG_SAY(( "Error getting Registry" )); - - return Set_Any_Render_Device(); -} - -bool DX8Wrapper::Registry_Load_Render_Device( const char * sub_key, char *device, int device_len, int &width, int &height, int &depth, int &windowed, int &texture_depth) -{ - RegistryClass registry( sub_key ); - - if ( registry.Is_Valid() ) { - registry.Get_String( VALUE_NAME_RENDER_DEVICE_NAME, - device, device_len); - - width = registry.Get_Int( VALUE_NAME_RENDER_DEVICE_WIDTH, -1 ); - height = registry.Get_Int( VALUE_NAME_RENDER_DEVICE_HEIGHT, -1 ); - depth = registry.Get_Int( VALUE_NAME_RENDER_DEVICE_DEPTH, -1 ); - windowed = registry.Get_Int( VALUE_NAME_RENDER_DEVICE_WINDOWED, -1 ); - texture_depth = registry.Get_Int( VALUE_NAME_RENDER_DEVICE_TEXTURE_DEPTH, -1 ); - return true; - } - *device=0; - width=-1; - height=-1; - depth=-1; - windowed=-1; - texture_depth=-1; - return false; -} - - -bool DX8Wrapper::Find_Color_And_Z_Mode(int resx,int resy,int bitdepth,D3DFORMAT * set_colorbuffer,D3DFORMAT * set_backbuffer,D3DFORMAT * set_zmode) -{ - static D3DFORMAT _formats16[] = - { - D3DFMT_R5G6B5, - D3DFMT_X1R5G5B5, - D3DFMT_A1R5G5B5 - }; - - static D3DFORMAT _formats32[] = - { - D3DFMT_A8R8G8B8, - D3DFMT_X8R8G8B8, - D3DFMT_R8G8B8, - }; - - /* - ** Select the table that we're going to use to search for a valid backbuffer format - */ - D3DFORMAT * format_table = NULL; - int format_count = 0; - - if (BitDepth == 16) { - format_table = _formats16; - format_count = sizeof(_formats16) / sizeof(D3DFORMAT); - } else { - format_table = _formats32; - format_count = sizeof(_formats32) / sizeof(D3DFORMAT); - } - - /* - ** now search for a valid format - */ - bool found = false; - unsigned int mode = 0; - - int format_index=0; - for (; format_index < format_count; format_index++) { - found |= Find_Color_Mode(format_table[format_index],resx,resy,&mode); - if (found) break; - } - - if (!found) { - return false; - } else { - *set_backbuffer=*set_colorbuffer = format_table[format_index]; - } - - if (bitdepth==32 && *set_colorbuffer == D3DFMT_X8R8G8B8 && D3DInterface->CheckDeviceType(0,D3DDEVTYPE_HAL,*set_colorbuffer,D3DFMT_A8R8G8B8, TRUE) == D3D_OK) - { //promote 32-bit modes to include destination alpha when supported - *set_backbuffer = D3DFMT_A8R8G8B8; - } - - /* - ** We found a backbuffer format, now find a zbuffer format - */ - return Find_Z_Mode(*set_colorbuffer,*set_backbuffer, set_zmode); -}; - - -// find the resolution mode with at least resx,resy with the highest supported -// refresh rate -bool DX8Wrapper::Find_Color_Mode(D3DFORMAT colorbuffer, int resx, int resy, UINT *mode) -{ - UINT i,j,modemax; - UINT rx,ry; - D3DDISPLAYMODE dmode; - ::ZeroMemory(&dmode, sizeof(D3DDISPLAYMODE)); - - rx=(unsigned int) resx; - ry=(unsigned int) resy; - - bool found=false; - - modemax=D3DInterface->GetAdapterModeCount(D3DADAPTER_DEFAULT); - - i=0; - - while (iEnumAdapterModes(D3DADAPTER_DEFAULT, i, &dmode); - if (dmode.Width==rx && dmode.Height==ry && dmode.Format==colorbuffer) { - WWDEBUG_SAY(("Found valid color mode. Width = %d Height = %d Format = %d",dmode.Width,dmode.Height,dmode.Format)); - found=true; - } - i++; - } - - i--; // this is the first valid mode - - // no match - if (!found) { - WWDEBUG_SAY(("Failed to find a valid color mode")); - return false; - } - - // go to the highest refresh rate in this mode - bool stillok=true; - - j=i; - while (jEnumAdapterModes(D3DADAPTER_DEFAULT, j, &dmode); - if (dmode.Width==rx && dmode.Height==ry && dmode.Format==colorbuffer) - stillok=true; else stillok=false; - j++; - } - - if (stillok==false) *mode=j-2; - else *mode=i; - - return true; -} - -// Helper function to find a Z buffer mode for the colorbuffer -// Will look for greatest Z precision -bool DX8Wrapper::Find_Z_Mode(D3DFORMAT colorbuffer,D3DFORMAT backbuffer, D3DFORMAT *zmode) -{ - //MW: Swapped the next 2 tests so that Stencil modes get tested first. - if (Test_Z_Mode(colorbuffer,backbuffer,D3DFMT_D24S8)) - { - *zmode=D3DFMT_D24S8; - WWDEBUG_SAY(("Found zbuffer mode D3DFMT_D24S8")); - return true; - } - - if (Test_Z_Mode(colorbuffer,backbuffer,D3DFMT_D32)) - { - *zmode=D3DFMT_D32; - WWDEBUG_SAY(("Found zbuffer mode D3DFMT_D32")); - return true; - } - - if (Test_Z_Mode(colorbuffer,backbuffer,D3DFMT_D24X8)) - { - *zmode=D3DFMT_D24X8; - WWDEBUG_SAY(("Found zbuffer mode D3DFMT_D24X8")); - return true; - } - - if (Test_Z_Mode(colorbuffer,backbuffer,D3DFMT_D24X4S4)) - { - *zmode=D3DFMT_D24X4S4; - WWDEBUG_SAY(("Found zbuffer mode D3DFMT_D24X4S4")); - return true; - } - - if (Test_Z_Mode(colorbuffer,backbuffer,D3DFMT_D16)) - { - *zmode=D3DFMT_D16; - WWDEBUG_SAY(("Found zbuffer mode D3DFMT_D16")); - return true; - } - - if (Test_Z_Mode(colorbuffer,backbuffer,D3DFMT_D15S1)) - { - *zmode=D3DFMT_D15S1; - WWDEBUG_SAY(("Found zbuffer mode D3DFMT_D15S1")); - return true; - } - - // can't find a match - WWDEBUG_SAY(("Failed to find a valid zbuffer mode")); - return false; -} - -bool DX8Wrapper::Test_Z_Mode(D3DFORMAT colorbuffer,D3DFORMAT backbuffer, D3DFORMAT zmode) -{ - // See if we have this mode first - if (FAILED(D3DInterface->CheckDeviceFormat(D3DADAPTER_DEFAULT,WW3D_DEVTYPE, - colorbuffer,D3DUSAGE_DEPTHSTENCIL,D3DRTYPE_SURFACE,zmode))) - { - WWDEBUG_SAY(("CheckDeviceFormat failed. Colorbuffer format = %d Zbufferformat = %d",colorbuffer,zmode)); - return false; - } - - // Then see if it matches the color buffer - if(FAILED(D3DInterface->CheckDepthStencilMatch(D3DADAPTER_DEFAULT, WW3D_DEVTYPE, - colorbuffer,backbuffer,zmode))) - { - WWDEBUG_SAY(("CheckDepthStencilMatch failed. Colorbuffer format = %d Backbuffer format = %d Zbufferformat = %d",colorbuffer,backbuffer,zmode)); - return false; - } - return true; -} - - -void DX8Wrapper::Reset_Statistics() -{ - matrix_changes = 0; - material_changes = 0; - vertex_buffer_changes = 0; - index_buffer_changes = 0; - light_changes = 0; - texture_changes = 0; - render_state_changes =0; - texture_stage_state_changes =0; - draw_calls =0; - - number_of_DX8_calls = 0; - last_frame_matrix_changes = 0; - last_frame_material_changes = 0; - last_frame_vertex_buffer_changes = 0; - last_frame_index_buffer_changes = 0; - last_frame_light_changes = 0; - last_frame_texture_changes = 0; - last_frame_render_state_changes = 0; - last_frame_texture_stage_state_changes = 0; - last_frame_number_of_DX8_calls = 0; - last_frame_draw_calls =0; -} - -void DX8Wrapper::Begin_Statistics() -{ - matrix_changes=0; - material_changes=0; - vertex_buffer_changes=0; - index_buffer_changes=0; - light_changes=0; - texture_changes = 0; - render_state_changes =0; - texture_stage_state_changes =0; - number_of_DX8_calls=0; - draw_calls=0; -} - -void DX8Wrapper::End_Statistics() -{ - last_frame_matrix_changes=matrix_changes; - last_frame_material_changes=material_changes; - last_frame_vertex_buffer_changes=vertex_buffer_changes; - last_frame_index_buffer_changes=index_buffer_changes; - last_frame_light_changes=light_changes; - last_frame_texture_changes = texture_changes; - last_frame_render_state_changes = render_state_changes; - last_frame_texture_stage_state_changes = texture_stage_state_changes; - last_frame_number_of_DX8_calls=number_of_DX8_calls; - last_frame_draw_calls=draw_calls; -} - -unsigned DX8Wrapper::Get_Last_Frame_Matrix_Changes() { return last_frame_matrix_changes; } -unsigned DX8Wrapper::Get_Last_Frame_Material_Changes() { return last_frame_material_changes; } -unsigned DX8Wrapper::Get_Last_Frame_Vertex_Buffer_Changes() { return last_frame_vertex_buffer_changes; } -unsigned DX8Wrapper::Get_Last_Frame_Index_Buffer_Changes() { return last_frame_index_buffer_changes; } -unsigned DX8Wrapper::Get_Last_Frame_Light_Changes() { return last_frame_light_changes; } -unsigned DX8Wrapper::Get_Last_Frame_Texture_Changes() { return last_frame_texture_changes; } -unsigned DX8Wrapper::Get_Last_Frame_Render_State_Changes() { return last_frame_render_state_changes; } -unsigned DX8Wrapper::Get_Last_Frame_Texture_Stage_State_Changes() { return last_frame_texture_stage_state_changes; } -unsigned DX8Wrapper::Get_Last_Frame_DX8_Calls() { return last_frame_number_of_DX8_calls; } -unsigned DX8Wrapper::Get_Last_Frame_Draw_Calls() { return last_frame_draw_calls; } -unsigned long DX8Wrapper::Get_FrameCount(void) {return FrameCount;} - -void DX8_Assert() -{ - WWASSERT(DX8Wrapper::_Get_D3D8()); - DX8_THREAD_ASSERT(); -} - -void DX8Wrapper::Begin_Scene(void) -{ - DX8_THREAD_ASSERT(); - -#if ENABLE_EMBEDDED_BROWSER - DX8WebBrowser::Update(); -#endif - - DX8CALL(BeginScene()); - - DX8WebBrowser::Update(); -} - -void DX8Wrapper::End_Scene(bool flip_frames) -{ - DX8_THREAD_ASSERT(); - DX8CALL(EndScene()); - - DX8WebBrowser::Render(0); - - if (flip_frames) { - DX8_Assert(); - HRESULT hr; - { - WWPROFILE("DX8Device::Present()"); - hr=_Get_D3D_Device8()->Present(NULL, NULL, NULL, NULL); - } - - number_of_DX8_calls++; - - if (SUCCEEDED(hr)) { -#ifdef EXTENDED_STATS - if (stats.m_sleepTime) { - ::Sleep(stats.m_sleepTime); - } -#endif - IsDeviceLost=false; - FrameCount++; - } - else { - IsDeviceLost=true; - } - - // If the device was lost we need to check for cooperative level and possibly reset the device - if (hr==D3DERR_DEVICELOST) { - hr=_Get_D3D_Device8()->TestCooperativeLevel(); - if (hr==D3DERR_DEVICENOTRESET) { - WWDEBUG_SAY(("DX8Wrapper::End_Scene is resetting the device.")); - Reset_Device(); - } - else { - // Sleep it not active - ThreadClass::Sleep_Ms(200); - } - } - else { - DX8_ErrorCode(hr); - } - } - - // Each frame, release all of the buffers and textures. - Set_Vertex_Buffer(NULL); - Set_Index_Buffer(NULL,0); - for (int i=0;iGet_Max_Textures_Per_Pass();++i) Set_Texture(i,NULL); - Set_Material(NULL); -} - - -void DX8Wrapper::Flip_To_Primary(void) -{ - // If we are fullscreen and the current frame is odd then we need - // to force a page flip to ensure that the first buffer in the flipping - // chain is the one visible. - if (!IsWindowed) { - DX8_Assert(); - - int numBuffers = (_PresentParameters.BackBufferCount + 1); - int visibleBuffer = (FrameCount % numBuffers); - int flipCount = ((numBuffers - visibleBuffer) % numBuffers); - int resetAttempts = 0; - - while ((flipCount > 0) && (resetAttempts < 3)) { - HRESULT hr = _Get_D3D_Device8()->TestCooperativeLevel(); - - if (FAILED(hr)) { - WWDEBUG_SAY(("TestCooperativeLevel Failed!")); - - if (D3DERR_DEVICELOST == hr) { - IsDeviceLost=true; - WWDEBUG_SAY(("DEVICELOST: Cannot flip to primary.")); - return; - } - IsDeviceLost=false; - - if (D3DERR_DEVICENOTRESET == hr) { - WWDEBUG_SAY(("DEVICENOTRESET")); - Reset_Device(); - resetAttempts++; - } - } else { - WWDEBUG_SAY(("Flipping: %ld", FrameCount)); - hr = _Get_D3D_Device8()->Present(NULL, NULL, NULL, NULL); - - if (SUCCEEDED(hr)) { - IsDeviceLost=false; - FrameCount++; - WWDEBUG_SAY(("Flip to primary succeeded %ld", FrameCount)); - } - else { - IsDeviceLost=true; - } - } - - --flipCount; - } - } -} - - -//********************************************************************************************** -//! Clear current render device -/*! KM -/* 5/17/02 KM Fixed support for render to texture with depth/stencil buffers -*/ -void DX8Wrapper::Clear(bool clear_color, bool clear_z_stencil, const Vector3 &color, float dest_alpha, float z, unsigned int stencil) -{ - DX8_THREAD_ASSERT(); - - // If we try to clear a stencil buffer which is not there, the entire call will fail - // KJM fixed this to get format from back buffer (incase render to texture is used) - /*bool has_stencil = ( _PresentParameters.AutoDepthStencilFormat == D3DFMT_D15S1 || - _PresentParameters.AutoDepthStencilFormat == D3DFMT_D24S8 || - _PresentParameters.AutoDepthStencilFormat == D3DFMT_D24X4S4);*/ - bool has_stencil=false; - IDirect3DSurface8* depthbuffer; - - _Get_D3D_Device8()->GetDepthStencilSurface(&depthbuffer); - number_of_DX8_calls++; - - if (depthbuffer) - { - D3DSURFACE_DESC desc; - depthbuffer->GetDesc(&desc); - has_stencil= - ( - desc.Format==D3DFMT_D15S1 || - desc.Format==D3DFMT_D24S8 || - desc.Format==D3DFMT_D24X4S4 - ); - - // release ref - depthbuffer->Release(); - } - - DWORD flags = 0; - if (clear_color) flags |= D3DCLEAR_TARGET; - if (clear_z_stencil) flags |= D3DCLEAR_ZBUFFER; - if (clear_z_stencil && has_stencil) flags |= D3DCLEAR_STENCIL; - if (flags) - { - DX8CALL(Clear(0, NULL, flags, Convert_Color(color,dest_alpha), z, stencil)); - } -} - -void DX8Wrapper::Set_Viewport(CONST D3DVIEWPORT8* pViewport) -{ - DX8_THREAD_ASSERT(); - DX8CALL(SetViewport(pViewport)); -} - -// ---------------------------------------------------------------------------- -// -// Set vertex buffer. A reference to previous vertex buffer is released and -// this one is assigned the current vertex buffer. The DX8 vertex buffer will -// actually be set in Apply() which is called by Draw_Indexed_Triangles(). -// -// ---------------------------------------------------------------------------- - -void DX8Wrapper::Set_Vertex_Buffer(const VertexBufferClass* vb, unsigned stream) -{ - render_state.vba_offset=0; - render_state.vba_count=0; - if (render_state.vertex_buffers[stream]) { - render_state.vertex_buffers[stream]->Release_Engine_Ref(); - } - REF_PTR_SET(render_state.vertex_buffers[stream],const_cast(vb)); - if (vb) { - vb->Add_Engine_Ref(); - render_state.vertex_buffer_types[stream]=vb->Type(); - } - else { - render_state.vertex_buffer_types[stream]=BUFFER_TYPE_INVALID; - } - render_state_changed|=VERTEX_BUFFER_CHANGED; -} - -// ---------------------------------------------------------------------------- -// -// Set index buffer. A reference to previous index buffer is released and -// this one is assigned the current index buffer. The DX8 index buffer will -// actually be set in Apply() which is called by Draw_Indexed_Triangles(). -// -// ---------------------------------------------------------------------------- - -void DX8Wrapper::Set_Index_Buffer(const IndexBufferClass* ib,unsigned short index_base_offset) -{ - render_state.iba_offset=0; - if (render_state.index_buffer) { - render_state.index_buffer->Release_Engine_Ref(); - } - REF_PTR_SET(render_state.index_buffer,const_cast(ib)); - render_state.index_base_offset=index_base_offset; - if (ib) { - ib->Add_Engine_Ref(); - render_state.index_buffer_type=ib->Type(); - } - else { - render_state.index_buffer_type=BUFFER_TYPE_INVALID; - } - render_state_changed|=INDEX_BUFFER_CHANGED; -} - -// ---------------------------------------------------------------------------- -// -// Set vertex buffer using dynamic access object. -// -// ---------------------------------------------------------------------------- - -void DX8Wrapper::Set_Vertex_Buffer(const DynamicVBAccessClass& vba_) -{ - // Release all streams (only one stream allowed in the legacy pipeline) - for (int i=1;iRelease_Engine_Ref(); - DynamicVBAccessClass& vba=const_cast(vba_); - render_state.vertex_buffer_types[0]=vba.Get_Type(); - render_state.vba_offset=vba.VertexBufferOffset; - render_state.vba_count=vba.Get_Vertex_Count(); - REF_PTR_SET(render_state.vertex_buffers[0],vba.VertexBuffer); - render_state.vertex_buffers[0]->Add_Engine_Ref(); - render_state_changed|=VERTEX_BUFFER_CHANGED; - render_state_changed|=INDEX_BUFFER_CHANGED; // vba_offset changes so index buffer needs to be reset as well. -} - -// ---------------------------------------------------------------------------- -// -// Set index buffer using dynamic access object. -// -// ---------------------------------------------------------------------------- - -void DX8Wrapper::Set_Index_Buffer(const DynamicIBAccessClass& iba_,unsigned short index_base_offset) -{ - if (render_state.index_buffer) render_state.index_buffer->Release_Engine_Ref(); - - DynamicIBAccessClass& iba=const_cast(iba_); - render_state.index_base_offset=index_base_offset; - render_state.index_buffer_type=iba.Get_Type(); - render_state.iba_offset=iba.IndexBufferOffset; - REF_PTR_SET(render_state.index_buffer,iba.IndexBuffer); - render_state.index_buffer->Add_Engine_Ref(); - render_state_changed|=INDEX_BUFFER_CHANGED; -} - -// ---------------------------------------------------------------------------- -// -// Private function for the special case of rendering polygons from sorting -// index and vertex buffers. -// -// ---------------------------------------------------------------------------- - -void DX8Wrapper::Draw_Sorting_IB_VB( - unsigned primitive_type, - unsigned short start_index, - unsigned short polygon_count, - unsigned short min_vertex_index, - unsigned short vertex_count) -{ - WWASSERT(render_state.vertex_buffer_types[0]==BUFFER_TYPE_SORTING || render_state.vertex_buffer_types[0]==BUFFER_TYPE_DYNAMIC_SORTING); - WWASSERT(render_state.index_buffer_type==BUFFER_TYPE_SORTING || render_state.index_buffer_type==BUFFER_TYPE_DYNAMIC_SORTING); - - // Fill dynamic vertex buffer with sorting vertex buffer vertices - DynamicVBAccessClass dyn_vb_access(BUFFER_TYPE_DYNAMIC_DX8,dynamic_fvf_type,vertex_count); - { - DynamicVBAccessClass::WriteLockClass lock(&dyn_vb_access); - VertexFormatXYZNDUV2* src = static_cast(render_state.vertex_buffers[0])->VertexBuffer; - VertexFormatXYZNDUV2* dest= lock.Get_Formatted_Vertex_Array(); - src += render_state.vba_offset + render_state.index_base_offset + min_vertex_index; - unsigned size = dyn_vb_access.FVF_Info().Get_FVF_Size()*vertex_count/sizeof(unsigned); - unsigned *dest_u =(unsigned*) dest; - unsigned *src_u = (unsigned*) src; - - for (unsigned i=0;i(dyn_vb_access.VertexBuffer)->Get_DX8_Vertex_Buffer(), - dyn_vb_access.FVF_Info().Get_FVF_Size())); - // If using FVF format VB, set the FVF as vertex shader (may not be needed here KM) - unsigned fvf=dyn_vb_access.FVF_Info().Get_FVF(); - if (fvf!=0) { - DX8CALL(SetVertexShader(fvf)); - } - DX8_RECORD_VERTEX_BUFFER_CHANGE(); - - unsigned index_count=0; - switch (primitive_type) { - case D3DPT_TRIANGLELIST: index_count=polygon_count*3; break; - case D3DPT_TRIANGLESTRIP: index_count=polygon_count+2; break; - case D3DPT_TRIANGLEFAN: index_count=polygon_count+2; break; - default: WWASSERT(0); break; // Unsupported primitive type - } - - // Fill dynamic index buffer with sorting index buffer vertices - DynamicIBAccessClass dyn_ib_access(BUFFER_TYPE_DYNAMIC_DX8,index_count); - { - DynamicIBAccessClass::WriteLockClass lock(&dyn_ib_access); - unsigned short* dest=lock.Get_Index_Array(); - unsigned short* src=NULL; - src=static_cast(render_state.index_buffer)->index_buffer; - src+=render_state.iba_offset+start_index; - - for (unsigned short i=0;i(dyn_ib_access.IndexBuffer)->Get_DX8_Index_Buffer(), - dyn_vb_access.VertexBufferOffset)); - DX8_RECORD_INDEX_BUFFER_CHANGE(); - - DX8_RECORD_DRAW_CALLS(); - DX8CALL(DrawIndexedPrimitive( - D3DPT_TRIANGLELIST, - 0, // start vertex - vertex_count, - dyn_ib_access.IndexBufferOffset, - polygon_count)); - - DX8_RECORD_RENDER(polygon_count,vertex_count,render_state.shader); -} - -// ---------------------------------------------------------------------------- -// -// -// -// ---------------------------------------------------------------------------- - -void DX8Wrapper::Draw( - unsigned primitive_type, - unsigned short start_index, - unsigned short polygon_count, - unsigned short min_vertex_index, - unsigned short vertex_count) -{ - if (DrawPolygonLowBoundLimit && DrawPolygonLowBoundLimit>=polygon_count) return; - - DX8_THREAD_ASSERT(); - SNAPSHOT_SAY(("DX8 - draw")); - - Apply_Render_State_Changes(); - - // Debug feature to disable triangle drawing... - if (!_Is_Triangle_Draw_Enabled()) return; - -#ifdef MESH_RENDER_SNAPSHOT_ENABLED - if (WW3D::Is_Snapshot_Activated()) { - unsigned long passes=0; - SNAPSHOT_SAY(("ValidateDevice:")); - HRESULT res=D3DDevice->ValidateDevice(&passes); - switch (res) { - case D3D_OK: - SNAPSHOT_SAY(("OK")); - break; - - case D3DERR_CONFLICTINGTEXTUREFILTER: - SNAPSHOT_SAY(("D3DERR_CONFLICTINGTEXTUREFILTER")); - break; - case D3DERR_CONFLICTINGTEXTUREPALETTE: - SNAPSHOT_SAY(("D3DERR_CONFLICTINGTEXTUREPALETTE")); - break; - case D3DERR_DEVICELOST: - SNAPSHOT_SAY(("D3DERR_DEVICELOST")); - break; - case D3DERR_TOOMANYOPERATIONS: - SNAPSHOT_SAY(("D3DERR_TOOMANYOPERATIONS")); - break; - case D3DERR_UNSUPPORTEDALPHAARG: - SNAPSHOT_SAY(("D3DERR_UNSUPPORTEDALPHAARG")); - break; - case D3DERR_UNSUPPORTEDALPHAOPERATION: - SNAPSHOT_SAY(("D3DERR_UNSUPPORTEDALPHAOPERATION")); - break; - case D3DERR_UNSUPPORTEDCOLORARG: - SNAPSHOT_SAY(("D3DERR_UNSUPPORTEDCOLORARG")); - break; - case D3DERR_UNSUPPORTEDCOLOROPERATION: - SNAPSHOT_SAY(("D3DERR_UNSUPPORTEDCOLOROPERATION")); - break; - case D3DERR_UNSUPPORTEDFACTORVALUE: - SNAPSHOT_SAY(("D3DERR_UNSUPPORTEDFACTORVALUE")); - break; - case D3DERR_UNSUPPORTEDTEXTUREFILTER: - SNAPSHOT_SAY(("D3DERR_UNSUPPORTEDTEXTUREFILTER")); - break; - case D3DERR_WRONGTEXTUREFORMAT: - SNAPSHOT_SAY(("D3DERR_WRONGTEXTUREFORMAT")); - break; - default: - SNAPSHOT_SAY(("UNKNOWN Error")); - break; - } - } -#endif // MESH_RENDER_SHAPSHOT_ENABLED - - - SNAPSHOT_SAY(("DX8 - draw %d polygons (%d vertices)",polygon_count,vertex_count)); - - if (vertex_count<3) { - min_vertex_index=0; - switch (render_state.vertex_buffer_types[0]) { - case BUFFER_TYPE_DX8: - case BUFFER_TYPE_SORTING: - vertex_count=render_state.vertex_buffers[0]->Get_Vertex_Count()-render_state.index_base_offset-render_state.vba_offset-min_vertex_index; - break; - case BUFFER_TYPE_DYNAMIC_DX8: - case BUFFER_TYPE_DYNAMIC_SORTING: - vertex_count=render_state.vba_count; - break; - } - } - - switch (render_state.vertex_buffer_types[0]) { - case BUFFER_TYPE_DX8: - case BUFFER_TYPE_DYNAMIC_DX8: - switch (render_state.index_buffer_type) { - case BUFFER_TYPE_DX8: - case BUFFER_TYPE_DYNAMIC_DX8: - { -/* if ((start_index+render_state.iba_offset+polygon_count*3) > render_state.index_buffer->Get_Index_Count()) - { WWASSERT_PRINT(0,"OVERFLOWING INDEX BUFFER"); - ///@todo: MUST FIND OUT WHY THIS HAPPENS WITH LOTS OF PARTICLES ON BIG FIGHT! -MW - break; - }*/ - DX8_RECORD_RENDER(polygon_count,vertex_count,render_state.shader); - DX8_RECORD_DRAW_CALLS(); - DX8CALL(DrawIndexedPrimitive( - (D3DPRIMITIVETYPE)primitive_type, - min_vertex_index, - vertex_count, - start_index+render_state.iba_offset, - polygon_count)); - } - break; - case BUFFER_TYPE_SORTING: - case BUFFER_TYPE_DYNAMIC_SORTING: - WWASSERT_PRINT(0,"VB and IB must of same type (sorting or dx8)"); - break; - case BUFFER_TYPE_INVALID: - WWASSERT(0); - break; - } - break; - case BUFFER_TYPE_SORTING: - case BUFFER_TYPE_DYNAMIC_SORTING: - switch (render_state.index_buffer_type) { - case BUFFER_TYPE_DX8: - case BUFFER_TYPE_DYNAMIC_DX8: - WWASSERT_PRINT(0,"VB and IB must of same type (sorting or dx8)"); - break; - case BUFFER_TYPE_SORTING: - case BUFFER_TYPE_DYNAMIC_SORTING: - Draw_Sorting_IB_VB(primitive_type,start_index,polygon_count,min_vertex_index,vertex_count); - break; - case BUFFER_TYPE_INVALID: - WWASSERT(0); - break; - } - break; - case BUFFER_TYPE_INVALID: - WWASSERT(0); - break; - } -} - -// ---------------------------------------------------------------------------- -// -// -// -// ---------------------------------------------------------------------------- - -void DX8Wrapper::Draw_Triangles( - unsigned buffer_type, - unsigned short start_index, - unsigned short polygon_count, - unsigned short min_vertex_index, - unsigned short vertex_count) -{ - if (buffer_type==BUFFER_TYPE_SORTING || buffer_type==BUFFER_TYPE_DYNAMIC_SORTING) { - SortingRendererClass::Insert_Triangles(start_index,polygon_count,min_vertex_index,vertex_count); - } - else { - Draw(D3DPT_TRIANGLELIST,start_index,polygon_count,min_vertex_index,vertex_count); - } -} - -// ---------------------------------------------------------------------------- -// -// -// -// ---------------------------------------------------------------------------- - -void DX8Wrapper::Draw_Triangles( - unsigned short start_index, - unsigned short polygon_count, - unsigned short min_vertex_index, - unsigned short vertex_count) -{ - Draw(D3DPT_TRIANGLELIST,start_index,polygon_count,min_vertex_index,vertex_count); -} - -// ---------------------------------------------------------------------------- -// -// -// -// ---------------------------------------------------------------------------- - -void DX8Wrapper::Draw_Strip( - unsigned short start_index, - unsigned short polygon_count, - unsigned short min_vertex_index, - unsigned short vertex_count) -{ - Draw(D3DPT_TRIANGLESTRIP,start_index,polygon_count,min_vertex_index,vertex_count); -} - -// ---------------------------------------------------------------------------- -// -// -// -// ---------------------------------------------------------------------------- - -void DX8Wrapper::Apply_Render_State_Changes() -{ - SNAPSHOT_SAY(("DX8Wrapper::Apply_Render_State_Changes()")); - - if (!render_state_changed) return; - if (render_state_changed&SHADER_CHANGED) { - SNAPSHOT_SAY(("DX8 - apply shader")); - render_state.shader.Apply(); - } - - unsigned mask=TEXTURE0_CHANGED; - int i=0; - for (;iGet_Max_Textures_Per_Pass();++i,mask<<=1) - { - if (render_state_changed&mask) - { - SNAPSHOT_SAY(("DX8 - apply texture %d (%s)",i,render_state.Textures[i] ? render_state.Textures[i]->Get_Full_Path().str() : "NULL")); - - if (render_state.Textures[i]) - { - render_state.Textures[i]->Apply(i); - } - else - { - TextureBaseClass::Apply_Null(i); - } - } - } - - if (render_state_changed&MATERIAL_CHANGED) - { - SNAPSHOT_SAY(("DX8 - apply material")); - VertexMaterialClass* material=const_cast(render_state.material); - if (material) - { - material->Apply(); - } - else VertexMaterialClass::Apply_Null(); - } - - if (render_state_changed&LIGHTS_CHANGED) - { - unsigned mask=LIGHT0_CHANGED; - for (unsigned index=0;index<4;++index,mask<<=1) { - if (render_state_changed&mask) { - SNAPSHOT_SAY(("DX8 - apply light %d",index)); - if (render_state.LightEnable[index]) { -#ifdef MESH_RENDER_SNAPSHOT_ENABLED - if ( WW3D::Is_Snapshot_Activated() ) { - D3DLIGHT8 * light = &(render_state.Lights[index]); - static const char * _light_types[] = { "Unknown", "Point","Spot", "Directional" }; - WWASSERT((light->Type >= 0) && (light->Type <= 3)); - - SNAPSHOT_SAY((" type = %s amb = %4.2f,%4.2f,%4.2f diff = %4.2f,%4.2f,%4.2f spec = %4.2f, %4.2f, %4.2f", - _light_types[light->Type], - light->Ambient.r,light->Ambient.g,light->Ambient.b, - light->Diffuse.r,light->Diffuse.g,light->Diffuse.b, - light->Specular.r,light->Specular.g,light->Specular.b )); - SNAPSHOT_SAY((" pos = %f, %f, %f dir = %f, %f, %f", - light->Position.x, light->Position.y, light->Position.z, - light->Direction.x, light->Direction.y, light->Direction.z )); - } -#endif - - Set_DX8_Light(index,&render_state.Lights[index]); - } - else { - Set_DX8_Light(index,NULL); - SNAPSHOT_SAY((" clearing light to NULL")); - } - } - } - } - - if (render_state_changed&WORLD_CHANGED) { - SNAPSHOT_SAY(("DX8 - apply world matrix")); - _Set_DX8_Transform(D3DTS_WORLD,render_state.world); - } - if (render_state_changed&VIEW_CHANGED) { - SNAPSHOT_SAY(("DX8 - apply view matrix")); - _Set_DX8_Transform(D3DTS_VIEW,render_state.view); - } - if (render_state_changed&VERTEX_BUFFER_CHANGED) { - SNAPSHOT_SAY(("DX8 - apply vb change")); - for (i=0;iType()) { - case BUFFER_TYPE_DX8: - case BUFFER_TYPE_DYNAMIC_DX8: - DX8CALL(SetStreamSource( - i, - static_cast(render_state.vertex_buffers[i])->Get_DX8_Vertex_Buffer(), - render_state.vertex_buffers[i]->FVF_Info().Get_FVF_Size())); - DX8_RECORD_VERTEX_BUFFER_CHANGE(); - { - // If the VB format is FVF, set the FVF as a vertex shader - unsigned fvf=render_state.vertex_buffers[i]->FVF_Info().Get_FVF(); - if (fvf!=0) { - Set_Vertex_Shader(fvf); - } - } - break; - case BUFFER_TYPE_SORTING: - case BUFFER_TYPE_DYNAMIC_SORTING: - break; - default: - WWASSERT(0); - } - } else { - DX8CALL(SetStreamSource(i,NULL,0)); - DX8_RECORD_VERTEX_BUFFER_CHANGE(); - } - } - } - if (render_state_changed&INDEX_BUFFER_CHANGED) { - SNAPSHOT_SAY(("DX8 - apply ib change")); - if (render_state.index_buffer) { - switch (render_state.index_buffer_type) {//->Type()) { - case BUFFER_TYPE_DX8: - case BUFFER_TYPE_DYNAMIC_DX8: - DX8CALL(SetIndices( - static_cast(render_state.index_buffer)->Get_DX8_Index_Buffer(), - render_state.index_base_offset+render_state.vba_offset)); - DX8_RECORD_INDEX_BUFFER_CHANGE(); - break; - case BUFFER_TYPE_SORTING: - case BUFFER_TYPE_DYNAMIC_SORTING: - break; - default: - WWASSERT(0); - } - } - else { - DX8CALL(SetIndices( - NULL, - 0)); - DX8_RECORD_INDEX_BUFFER_CHANGE(); - } - } - - render_state_changed&=((unsigned)WORLD_IDENTITY|(unsigned)VIEW_IDENTITY); - - SNAPSHOT_SAY(("DX8Wrapper::Apply_Render_State_Changes() - finished")); -} - -IDirect3DTexture8 * DX8Wrapper::_Create_DX8_Texture -( - unsigned int width, - unsigned int height, - WW3DFormat format, - MipCountType mip_level_count, - D3DPOOL pool, - bool rendertarget -) -{ - DX8_THREAD_ASSERT(); - DX8_Assert(); - IDirect3DTexture8 *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=D3DXCreateTexture( - DX8Wrapper::_Get_D3D_Device8(), - width, - height, - 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=D3DXCreateTexture( - DX8Wrapper::_Get_D3D_Device8(), - width, - height, - 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=D3DXCreateTexture( - DX8Wrapper::_Get_D3D_Device8(), - width, - height, - 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=D3DXCreateTexture( - DX8Wrapper::_Get_D3D_Device8(), - width, - height, - 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; -} - -IDirect3DTexture8 * DX8Wrapper::_Create_DX8_Texture -( - const char *filename, - MipCountType mip_level_count -) -{ - DX8_THREAD_ASSERT(); - DX8_Assert(); - IDirect3DTexture8 *texture = NULL; - - // NOTE: If the original image format is not supported as a texture format, it will - // automatically be converted to an appropriate format. - // NOTE: It is possible to get the size and format of the original image file from this - // function as well, so if we later want to second-guess D3DX's format conversion decisions - // we can do so after this function is called.. - unsigned result = D3DXCreateTextureFromFileExA( - _Get_D3D_Device8(), - filename, - D3DX_DEFAULT, - D3DX_DEFAULT, - mip_level_count,//create_mipmaps ? 0 : 1, - 0, - D3DFMT_UNKNOWN, - D3DPOOL_MANAGED, - D3DX_FILTER_BOX, - D3DX_FILTER_BOX, - 0, - NULL, - NULL, - &texture); - - if (result != D3D_OK) { - return MissingTexture::_Get_Missing_Texture(); - } - - // Make sure texture wasn't paletted! - D3DSURFACE_DESC desc; - texture->GetLevelDesc(0,&desc); - if (desc.Format==D3DFMT_P8) { - texture->Release(); - return MissingTexture::_Get_Missing_Texture(); - } - return texture; -} - -IDirect3DTexture8 * DX8Wrapper::_Create_DX8_Texture -( - IDirect3DSurface8 *surface, - MipCountType mip_level_count -) -{ - DX8_THREAD_ASSERT(); - DX8_Assert(); - IDirect3DTexture8 *texture = NULL; - - D3DSURFACE_DESC surface_desc; - ::ZeroMemory(&surface_desc, sizeof(D3DSURFACE_DESC)); - surface->GetDesc(&surface_desc); - - // This function will create a texture with a different (but similar) format if the surface is - // not in a supported texture format. - WW3DFormat format=D3DFormat_To_WW3DFormat(surface_desc.Format); - texture = _Create_DX8_Texture(surface_desc.Width, surface_desc.Height, format, mip_level_count); - - // Copy the surface to the texture - IDirect3DSurface8 *tex_surface = NULL; - texture->GetSurfaceLevel(0, &tex_surface); - DX8_ErrorCode(D3DXLoadSurfaceFromSurface(tex_surface, NULL, NULL, surface, NULL, NULL, D3DX_FILTER_BOX, 0)); - tex_surface->Release(); - - // Create mipmaps if needed - if (mip_level_count!=MIP_LEVELS_1) - { - DX8_ErrorCode(D3DXFilterTexture(texture, NULL, 0, D3DX_FILTER_BOX)); - } - - return 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(); - DX8_Assert(); - - IDirect3DSurface8 *surface = NULL; - - // Paletted surfaces not supported! - WWASSERT(format!=D3DFMT_P8); - - DX8CALL(CreateImageSurface(width, height, WW3DFormat_To_D3DFormat(format), &surface)); - - return surface; -} - -IDirect3DSurface8 * DX8Wrapper::_Create_DX8_Surface(const char *filename_) -{ - DX8_THREAD_ASSERT(); - DX8_Assert(); - - // Note: Since there is no "D3DXCreateSurfaceFromFile" and no "GetSurfaceInfoFromFile" (the - // latter is supposed to be added to D3DX in a future version), we create a texture from the - // file (w/o mipmaps), check that its surface is equal to the original file data (which it - // will not be if the file is not in a texture-supported format or size). If so, copy its - // surface (we might be able to just get its surface and add a ref to it but I'm not sure so - // I'm not going to risk it) and release the texture. If not, create a surface according to - // the file data and use D3DXLoadSurfaceFromFile. This is a horrible hack, but it saves us - // having to write file loaders. Will fix this when D3DX provides us with the right functions. - // Create a surface the size of the file image data - IDirect3DSurface8 *surface = NULL; - - { - - file_auto_ptr myfile(_TheFileFactory,filename_); - // If file not found, create a surface with missing texture in it - - if (!myfile->Is_Available()) { - // If file not found, try the dds format - // else create a surface with missing texture in it - char compressed_name[200]; - strncpy(compressed_name,filename_, ARRAY_SIZE(compressed_name)); - compressed_name[ARRAY_SIZE(compressed_name)-1] = '\0'; - char *ext = strstr(compressed_name, "."); - if ( ext && (strlen(ext)==4) && - ( (ext[1] == 't') || (ext[1] == 'T') ) && - ( (ext[2] == 'g') || (ext[2] == 'G') ) && - ( (ext[3] == 'a') || (ext[3] == 'A') ) ) { - ext[1]='d'; - ext[2]='d'; - ext[3]='s'; - } - file_auto_ptr myfile2(_TheFileFactory,compressed_name); - if (!myfile2->Is_Available()) - return MissingTexture::_Create_Missing_Surface(); - } - } - - StringClass filename_string(filename_,true); - surface=TextureLoader::Load_Surface_Immediate( - filename_string, - WW3D_FORMAT_UNKNOWN, - true); - return surface; -} - - -/*********************************************************************************************** - * DX8Wrapper::_Update_Texture -- Copies a texture from system memory to video memory * - * * - * * - * * - * * - * INPUT: * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 4/26/2001 hy : Created. * - *=============================================================================================*/ -void DX8Wrapper::_Update_Texture(TextureClass *system, TextureClass *video) -{ - WWASSERT(system); - WWASSERT(video); - WWASSERT(system->Get_Pool()==TextureClass::POOL_SYSTEMMEM); - WWASSERT(video->Get_Pool()==TextureClass::POOL_DEFAULT); - DX8CALL(UpdateTexture(system->Peek_D3D_Base_Texture(),video->Peek_D3D_Base_Texture())); -} - -void DX8Wrapper::Compute_Caps(WW3DFormat display_format) -{ - DX8_THREAD_ASSERT(); - DX8_Assert(); - delete CurrentCaps; - CurrentCaps=new DX8Caps(_Get_D3D8(),D3DDevice,display_format,Get_Current_Adapter_Identifier()); -} - - -void DX8Wrapper::Set_Light(unsigned index, const D3DLIGHT8* light) -{ - if (light) { - render_state.Lights[index]=*light; - render_state.LightEnable[index]=true; - } - else { - render_state.LightEnable[index]=false; - } - render_state_changed|=(LIGHT0_CHANGED< Date: Fri, 1 Aug 2025 17:29:14 +0800 Subject: [PATCH 12/20] Unify Set_Light_Environment --- .../Common/Graphics/DX8/dx8wrapper_common.h | 85 +++++++++++++++++++ .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 66 -------------- .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 83 ------------------ 3 files changed, 85 insertions(+), 149 deletions(-) diff --git a/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h b/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h index fa6289e3a8f..c126ef99e48 100644 --- a/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h +++ b/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h @@ -2830,3 +2830,88 @@ void DX8Wrapper::Set_Light(unsigned index, const LightClass& light) Set_Light(index, &dlight); } +//********************************************************************************************** +//! Set the light environment. This is a lighting model which used up to four +//! directional lights to produce the lighting. +/*! 5/27/02 KJM Added shader light environment support +*/ +void DX8Wrapper::Set_Light_Environment(LightEnvironmentClass* light_env) +{ + // Shader light environment support * +// if (Light_Environment && light_env && (*Light_Environment)==(*light_env)) return; + + Light_Environment = light_env; + + if (light_env) + { + int light_count = light_env->Get_Light_Count(); + unsigned int color = Convert_Color(light_env->Get_Equivalent_Ambient(), 0.0f); + if (RenderStates[D3DRS_AMBIENT] != color) + { + Set_DX8_Render_State(D3DRS_AMBIENT, color); + //buggy Radeon 9700 driver doesn't apply new ambient unless the material also changes. +#if 1 + render_state_changed |= MATERIAL_CHANGED; +#endif + } + + D3DLIGHT8 light; + int l = 0; + for (; l < light_count; ++l) { + + ::ZeroMemory(&light, sizeof(D3DLIGHT8)); + + light.Type = D3DLIGHT_DIRECTIONAL; + (Vector3&)light.Diffuse = light_env->Get_Light_Diffuse(l); + Vector3 dir = -light_env->Get_Light_Direction(l); + light.Direction = (const D3DVECTOR&)(dir); + + // (gth) TODO: put specular into LightEnvironment? Much work to be done on lights :-)' + if (l == 0) { + light.Specular.r = light.Specular.g = light.Specular.b = 1.0f; + } + + if (light_env->isPointLight(l)) { + light.Type = D3DLIGHT_POINT; + (Vector3&)light.Diffuse = light_env->getPointDiffuse(l); + (Vector3&)light.Ambient = light_env->getPointAmbient(l); + light.Position = (const D3DVECTOR&)light_env->getPointCenter(l); + light.Range = light_env->getPointOrad(l); + + // Inverse linear light 1/(1+D) + double a, b; + b = light_env->getPointOrad(l); + a = light_env->getPointIrad(l); + + //(gth) CNC3 Generals code for the attenuation factors is causing the lights to over-brighten + //I'm changing the Attenuation0 parameter to 1.0 to avoid this problem. +#if 0 + light.Attenuation0 = 0.01f; +#else + light.Attenuation0 = 1.0f; +#endif + if (fabs(a - b) < 1e-5) + // if the attenuation range is too small assume uniform with cutoff + light.Attenuation1 = 0.0f; + else + // this will cause the light to drop to half intensity at the first far attenuation + light.Attenuation1 = (float)0.1 / a; + + light.Attenuation2 = 8.0f / (b * b); + } + + Set_Light(l, &light); + } + + for (; l < 4; ++l) { + Set_Light(l, NULL); + } + } + /* else { + for (int l=0;l<4;++l) { + Set_Light(l,NULL); + } + } + */ +} + diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 716ddbd762c..59f111d8157 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -265,72 +265,6 @@ void MoveRectIntoOtherRect(const RECT& inner, const RECT& outer, int* x, int* y) #include "../../Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h" -// ---------------------------------------------------------------------------- -// -// Set the light environment. This is a lighting model which used up to four -// directional lights to produce the lighting. -// -void DX8Wrapper::Set_Light_Environment(LightEnvironmentClass* light_env) -{ - if (light_env) - { - int light_count = light_env->Get_Light_Count(); - unsigned int color=Convert_Color(light_env->Get_Equivalent_Ambient(),0.0f); - if (RenderStates[D3DRS_AMBIENT]!=color) - { - Set_DX8_Render_State(D3DRS_AMBIENT,color); -//buggy Radeon 9700 driver doesn't apply new ambient unless the material also changes. -#if 1 - render_state_changed|=MATERIAL_CHANGED; -#endif - } - - D3DLIGHT8 light; - int l=0; - for (;lGet_Light_Diffuse(l); - Vector3 dir=-light_env->Get_Light_Direction(l); - light.Direction=(const D3DVECTOR&)(dir); - if (light_env->isPointLight(l)) { - light.Type = D3DLIGHT_POINT; - (Vector3&)light.Diffuse=light_env->getPointDiffuse(l); - (Vector3&)light.Ambient=light_env->getPointAmbient(l); - light.Position = (const D3DVECTOR&)light_env->getPointCenter(l); - light.Range = light_env->getPointOrad(l); - - // Inverse linear light 1/(1+D) - double a,b; - b = light_env->getPointOrad(l); - a = light_env->getPointIrad(l); - light.Attenuation0=0.01f; - if (fabs(a-b)<1e-5) - // if the attenuation range is too small assume uniform with cutoff - light.Attenuation1=0.0f; - else - // this will cause the light to drop to half intensity at the first far attenuation - light.Attenuation1=(float) 0.1/a; - - light.Attenuation2=8.0f/(b*b); - } - - Set_Light(l,&light); - } - - for (;l<4;++l) { - Set_Light(l,NULL); - } - } -/* else { - for (int l=0;l<4;++l) { - Set_Light(l,NULL); - } - } -*/ -} IDirect3DSurface8 * DX8Wrapper::_Get_DX8_Front_Buffer() { diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index aafb7b2bc41..a15c192ed2d 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -273,90 +273,7 @@ void MoveRectIntoOtherRect(const RECT& inner, const RECT& outer, int* x, int* y) -//********************************************************************************************** -//! Set the light environment. This is a lighting model which used up to four -//! directional lights to produce the lighting. -/*! 5/27/02 KJM Added shader light environment support -*/ -void DX8Wrapper::Set_Light_Environment(LightEnvironmentClass* light_env) -{ - // Shader light environment support * -// if (Light_Environment && light_env && (*Light_Environment)==(*light_env)) return; - - Light_Environment=light_env; - - if (light_env) - { - int light_count = light_env->Get_Light_Count(); - unsigned int color=Convert_Color(light_env->Get_Equivalent_Ambient(),0.0f); - if (RenderStates[D3DRS_AMBIENT]!=color) - { - Set_DX8_Render_State(D3DRS_AMBIENT,color); -//buggy Radeon 9700 driver doesn't apply new ambient unless the material also changes. -#if 1 - render_state_changed|=MATERIAL_CHANGED; -#endif - } - D3DLIGHT8 light; - int l=0; - for (;lGet_Light_Diffuse(l); - Vector3 dir=-light_env->Get_Light_Direction(l); - light.Direction=(const D3DVECTOR&)(dir); - - // (gth) TODO: put specular into LightEnvironment? Much work to be done on lights :-)' - if (l==0) { - light.Specular.r = light.Specular.g = light.Specular.b = 1.0f; - } - - if (light_env->isPointLight(l)) { - light.Type = D3DLIGHT_POINT; - (Vector3&)light.Diffuse=light_env->getPointDiffuse(l); - (Vector3&)light.Ambient=light_env->getPointAmbient(l); - light.Position = (const D3DVECTOR&)light_env->getPointCenter(l); - light.Range = light_env->getPointOrad(l); - - // Inverse linear light 1/(1+D) - double a,b; - b = light_env->getPointOrad(l); - a = light_env->getPointIrad(l); - -//(gth) CNC3 Generals code for the attenuation factors is causing the lights to over-brighten -//I'm changing the Attenuation0 parameter to 1.0 to avoid this problem. -#if 0 - light.Attenuation0=0.01f; -#else - light.Attenuation0=1.0f; -#endif - if (fabs(a-b)<1e-5) - // if the attenuation range is too small assume uniform with cutoff - light.Attenuation1=0.0f; - else - // this will cause the light to drop to half intensity at the first far attenuation - light.Attenuation1=(float) 0.1/a; - - light.Attenuation2=8.0f/(b*b); - } - - Set_Light(l,&light); - } - - for (;l<4;++l) { - Set_Light(l,NULL); - } - } -/* else { - for (int l=0;l<4;++l) { - Set_Light(l,NULL); - } - } -*/ -} IDirect3DSurface8 * DX8Wrapper::_Get_DX8_Front_Buffer() { From dfc45abaee5d6a1193e1225b3d190688f446fee2 Mon Sep 17 00:00:00 2001 From: ryan-de-boer Date: Fri, 1 Aug 2025 17:36:05 +0800 Subject: [PATCH 13/20] Unify Create_Render_Target --- .../Common/Graphics/DX8/dx8wrapper_common.h | 87 +++++++++++++ .../GameClient/Shadow/W3DProjectedShadow.cpp | 12 +- .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 115 ------------------ .../Source/WWVegas/WW3D2/dx8wrapper.h | 4 +- .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 91 -------------- 5 files changed, 95 insertions(+), 214 deletions(-) diff --git a/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h b/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h index c126ef99e48..2673fde7270 100644 --- a/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h +++ b/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h @@ -2915,3 +2915,90 @@ void DX8Wrapper::Set_Light_Environment(LightEnvironmentClass* light_env) */ } + +IDirect3DSurface8* DX8Wrapper::_Get_DX8_Front_Buffer() +{ + DX8_THREAD_ASSERT(); + D3DDISPLAYMODE mode; + + DX8CALL(GetDisplayMode(&mode)); + + IDirect3DSurface8* fb = NULL; + + DX8CALL(CreateImageSurface(mode.Width, mode.Height, D3DFMT_A8R8G8B8, &fb)); + + DX8CALL(GetFrontBuffer(fb)); + return fb; +} + +SurfaceClass* DX8Wrapper::_Get_DX8_Back_Buffer(unsigned int num) +{ + DX8_THREAD_ASSERT(); + + IDirect3DSurface8* bb; + SurfaceClass* surf = NULL; + DX8CALL(GetBackBuffer(num, D3DBACKBUFFER_TYPE_MONO, &bb)); + if (bb) + { + surf = NEW_REF(SurfaceClass, (bb)); + bb->Release(); + } + + return surf; +} + +TextureClass* +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 + // + const D3DCAPS8& dx8caps = Get_Current_Caps()->Get_DX8_Caps(); + float poweroftwosize = width; + if (height > 0 && height < width) { + poweroftwosize = height; + } + poweroftwosize = ::Find_POT(poweroftwosize); + + if (poweroftwosize > dx8caps.MaxTextureWidth) { + poweroftwosize = dx8caps.MaxTextureWidth; + } + if (poweroftwosize > dx8caps.MaxTextureHeight) { + poweroftwosize = dx8caps.MaxTextureHeight; + } + + width = height = poweroftwosize; + + // + // Attempt to create the render target + // + 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; +} + diff --git a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Shadow/W3DProjectedShadow.cpp b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Shadow/W3DProjectedShadow.cpp index 8f9701e3cca..c8ac8e0b4b2 100644 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Shadow/W3DProjectedShadow.cpp +++ b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Shadow/W3DProjectedShadow.cpp @@ -263,14 +263,14 @@ 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) + m_renderTargetHasAlpha = TRUE; + if ((m_dynamicRenderTarget = DX8Wrapper::Create_Render_Target(DEFAULT_RENDER_TARGET_WIDTH, DEFAULT_RENDER_TARGET_HEIGHT, WW3D_FORMAT_A8R8G8B8)) == NULL) { - m_renderTargetHasAlpha=FALSE; + m_renderTargetHasAlpha = FALSE; - //failed to get a render target with alpha. - //try again without. - m_dynamicRenderTarget=DX8Wrapper::Create_Render_Target (DEFAULT_RENDER_TARGET_WIDTH, DEFAULT_RENDER_TARGET_HEIGHT); + //failed to get a render target with alpha. + //try again without. + m_dynamicRenderTarget = DX8Wrapper::Create_Render_Target(DEFAULT_RENDER_TARGET_WIDTH, DEFAULT_RENDER_TARGET_HEIGHT); } LPDIRECT3DDEVICE8 m_pDev=DX8Wrapper::_Get_D3D_Device8(); diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 59f111d8157..68b8b535ba7 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -265,121 +265,6 @@ void MoveRectIntoOtherRect(const RECT& inner, const RECT& outer, int* x, int* y) #include "../../Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h" - -IDirect3DSurface8 * DX8Wrapper::_Get_DX8_Front_Buffer() -{ - DX8_THREAD_ASSERT(); - D3DDISPLAYMODE mode; - - DX8CALL(GetDisplayMode(&mode)); - - IDirect3DSurface8 * fb=NULL; - - DX8CALL(CreateImageSurface(mode.Width,mode.Height,D3DFMT_A8R8G8B8,&fb)); - - DX8CALL(GetFrontBuffer(fb)); - return fb; -} - -SurfaceClass * DX8Wrapper::_Get_DX8_Back_Buffer(unsigned int num) -{ - DX8_THREAD_ASSERT(); - - IDirect3DSurface8 * bb; - SurfaceClass *surf=NULL; - DX8CALL(GetBackBuffer(num,D3DBACKBUFFER_TYPE_MONO,&bb)); - if (bb) - { - surf=NEW_REF(SurfaceClass,(bb)); - bb->Release(); - } - - return surf; -} - - -TextureClass * -DX8Wrapper::Create_Render_Target (int width, int height, bool alpha) -{ - DX8_THREAD_ASSERT(); - DX8_Assert(); - - // - // 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) { - poweroftwosize = height; - } - poweroftwosize = ::Find_POT (poweroftwosize); - - if (poweroftwosize>dx8caps.MaxTextureWidth) { - poweroftwosize=dx8caps.MaxTextureWidth; - } - if (poweroftwosize>dx8caps.MaxTextureHeight) { - poweroftwosize=dx8caps.MaxTextureHeight; - } - - width = height = poweroftwosize; - - // - // Get the current format of the display - // - D3DDISPLAYMODE mode; - DX8CALL(GetDisplayMode(&mode)); - - // If the user requested a render-target texture and this device does not support that - // feature, return NULL - HRESULT hr; - - if (alpha) - { - //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; - } - else - { - hr = D3DInterface->CheckDeviceFormat( D3DADAPTER_DEFAULT, - WW3D_DEVTYPE, - mode.Format, - D3DUSAGE_RENDERTARGET, - D3DRTYPE_TEXTURE, - mode.Format ); - } - - number_of_DX8_calls++; - if (hr != D3D_OK) { - WWDEBUG_SAY(("DX8Wrapper - Driver cannot create render target!")); - return NULL; - } - - // - // 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)); - - // 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; -} - - //void //DX8Wrapper::Set_Render_Target //(TextureClass * texture) diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h index e39aff48165..e3eb074348d 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h @@ -473,9 +473,9 @@ 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_With_Z(TextureClass* texture, ZTextureClass* ztexture = NULL); diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index a15c192ed2d..398ef7a1410 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -271,97 +271,6 @@ void MoveRectIntoOtherRect(const RECT& inner, const RECT& outer, int* x, int* y) #include "../../Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h" - - - - -IDirect3DSurface8 * DX8Wrapper::_Get_DX8_Front_Buffer() -{ - DX8_THREAD_ASSERT(); - D3DDISPLAYMODE mode; - - DX8CALL(GetDisplayMode(&mode)); - - IDirect3DSurface8 * fb=NULL; - - DX8CALL(CreateImageSurface(mode.Width,mode.Height,D3DFMT_A8R8G8B8,&fb)); - - DX8CALL(GetFrontBuffer(fb)); - return fb; -} - -SurfaceClass * DX8Wrapper::_Get_DX8_Back_Buffer(unsigned int num) -{ - DX8_THREAD_ASSERT(); - - IDirect3DSurface8 * bb; - SurfaceClass *surf=NULL; - DX8CALL(GetBackBuffer(num,D3DBACKBUFFER_TYPE_MONO,&bb)); - if (bb) - { - surf=NEW_REF(SurfaceClass,(bb)); - bb->Release(); - } - - return surf; -} - - -TextureClass * -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 - // - const D3DCAPS8& dx8caps=Get_Current_Caps()->Get_DX8_Caps(); - float poweroftwosize = width; - if (height > 0 && height < width) { - poweroftwosize = height; - } - poweroftwosize = ::Find_POT (poweroftwosize); - - if (poweroftwosize>dx8caps.MaxTextureWidth) { - poweroftwosize=dx8caps.MaxTextureWidth; - } - if (poweroftwosize>dx8caps.MaxTextureHeight) { - poweroftwosize=dx8caps.MaxTextureHeight; - } - - width = height = poweroftwosize; - - // - // Attempt to create the render target - // - 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 From 1a34baca526d299e93bcb68498d7ef568a2466dc Mon Sep 17 00:00:00 2001 From: ryan-de-boer Date: Fri, 1 Aug 2025 17:42:02 +0800 Subject: [PATCH 14/20] Unified to end of dx8wrapper --- .../Common/Graphics/DX8/dx8wrapper_common.h | 1222 +++++++++++++++++ .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 1145 --------------- .../Source/WWVegas/WW3D2/dx8wrapper.h | 11 + .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 1220 ---------------- 4 files changed, 1233 insertions(+), 2365 deletions(-) diff --git a/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h b/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h index 2673fde7270..6e384a9431d 100644 --- a/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h +++ b/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h @@ -3002,3 +3002,1225 @@ DX8Wrapper::Create_Render_Target(int width, int height, WW3DFormat format) 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++; + + // 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 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)) + { + WWDEBUG_SAY(("DX8Wrapper - Render target with depth format is not supported")); + return; + } + + // 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) + { + poweroftwosize = height; + } + poweroftwosize = ::Find_POT(poweroftwosize); + + if (poweroftwosize > dx8caps.MaxTextureWidth) + { + poweroftwosize = dx8caps.MaxTextureWidth; + } + + if (poweroftwosize > dx8caps.MaxTextureHeight) + { + poweroftwosize = dx8caps.MaxTextureHeight; + } + + width = height = poweroftwosize; + + // Attempt to create the render target + 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); + } + + *target = tex; + + // attempt to create the depth stencil buffer + *depth_buffer = NEW_REF + ( + ZTextureClass, + ( + width, + height, + zformat, + MIP_LEVELS_1, + TextureClass::POOL_DEFAULT + ) + ); +} + +/*! + * Set render target + * KM Added optional custom z target + */ +void DX8Wrapper::Set_Render_Target_With_Z +( + TextureClass* texture, + ZTextureClass* ztexture +) +{ + 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 +DX8Wrapper::Set_Render_Target(IDirect3DSwapChain8* swap_chain) +{ + DX8_THREAD_ASSERT(); + WWASSERT(swap_chain != NULL); + + // + // Get the back buffer for the swap chain + // + LPDIRECT3DSURFACE8 render_target = NULL; + swap_chain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &render_target); + + // + // Set this back buffer as the render targer + // + Set_Render_Target(render_target, true); + + // + // Release our hold on the back buffer + // + if (render_target != NULL) { + render_target->Release(); + render_target = NULL; + } + + IsRenderToTexture = false; + + return; +} + +void +DX8Wrapper::Set_Render_Target(IDirect3DSurface8* render_target, bool use_default_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; + WWASSERT(CurrentRenderTarget != NULL); + if (CurrentRenderTarget != NULL) + { + CurrentRenderTarget->AddRef(); + + // + // Switch render targets + // + 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; +// } + + 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 +} + + +IDirect3DSwapChain8* +DX8Wrapper::Create_Additional_Swap_Chain(HWND render_window) +{ + DX8_Assert(); + + // + // Configure the presentation parameters for a windowed render target + // + D3DPRESENT_PARAMETERS params = { 0 }; + params.BackBufferFormat = _PresentParameters.BackBufferFormat; + params.BackBufferCount = 1; + params.MultiSampleType = D3DMULTISAMPLE_NONE; + params.SwapEffect = D3DSWAPEFFECT_COPY_VSYNC; + params.hDeviceWindow = render_window; + params.Windowed = TRUE; + params.EnableAutoDepthStencil = TRUE; + params.AutoDepthStencilFormat = _PresentParameters.AutoDepthStencilFormat; + params.Flags = 0; + params.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT; + params.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; + + // + // Create the swap chain + // + IDirect3DSwapChain8* swap_chain = NULL; + DX8CALL(CreateAdditionalSwapChain(¶ms, &swap_chain)); + return swap_chain; +} + +void DX8Wrapper::Flush_DX8_Resource_Manager(unsigned int bytes) +{ + DX8_Assert(); + DX8CALL(ResourceManagerDiscardBytes(bytes)); +} + +unsigned int DX8Wrapper::Get_Free_Texture_RAM() +{ + DX8_Assert(); + number_of_DX8_calls++; + return DX8Wrapper::_Get_D3D_Device8()->GetAvailableTextureMem(); +} + +// Converts a linear gamma ramp to one that is controlled by: +// Gamma - controls the curvature of the middle of the curve +// Bright - controls the minimum value of the curve +// Contrast - controls the difference between the maximum and the minimum of the curve +void DX8Wrapper::Set_Gamma(float gamma, float bright, float contrast, bool calibrate, bool uselimit) +{ + gamma = Bound(gamma, 0.6f, 6.0f); + bright = Bound(bright, -0.5f, 0.5f); + contrast = Bound(contrast, 0.5f, 2.0f); + float oo_gamma = 1.0f / gamma; + + DX8_Assert(); + number_of_DX8_calls++; + + DWORD flag = (calibrate ? D3DSGR_CALIBRATE : D3DSGR_NO_CALIBRATION); + + D3DGAMMARAMP ramp; + float limit; + + // IML: I'm not really sure what the intent of the 'limit' variable is. It does not produce useful results for my purposes. + if (uselimit) { + limit = (contrast - 1) / 2 * contrast; + } + else { + limit = 0.0f; + } + + // HY - arrived at this equation after much trial and error. + for (int i = 0; i < 256; i++) { + float in, out; + in = i / 256.0f; + float x = in - limit; + x = Bound(x, 0.0f, 1.0f); + x = powf(x, oo_gamma); + out = contrast * x + bright; + out = Bound(out, 0.0f, 1.0f); + ramp.red[i] = (WORD)(out * 65535); + ramp.green[i] = (WORD)(out * 65535); + ramp.blue[i] = (WORD)(out * 65535); + } + + if (Get_Current_Caps()->Support_Gamma()) { + DX8Wrapper::_Get_D3D_Device8()->SetGammaRamp(flag, &ramp); + } + else { + HWND hwnd = GetDesktopWindow(); + HDC hdc = GetDC(hwnd); + if (hdc) + { + SetDeviceGammaRamp(hdc, &ramp); + ReleaseDC(hwnd, hdc); + } + } +} + +//********************************************************************************************** +//! Resets render device to default state +/*! +*/ +void DX8Wrapper::Apply_Default_State() +{ + SNAPSHOT_SAY(("DX8Wrapper::Apply_Default_State()")); + + // only set states used in game + Set_DX8_Render_State(D3DRS_ZENABLE, TRUE); + // Set_DX8_Render_State(D3DRS_FILLMODE, D3DFILL_SOLID); + Set_DX8_Render_State(D3DRS_SHADEMODE, D3DSHADE_GOURAUD); + //Set_DX8_Render_State(D3DRS_LINEPATTERN, 0); + Set_DX8_Render_State(D3DRS_ZWRITEENABLE, TRUE); + Set_DX8_Render_State(D3DRS_ALPHATESTENABLE, FALSE); + //Set_DX8_Render_State(D3DRS_LASTPIXEL, FALSE); + Set_DX8_Render_State(D3DRS_SRCBLEND, D3DBLEND_ONE); + Set_DX8_Render_State(D3DRS_DESTBLEND, D3DBLEND_ZERO); + Set_DX8_Render_State(D3DRS_CULLMODE, D3DCULL_CW); + Set_DX8_Render_State(D3DRS_ZFUNC, D3DCMP_LESSEQUAL); + Set_DX8_Render_State(D3DRS_ALPHAREF, 0); + Set_DX8_Render_State(D3DRS_ALPHAFUNC, D3DCMP_LESSEQUAL); + Set_DX8_Render_State(D3DRS_DITHERENABLE, FALSE); + Set_DX8_Render_State(D3DRS_ALPHABLENDENABLE, FALSE); + Set_DX8_Render_State(D3DRS_FOGENABLE, FALSE); + Set_DX8_Render_State(D3DRS_SPECULARENABLE, FALSE); + // Set_DX8_Render_State(D3DRS_ZVISIBLE, FALSE); + // Set_DX8_Render_State(D3DRS_FOGCOLOR, 0); + // Set_DX8_Render_State(D3DRS_FOGTABLEMODE, D3DFOG_NONE); + // Set_DX8_Render_State(D3DRS_FOGSTART, 0); + + // Set_DX8_Render_State(D3DRS_FOGEND, WWMath::Float_As_Int(1.0f)); + // Set_DX8_Render_State(D3DRS_FOGDENSITY, WWMath::Float_As_Int(1.0f)); + + //Set_DX8_Render_State(D3DRS_EDGEANTIALIAS, FALSE); + Set_DX8_Render_State(D3DRS_ZBIAS, 0); + // Set_DX8_Render_State(D3DRS_RANGEFOGENABLE, FALSE); + Set_DX8_Render_State(D3DRS_STENCILENABLE, FALSE); + Set_DX8_Render_State(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP); + Set_DX8_Render_State(D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP); + Set_DX8_Render_State(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP); + Set_DX8_Render_State(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); + Set_DX8_Render_State(D3DRS_STENCILREF, 0); + Set_DX8_Render_State(D3DRS_STENCILMASK, 0xffffffff); + Set_DX8_Render_State(D3DRS_STENCILWRITEMASK, 0xffffffff); + Set_DX8_Render_State(D3DRS_TEXTUREFACTOR, 0); + /* Set_DX8_Render_State(D3DRS_WRAP0, D3DWRAP_U| D3DWRAP_V); + Set_DX8_Render_State(D3DRS_WRAP1, D3DWRAP_U| D3DWRAP_V); + Set_DX8_Render_State(D3DRS_WRAP2, D3DWRAP_U| D3DWRAP_V); + Set_DX8_Render_State(D3DRS_WRAP3, D3DWRAP_U| D3DWRAP_V); + Set_DX8_Render_State(D3DRS_WRAP4, D3DWRAP_U| D3DWRAP_V); + Set_DX8_Render_State(D3DRS_WRAP5, D3DWRAP_U| D3DWRAP_V); + Set_DX8_Render_State(D3DRS_WRAP6, D3DWRAP_U| D3DWRAP_V); + Set_DX8_Render_State(D3DRS_WRAP7, D3DWRAP_U| D3DWRAP_V);*/ + Set_DX8_Render_State(D3DRS_CLIPPING, TRUE); + Set_DX8_Render_State(D3DRS_LIGHTING, FALSE); + //Set_DX8_Render_State(D3DRS_AMBIENT, 0); +// Set_DX8_Render_State(D3DRS_FOGVERTEXMODE, D3DFOG_NONE); + Set_DX8_Render_State(D3DRS_COLORVERTEX, TRUE); + /* Set_DX8_Render_State(D3DRS_LOCALVIEWER, TRUE); + Set_DX8_Render_State(D3DRS_NORMALIZENORMALS, FALSE); + Set_DX8_Render_State(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1); + Set_DX8_Render_State(D3DRS_SPECULARMATERIALSOURCE, D3DMCS_COLOR2); + Set_DX8_Render_State(D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_MATERIAL); + Set_DX8_Render_State(D3DRS_EMISSIVEMATERIALSOURCE, D3DMCS_MATERIAL); + Set_DX8_Render_State(D3DRS_VERTEXBLEND, D3DVBF_DISABLE);*/ + //Set_DX8_Render_State(D3DRS_CLIPPLANEENABLE, 0); + Set_DX8_Render_State(D3DRS_SOFTWAREVERTEXPROCESSING, FALSE); + //Set_DX8_Render_State(D3DRS_POINTSIZE, 0x3f800000); + //Set_DX8_Render_State(D3DRS_POINTSIZE_MIN, 0); + //Set_DX8_Render_State(D3DRS_POINTSPRITEENABLE, FALSE); + //Set_DX8_Render_State(D3DRS_POINTSCALEENABLE, FALSE); + //Set_DX8_Render_State(D3DRS_POINTSCALE_A, 0); + //Set_DX8_Render_State(D3DRS_POINTSCALE_B, 0); + //Set_DX8_Render_State(D3DRS_POINTSCALE_C, 0); + //Set_DX8_Render_State(D3DRS_MULTISAMPLEANTIALIAS, TRUE); + //Set_DX8_Render_State(D3DRS_MULTISAMPLEMASK, 0xffffffff); + //Set_DX8_Render_State(D3DRS_PATCHEDGESTYLE, D3DPATCHEDGE_DISCRETE); + //Set_DX8_Render_State(D3DRS_PATCHSEGMENTS, 0x3f800000); + //Set_DX8_Render_State(D3DRS_DEBUGMONITORTOKEN, D3DDMT_ENABLE); + //Set_DX8_Render_State(D3DRS_POINTSIZE_MAX, Float_At_Int(64.0f)); + //Set_DX8_Render_State(D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE); + Set_DX8_Render_State(D3DRS_COLORWRITEENABLE, 0x0000000f); + //Set_DX8_Render_State(D3DRS_TWEENFACTOR, 0); + Set_DX8_Render_State(D3DRS_BLENDOP, D3DBLENDOP_ADD); + //Set_DX8_Render_State(D3DRS_POSITIONORDER, D3DORDER_CUBIC); + //Set_DX8_Render_State(D3DRS_NORMALORDER, D3DORDER_LINEAR); + + // disable TSS stages + int i; + for (i = 0; i < CurrentCaps->Get_Max_Textures_Per_Pass(); i++) + { + Set_DX8_Texture_Stage_State(i, D3DTSS_COLOROP, D3DTOP_DISABLE); + Set_DX8_Texture_Stage_State(i, D3DTSS_COLORARG1, D3DTA_TEXTURE); + Set_DX8_Texture_Stage_State(i, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + + Set_DX8_Texture_Stage_State(i, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + Set_DX8_Texture_Stage_State(i, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + Set_DX8_Texture_Stage_State(i, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); + + /*Set_DX8_Texture_Stage_State(i, D3DTSS_BUMPENVMAT00, 0); + Set_DX8_Texture_Stage_State(i, D3DTSS_BUMPENVMAT01, 0); + Set_DX8_Texture_Stage_State(i, D3DTSS_BUMPENVMAT10, 0); + Set_DX8_Texture_Stage_State(i, D3DTSS_BUMPENVMAT11, 0); + Set_DX8_Texture_Stage_State(i, D3DTSS_BUMPENVLSCALE, 0); + Set_DX8_Texture_Stage_State(i, D3DTSS_BUMPENVLOFFSET, 0);*/ + + Set_DX8_Texture_Stage_State(i, D3DTSS_TEXCOORDINDEX, i); + + + Set_DX8_Texture_Stage_State(i, D3DTSS_ADDRESSU, D3DTADDRESS_WRAP); + Set_DX8_Texture_Stage_State(i, D3DTSS_ADDRESSV, D3DTADDRESS_WRAP); + Set_DX8_Texture_Stage_State(i, D3DTSS_BORDERCOLOR, 0); + // Set_DX8_Texture_Stage_State(i, D3DTSS_MAGFILTER, D3DTEXF_LINEAR); + // Set_DX8_Texture_Stage_State(i, D3DTSS_MINFILTER, D3DTEXF_LINEAR); + // Set_DX8_Texture_Stage_State(i, D3DTSS_MIPFILTER, D3DTEXF_LINEAR); + // Set_DX8_Texture_Stage_State(i, D3DTSS_MIPMAPLODBIAS, 0); + // Set_DX8_Texture_Stage_State(i, D3DTSS_MAXMIPLEVEL, 0); + // Set_DX8_Texture_Stage_State(i, D3DTSS_MAXANISOTROPY, 1); + //Set_DX8_Texture_Stage_State(i, D3DTSS_ADDRESSW, D3DTADDRESS_WRAP); + //Set_DX8_Texture_Stage_State(i, D3DTSS_COLORARG0, D3DTA_CURRENT); + //Set_DX8_Texture_Stage_State(i, D3DTSS_ALPHAARG0, D3DTA_CURRENT); + //Set_DX8_Texture_Stage_State(i, D3DTSS_RESULTARG, D3DTA_CURRENT); + + Set_DX8_Texture_Stage_State(i, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE); + Set_Texture(i, NULL); + } + + // DX8Wrapper::Set_Material(NULL); + VertexMaterialClass::Apply_Null(); + + for (unsigned index = 0; index < 4; ++index) { + SNAPSHOT_SAY(("Clearing light %d to NULL", index)); + Set_DX8_Light(index, NULL); + } + + // set up simple default TSS + Vector4 vconst[MAX_VERTEX_SHADER_CONSTANTS]; + memset(vconst, 0, sizeof(Vector4) * MAX_VERTEX_SHADER_CONSTANTS); + Set_Vertex_Shader_Constant(0, vconst, MAX_VERTEX_SHADER_CONSTANTS); + + Vector4 pconst[MAX_PIXEL_SHADER_CONSTANTS]; + memset(pconst, 0, sizeof(Vector4) * MAX_PIXEL_SHADER_CONSTANTS); + Set_Pixel_Shader_Constant(0, pconst, MAX_PIXEL_SHADER_CONSTANTS); + + Set_Vertex_Shader(DX8_FVF_XYZNDUV2); + Set_Pixel_Shader(0); + + ShaderClass::Invalidate(); +} + +const char* DX8Wrapper::Get_DX8_Render_State_Name(D3DRENDERSTATETYPE state) +{ + switch (state) { + case D3DRS_ZENABLE: return "D3DRS_ZENABLE"; + case D3DRS_FILLMODE: return "D3DRS_FILLMODE"; + case D3DRS_SHADEMODE: return "D3DRS_SHADEMODE"; + case D3DRS_LINEPATTERN: return "D3DRS_LINEPATTERN"; + case D3DRS_ZWRITEENABLE: return "D3DRS_ZWRITEENABLE"; + case D3DRS_ALPHATESTENABLE: return "D3DRS_ALPHATESTENABLE"; + case D3DRS_LASTPIXEL: return "D3DRS_LASTPIXEL"; + case D3DRS_SRCBLEND: return "D3DRS_SRCBLEND"; + case D3DRS_DESTBLEND: return "D3DRS_DESTBLEND"; + case D3DRS_CULLMODE: return "D3DRS_CULLMODE"; + case D3DRS_ZFUNC: return "D3DRS_ZFUNC"; + case D3DRS_ALPHAREF: return "D3DRS_ALPHAREF"; + case D3DRS_ALPHAFUNC: return "D3DRS_ALPHAFUNC"; + case D3DRS_DITHERENABLE: return "D3DRS_DITHERENABLE"; + case D3DRS_ALPHABLENDENABLE: return "D3DRS_ALPHABLENDENABLE"; + case D3DRS_FOGENABLE: return "D3DRS_FOGENABLE"; + case D3DRS_SPECULARENABLE: return "D3DRS_SPECULARENABLE"; + case D3DRS_ZVISIBLE: return "D3DRS_ZVISIBLE"; + case D3DRS_FOGCOLOR: return "D3DRS_FOGCOLOR"; + case D3DRS_FOGTABLEMODE: return "D3DRS_FOGTABLEMODE"; + case D3DRS_FOGSTART: return "D3DRS_FOGSTART"; + case D3DRS_FOGEND: return "D3DRS_FOGEND"; + case D3DRS_FOGDENSITY: return "D3DRS_FOGDENSITY"; + case D3DRS_EDGEANTIALIAS: return "D3DRS_EDGEANTIALIAS"; + case D3DRS_ZBIAS: return "D3DRS_ZBIAS"; + case D3DRS_RANGEFOGENABLE: return "D3DRS_RANGEFOGENABLE"; + case D3DRS_STENCILENABLE: return "D3DRS_STENCILENABLE"; + case D3DRS_STENCILFAIL: return "D3DRS_STENCILFAIL"; + case D3DRS_STENCILZFAIL: return "D3DRS_STENCILZFAIL"; + case D3DRS_STENCILPASS: return "D3DRS_STENCILPASS"; + case D3DRS_STENCILFUNC: return "D3DRS_STENCILFUNC"; + case D3DRS_STENCILREF: return "D3DRS_STENCILREF"; + case D3DRS_STENCILMASK: return "D3DRS_STENCILMASK"; + case D3DRS_STENCILWRITEMASK: return "D3DRS_STENCILWRITEMASK"; + case D3DRS_TEXTUREFACTOR: return "D3DRS_TEXTUREFACTOR"; + case D3DRS_WRAP0: return "D3DRS_WRAP0"; + case D3DRS_WRAP1: return "D3DRS_WRAP1"; + case D3DRS_WRAP2: return "D3DRS_WRAP2"; + case D3DRS_WRAP3: return "D3DRS_WRAP3"; + case D3DRS_WRAP4: return "D3DRS_WRAP4"; + case D3DRS_WRAP5: return "D3DRS_WRAP5"; + case D3DRS_WRAP6: return "D3DRS_WRAP6"; + case D3DRS_WRAP7: return "D3DRS_WRAP7"; + case D3DRS_CLIPPING: return "D3DRS_CLIPPING"; + case D3DRS_LIGHTING: return "D3DRS_LIGHTING"; + case D3DRS_AMBIENT: return "D3DRS_AMBIENT"; + case D3DRS_FOGVERTEXMODE: return "D3DRS_FOGVERTEXMODE"; + case D3DRS_COLORVERTEX: return "D3DRS_COLORVERTEX"; + case D3DRS_LOCALVIEWER: return "D3DRS_LOCALVIEWER"; + case D3DRS_NORMALIZENORMALS: return "D3DRS_NORMALIZENORMALS"; + case D3DRS_DIFFUSEMATERIALSOURCE: return "D3DRS_DIFFUSEMATERIALSOURCE"; + case D3DRS_SPECULARMATERIALSOURCE: return "D3DRS_SPECULARMATERIALSOURCE"; + case D3DRS_AMBIENTMATERIALSOURCE: return "D3DRS_AMBIENTMATERIALSOURCE"; + case D3DRS_EMISSIVEMATERIALSOURCE: return "D3DRS_EMISSIVEMATERIALSOURCE"; + case D3DRS_VERTEXBLEND: return "D3DRS_VERTEXBLEND"; + case D3DRS_CLIPPLANEENABLE: return "D3DRS_CLIPPLANEENABLE"; + case D3DRS_SOFTWAREVERTEXPROCESSING: return "D3DRS_SOFTWAREVERTEXPROCESSING"; + case D3DRS_POINTSIZE: return "D3DRS_POINTSIZE"; + case D3DRS_POINTSIZE_MIN: return "D3DRS_POINTSIZE_MIN"; + case D3DRS_POINTSPRITEENABLE: return "D3DRS_POINTSPRITEENABLE"; + case D3DRS_POINTSCALEENABLE: return "D3DRS_POINTSCALEENABLE"; + case D3DRS_POINTSCALE_A: return "D3DRS_POINTSCALE_A"; + case D3DRS_POINTSCALE_B: return "D3DRS_POINTSCALE_B"; + case D3DRS_POINTSCALE_C: return "D3DRS_POINTSCALE_C"; + case D3DRS_MULTISAMPLEANTIALIAS: return "D3DRS_MULTISAMPLEANTIALIAS"; + case D3DRS_MULTISAMPLEMASK: return "D3DRS_MULTISAMPLEMASK"; + case D3DRS_PATCHEDGESTYLE: return "D3DRS_PATCHEDGESTYLE"; + case D3DRS_PATCHSEGMENTS: return "D3DRS_PATCHSEGMENTS"; + case D3DRS_DEBUGMONITORTOKEN: return "D3DRS_DEBUGMONITORTOKEN"; + case D3DRS_POINTSIZE_MAX: return "D3DRS_POINTSIZE_MAX"; + case D3DRS_INDEXEDVERTEXBLENDENABLE: return "D3DRS_INDEXEDVERTEXBLENDENABLE"; + case D3DRS_COLORWRITEENABLE: return "D3DRS_COLORWRITEENABLE"; + case D3DRS_TWEENFACTOR: return "D3DRS_TWEENFACTOR"; + case D3DRS_BLENDOP: return "D3DRS_BLENDOP"; + // case D3DRS_POSITIONORDER : return "D3DRS_POSITIONORDER"; + // case D3DRS_NORMALORDER : return "D3DRS_NORMALORDER"; + default: return "UNKNOWN"; + } +} + +const char* DX8Wrapper::Get_DX8_Texture_Stage_State_Name(D3DTEXTURESTAGESTATETYPE state) +{ + switch (state) { + case D3DTSS_COLOROP: return "D3DTSS_COLOROP"; + case D3DTSS_COLORARG1: return "D3DTSS_COLORARG1"; + case D3DTSS_COLORARG2: return "D3DTSS_COLORARG2"; + case D3DTSS_ALPHAOP: return "D3DTSS_ALPHAOP"; + case D3DTSS_ALPHAARG1: return "D3DTSS_ALPHAARG1"; + case D3DTSS_ALPHAARG2: return "D3DTSS_ALPHAARG2"; + case D3DTSS_BUMPENVMAT00: return "D3DTSS_BUMPENVMAT00"; + case D3DTSS_BUMPENVMAT01: return "D3DTSS_BUMPENVMAT01"; + case D3DTSS_BUMPENVMAT10: return "D3DTSS_BUMPENVMAT10"; + case D3DTSS_BUMPENVMAT11: return "D3DTSS_BUMPENVMAT11"; + case D3DTSS_TEXCOORDINDEX: return "D3DTSS_TEXCOORDINDEX"; + case D3DTSS_ADDRESSU: return "D3DTSS_ADDRESSU"; + case D3DTSS_ADDRESSV: return "D3DTSS_ADDRESSV"; + case D3DTSS_BORDERCOLOR: return "D3DTSS_BORDERCOLOR"; + case D3DTSS_MAGFILTER: return "D3DTSS_MAGFILTER"; + case D3DTSS_MINFILTER: return "D3DTSS_MINFILTER"; + case D3DTSS_MIPFILTER: return "D3DTSS_MIPFILTER"; + case D3DTSS_MIPMAPLODBIAS: return "D3DTSS_MIPMAPLODBIAS"; + case D3DTSS_MAXMIPLEVEL: return "D3DTSS_MAXMIPLEVEL"; + case D3DTSS_MAXANISOTROPY: return "D3DTSS_MAXANISOTROPY"; + case D3DTSS_BUMPENVLSCALE: return "D3DTSS_BUMPENVLSCALE"; + case D3DTSS_BUMPENVLOFFSET: return "D3DTSS_BUMPENVLOFFSET"; + case D3DTSS_TEXTURETRANSFORMFLAGS: return "D3DTSS_TEXTURETRANSFORMFLAGS"; + case D3DTSS_ADDRESSW: return "D3DTSS_ADDRESSW"; + case D3DTSS_COLORARG0: return "D3DTSS_COLORARG0"; + case D3DTSS_ALPHAARG0: return "D3DTSS_ALPHAARG0"; + case D3DTSS_RESULTARG: return "D3DTSS_RESULTARG"; + default: return "UNKNOWN"; + } +} + +void DX8Wrapper::Get_DX8_Render_State_Value_Name(StringClass& name, D3DRENDERSTATETYPE state, unsigned value) +{ + switch (state) { + case D3DRS_ZENABLE: + name = Get_DX8_ZBuffer_Type_Name(value); + break; + + case D3DRS_FILLMODE: + name = Get_DX8_Fill_Mode_Name(value); + break; + + case D3DRS_SHADEMODE: + name = Get_DX8_Shade_Mode_Name(value); + break; + + case D3DRS_LINEPATTERN: + case D3DRS_FOGCOLOR: + case D3DRS_ALPHAREF: + case D3DRS_STENCILMASK: + case D3DRS_STENCILWRITEMASK: + case D3DRS_TEXTUREFACTOR: + case D3DRS_AMBIENT: + case D3DRS_CLIPPLANEENABLE: + case D3DRS_MULTISAMPLEMASK: + name.Format("0x%x", value); + break; + + case D3DRS_ZWRITEENABLE: + case D3DRS_ALPHATESTENABLE: + case D3DRS_LASTPIXEL: + case D3DRS_DITHERENABLE: + case D3DRS_ALPHABLENDENABLE: + case D3DRS_FOGENABLE: + case D3DRS_SPECULARENABLE: + case D3DRS_STENCILENABLE: + case D3DRS_RANGEFOGENABLE: + case D3DRS_EDGEANTIALIAS: + case D3DRS_CLIPPING: + case D3DRS_LIGHTING: + case D3DRS_COLORVERTEX: + case D3DRS_LOCALVIEWER: + case D3DRS_NORMALIZENORMALS: + case D3DRS_SOFTWAREVERTEXPROCESSING: + case D3DRS_POINTSPRITEENABLE: + case D3DRS_POINTSCALEENABLE: + case D3DRS_MULTISAMPLEANTIALIAS: + case D3DRS_INDEXEDVERTEXBLENDENABLE: + name = value ? "TRUE" : "FALSE"; + break; + + case D3DRS_SRCBLEND: + case D3DRS_DESTBLEND: + name = Get_DX8_Blend_Name(value); + break; + + case D3DRS_CULLMODE: + name = Get_DX8_Cull_Mode_Name(value); + break; + + case D3DRS_ZFUNC: + case D3DRS_ALPHAFUNC: + case D3DRS_STENCILFUNC: + name = Get_DX8_Cmp_Func_Name(value); + break; + + case D3DRS_ZVISIBLE: + name = "NOTSUPPORTED"; + break; + + case D3DRS_FOGTABLEMODE: + case D3DRS_FOGVERTEXMODE: + name = Get_DX8_Fog_Mode_Name(value); + break; + + case D3DRS_FOGSTART: + case D3DRS_FOGEND: + case D3DRS_FOGDENSITY: + case D3DRS_POINTSIZE: + case D3DRS_POINTSIZE_MIN: + case D3DRS_POINTSCALE_A: + case D3DRS_POINTSCALE_B: + case D3DRS_POINTSCALE_C: + case D3DRS_PATCHSEGMENTS: + case D3DRS_POINTSIZE_MAX: + case D3DRS_TWEENFACTOR: + name.Format("%f", *(float*)&value); + break; + + case D3DRS_ZBIAS: + case D3DRS_STENCILREF: + name.Format("%d", value); + break; + + case D3DRS_STENCILFAIL: + case D3DRS_STENCILZFAIL: + case D3DRS_STENCILPASS: + name = Get_DX8_Stencil_Op_Name(value); + break; + + case D3DRS_WRAP0: + case D3DRS_WRAP1: + case D3DRS_WRAP2: + case D3DRS_WRAP3: + case D3DRS_WRAP4: + case D3DRS_WRAP5: + case D3DRS_WRAP6: + case D3DRS_WRAP7: + name = "0"; + if (value & D3DWRAP_U) name += "|D3DWRAP_U"; + if (value & D3DWRAP_V) name += "|D3DWRAP_V"; + if (value & D3DWRAP_W) name += "|D3DWRAP_W"; + break; + + case D3DRS_DIFFUSEMATERIALSOURCE: + case D3DRS_SPECULARMATERIALSOURCE: + case D3DRS_AMBIENTMATERIALSOURCE: + case D3DRS_EMISSIVEMATERIALSOURCE: + name = Get_DX8_Material_Source_Name(value); + break; + + case D3DRS_VERTEXBLEND: + name = Get_DX8_Vertex_Blend_Flag_Name(value); + break; + + case D3DRS_PATCHEDGESTYLE: + name = Get_DX8_Patch_Edge_Style_Name(value); + break; + + case D3DRS_DEBUGMONITORTOKEN: + name = Get_DX8_Debug_Monitor_Token_Name(value); + break; + + case D3DRS_COLORWRITEENABLE: + name = "0"; + if (value & D3DCOLORWRITEENABLE_RED) name += "|D3DCOLORWRITEENABLE_RED"; + if (value & D3DCOLORWRITEENABLE_GREEN) name += "|D3DCOLORWRITEENABLE_GREEN"; + if (value & D3DCOLORWRITEENABLE_BLUE) name += "|D3DCOLORWRITEENABLE_BLUE"; + if (value & D3DCOLORWRITEENABLE_ALPHA) name += "|D3DCOLORWRITEENABLE_ALPHA"; + break; + case D3DRS_BLENDOP: + name = Get_DX8_Blend_Op_Name(value); + break; + default: + name.Format("UNKNOWN (%d)", value); + break; + } +} + +void DX8Wrapper::Get_DX8_Texture_Stage_State_Value_Name(StringClass& name, D3DTEXTURESTAGESTATETYPE state, unsigned value) +{ + switch (state) { + case D3DTSS_COLOROP: + case D3DTSS_ALPHAOP: + name = Get_DX8_Texture_Op_Name(value); + break; + + case D3DTSS_COLORARG0: + case D3DTSS_COLORARG1: + case D3DTSS_COLORARG2: + case D3DTSS_ALPHAARG0: + case D3DTSS_ALPHAARG1: + case D3DTSS_ALPHAARG2: + case D3DTSS_RESULTARG: + name = Get_DX8_Texture_Arg_Name(value); + break; + + case D3DTSS_ADDRESSU: + case D3DTSS_ADDRESSV: + case D3DTSS_ADDRESSW: + name = Get_DX8_Texture_Address_Name(value); + break; + + case D3DTSS_MAGFILTER: + case D3DTSS_MINFILTER: + case D3DTSS_MIPFILTER: + name = Get_DX8_Texture_Filter_Name(value); + break; + + case D3DTSS_TEXTURETRANSFORMFLAGS: + name = Get_DX8_Texture_Transform_Flag_Name(value); + break; + + // Floating point values + case D3DTSS_MIPMAPLODBIAS: + case D3DTSS_BUMPENVMAT00: + case D3DTSS_BUMPENVMAT01: + case D3DTSS_BUMPENVMAT10: + case D3DTSS_BUMPENVMAT11: + case D3DTSS_BUMPENVLSCALE: + case D3DTSS_BUMPENVLOFFSET: + name.Format("%f", *(float*)&value); + break; + + case D3DTSS_TEXCOORDINDEX: + if ((value & 0xffff0000) == D3DTSS_TCI_CAMERASPACENORMAL) { + name.Format("D3DTSS_TCI_CAMERASPACENORMAL|%d", value & 0xffff); + } + else if ((value & 0xffff0000) == D3DTSS_TCI_CAMERASPACEPOSITION) { + name.Format("D3DTSS_TCI_CAMERASPACEPOSITION|%d", value & 0xffff); + } + else if ((value & 0xffff0000) == D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR) { + name.Format("D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR|%d", value & 0xffff); + } + else { + name.Format("%d", value); + } + break; + + // Integer value + case D3DTSS_MAXMIPLEVEL: + case D3DTSS_MAXANISOTROPY: + name.Format("%d", value); + break; + // Hex values + case D3DTSS_BORDERCOLOR: + name.Format("0x%x", value); + break; + + default: + name.Format("UNKNOWN (%d)", value); + break; + } +} + +const char* DX8Wrapper::Get_DX8_Texture_Op_Name(unsigned value) +{ + switch (value) { + case D3DTOP_DISABLE: return "D3DTOP_DISABLE"; + case D3DTOP_SELECTARG1: return "D3DTOP_SELECTARG1"; + case D3DTOP_SELECTARG2: return "D3DTOP_SELECTARG2"; + case D3DTOP_MODULATE: return "D3DTOP_MODULATE"; + case D3DTOP_MODULATE2X: return "D3DTOP_MODULATE2X"; + case D3DTOP_MODULATE4X: return "D3DTOP_MODULATE4X"; + case D3DTOP_ADD: return "D3DTOP_ADD"; + case D3DTOP_ADDSIGNED: return "D3DTOP_ADDSIGNED"; + case D3DTOP_ADDSIGNED2X: return "D3DTOP_ADDSIGNED2X"; + case D3DTOP_SUBTRACT: return "D3DTOP_SUBTRACT"; + case D3DTOP_ADDSMOOTH: return "D3DTOP_ADDSMOOTH"; + case D3DTOP_BLENDDIFFUSEALPHA: return "D3DTOP_BLENDDIFFUSEALPHA"; + case D3DTOP_BLENDTEXTUREALPHA: return "D3DTOP_BLENDTEXTUREALPHA"; + case D3DTOP_BLENDFACTORALPHA: return "D3DTOP_BLENDFACTORALPHA"; + case D3DTOP_BLENDTEXTUREALPHAPM: return "D3DTOP_BLENDTEXTUREALPHAPM"; + case D3DTOP_BLENDCURRENTALPHA: return "D3DTOP_BLENDCURRENTALPHA"; + case D3DTOP_PREMODULATE: return "D3DTOP_PREMODULATE"; + case D3DTOP_MODULATEALPHA_ADDCOLOR: return "D3DTOP_MODULATEALPHA_ADDCOLOR"; + case D3DTOP_MODULATECOLOR_ADDALPHA: return "D3DTOP_MODULATECOLOR_ADDALPHA"; + case D3DTOP_MODULATEINVALPHA_ADDCOLOR: return "D3DTOP_MODULATEINVALPHA_ADDCOLOR"; + case D3DTOP_MODULATEINVCOLOR_ADDALPHA: return "D3DTOP_MODULATEINVCOLOR_ADDALPHA"; + case D3DTOP_BUMPENVMAP: return "D3DTOP_BUMPENVMAP"; + case D3DTOP_BUMPENVMAPLUMINANCE: return "D3DTOP_BUMPENVMAPLUMINANCE"; + case D3DTOP_DOTPRODUCT3: return "D3DTOP_DOTPRODUCT3"; + case D3DTOP_MULTIPLYADD: return "D3DTOP_MULTIPLYADD"; + case D3DTOP_LERP: return "D3DTOP_LERP"; + default: return "UNKNOWN"; + } +} + +const char* DX8Wrapper::Get_DX8_Texture_Arg_Name(unsigned value) +{ + switch (value) { + case D3DTA_CURRENT: return "D3DTA_CURRENT"; + case D3DTA_DIFFUSE: return "D3DTA_DIFFUSE"; + case D3DTA_SELECTMASK: return "D3DTA_SELECTMASK"; + case D3DTA_SPECULAR: return "D3DTA_SPECULAR"; + case D3DTA_TEMP: return "D3DTA_TEMP"; + case D3DTA_TEXTURE: return "D3DTA_TEXTURE"; + case D3DTA_TFACTOR: return "D3DTA_TFACTOR"; + case D3DTA_ALPHAREPLICATE: return "D3DTA_ALPHAREPLICATE"; + case D3DTA_COMPLEMENT: return "D3DTA_COMPLEMENT"; + default: return "UNKNOWN"; + } +} + +const char* DX8Wrapper::Get_DX8_Texture_Filter_Name(unsigned value) +{ + switch (value) { + case D3DTEXF_NONE: return "D3DTEXF_NONE"; + case D3DTEXF_POINT: return "D3DTEXF_POINT"; + case D3DTEXF_LINEAR: return "D3DTEXF_LINEAR"; + case D3DTEXF_ANISOTROPIC: return "D3DTEXF_ANISOTROPIC"; + case D3DTEXF_FLATCUBIC: return "D3DTEXF_FLATCUBIC"; + case D3DTEXF_GAUSSIANCUBIC: return "D3DTEXF_GAUSSIANCUBIC"; + default: return "UNKNOWN"; + } +} + +const char* DX8Wrapper::Get_DX8_Texture_Address_Name(unsigned value) +{ + switch (value) { + case D3DTADDRESS_WRAP: return "D3DTADDRESS_WRAP"; + case D3DTADDRESS_MIRROR: return "D3DTADDRESS_MIRROR"; + case D3DTADDRESS_CLAMP: return "D3DTADDRESS_CLAMP"; + case D3DTADDRESS_BORDER: return "D3DTADDRESS_BORDER"; + case D3DTADDRESS_MIRRORONCE: return "D3DTADDRESS_MIRRORONCE"; + default: return "UNKNOWN"; + } +} + +const char* DX8Wrapper::Get_DX8_Texture_Transform_Flag_Name(unsigned value) +{ + switch (value) { + case D3DTTFF_DISABLE: return "D3DTTFF_DISABLE"; + case D3DTTFF_COUNT1: return "D3DTTFF_COUNT1"; + case D3DTTFF_COUNT2: return "D3DTTFF_COUNT2"; + case D3DTTFF_COUNT3: return "D3DTTFF_COUNT3"; + case D3DTTFF_COUNT4: return "D3DTTFF_COUNT4"; + case D3DTTFF_PROJECTED: return "D3DTTFF_PROJECTED"; + default: return "UNKNOWN"; + } +} + +const char* DX8Wrapper::Get_DX8_ZBuffer_Type_Name(unsigned value) +{ + switch (value) { + case D3DZB_FALSE: return "D3DZB_FALSE"; + case D3DZB_TRUE: return "D3DZB_TRUE"; + case D3DZB_USEW: return "D3DZB_USEW"; + default: return "UNKNOWN"; + } +} + +const char* DX8Wrapper::Get_DX8_Fill_Mode_Name(unsigned value) +{ + switch (value) { + case D3DFILL_POINT: return "D3DFILL_POINT"; + case D3DFILL_WIREFRAME: return "D3DFILL_WIREFRAME"; + case D3DFILL_SOLID: return "D3DFILL_SOLID"; + default: return "UNKNOWN"; + } +} + +const char* DX8Wrapper::Get_DX8_Shade_Mode_Name(unsigned value) +{ + switch (value) { + case D3DSHADE_FLAT: return "D3DSHADE_FLAT"; + case D3DSHADE_GOURAUD: return "D3DSHADE_GOURAUD"; + case D3DSHADE_PHONG: return "D3DSHADE_PHONG"; + default: return "UNKNOWN"; + } +} + +const char* DX8Wrapper::Get_DX8_Blend_Name(unsigned value) +{ + switch (value) { + case D3DBLEND_ZERO: return "D3DBLEND_ZERO"; + case D3DBLEND_ONE: return "D3DBLEND_ONE"; + case D3DBLEND_SRCCOLOR: return "D3DBLEND_SRCCOLOR"; + case D3DBLEND_INVSRCCOLOR: return "D3DBLEND_INVSRCCOLOR"; + case D3DBLEND_SRCALPHA: return "D3DBLEND_SRCALPHA"; + case D3DBLEND_INVSRCALPHA: return "D3DBLEND_INVSRCALPHA"; + case D3DBLEND_DESTALPHA: return "D3DBLEND_DESTALPHA"; + case D3DBLEND_INVDESTALPHA: return "D3DBLEND_INVDESTALPHA"; + case D3DBLEND_DESTCOLOR: return "D3DBLEND_DESTCOLOR"; + case D3DBLEND_INVDESTCOLOR: return "D3DBLEND_INVDESTCOLOR"; + case D3DBLEND_SRCALPHASAT: return "D3DBLEND_SRCALPHASAT"; + case D3DBLEND_BOTHSRCALPHA: return "D3DBLEND_BOTHSRCALPHA"; + case D3DBLEND_BOTHINVSRCALPHA: return "D3DBLEND_BOTHINVSRCALPHA"; + default: return "UNKNOWN"; + } +} + +const char* DX8Wrapper::Get_DX8_Cull_Mode_Name(unsigned value) +{ + switch (value) { + case D3DCULL_NONE: return "D3DCULL_NONE"; + case D3DCULL_CW: return "D3DCULL_CW"; + case D3DCULL_CCW: return "D3DCULL_CCW"; + default: return "UNKNOWN"; + } +} + +const char* DX8Wrapper::Get_DX8_Cmp_Func_Name(unsigned value) +{ + switch (value) { + case D3DCMP_NEVER: return "D3DCMP_NEVER"; + case D3DCMP_LESS: return "D3DCMP_LESS"; + case D3DCMP_EQUAL: return "D3DCMP_EQUAL"; + case D3DCMP_LESSEQUAL: return "D3DCMP_LESSEQUAL"; + case D3DCMP_GREATER: return "D3DCMP_GREATER"; + case D3DCMP_NOTEQUAL: return "D3DCMP_NOTEQUAL"; + case D3DCMP_GREATEREQUAL: return "D3DCMP_GREATEREQUAL"; + case D3DCMP_ALWAYS: return "D3DCMP_ALWAYS"; + default: return "UNKNOWN"; + } +} + +const char* DX8Wrapper::Get_DX8_Fog_Mode_Name(unsigned value) +{ + switch (value) { + case D3DFOG_NONE: return "D3DFOG_NONE"; + case D3DFOG_EXP: return "D3DFOG_EXP"; + case D3DFOG_EXP2: return "D3DFOG_EXP2"; + case D3DFOG_LINEAR: return "D3DFOG_LINEAR"; + default: return "UNKNOWN"; + } +} + +const char* DX8Wrapper::Get_DX8_Stencil_Op_Name(unsigned value) +{ + switch (value) { + case D3DSTENCILOP_KEEP: return "D3DSTENCILOP_KEEP"; + case D3DSTENCILOP_ZERO: return "D3DSTENCILOP_ZERO"; + case D3DSTENCILOP_REPLACE: return "D3DSTENCILOP_REPLACE"; + case D3DSTENCILOP_INCRSAT: return "D3DSTENCILOP_INCRSAT"; + case D3DSTENCILOP_DECRSAT: return "D3DSTENCILOP_DECRSAT"; + case D3DSTENCILOP_INVERT: return "D3DSTENCILOP_INVERT"; + case D3DSTENCILOP_INCR: return "D3DSTENCILOP_INCR"; + case D3DSTENCILOP_DECR: return "D3DSTENCILOP_DECR"; + default: return "UNKNOWN"; + } +} + +const char* DX8Wrapper::Get_DX8_Material_Source_Name(unsigned value) +{ + switch (value) { + case D3DMCS_MATERIAL: return "D3DMCS_MATERIAL"; + case D3DMCS_COLOR1: return "D3DMCS_COLOR1"; + case D3DMCS_COLOR2: return "D3DMCS_COLOR2"; + default: return "UNKNOWN"; + } +} + +const char* DX8Wrapper::Get_DX8_Vertex_Blend_Flag_Name(unsigned value) +{ + switch (value) { + case D3DVBF_DISABLE: return "D3DVBF_DISABLE"; + case D3DVBF_1WEIGHTS: return "D3DVBF_1WEIGHTS"; + case D3DVBF_2WEIGHTS: return "D3DVBF_2WEIGHTS"; + case D3DVBF_3WEIGHTS: return "D3DVBF_3WEIGHTS"; + case D3DVBF_TWEENING: return "D3DVBF_TWEENING"; + case D3DVBF_0WEIGHTS: return "D3DVBF_0WEIGHTS"; + default: return "UNKNOWN"; + } +} + +const char* DX8Wrapper::Get_DX8_Patch_Edge_Style_Name(unsigned value) +{ + switch (value) { + case D3DPATCHEDGE_DISCRETE: return "D3DPATCHEDGE_DISCRETE"; + case D3DPATCHEDGE_CONTINUOUS:return "D3DPATCHEDGE_CONTINUOUS"; + default: return "UNKNOWN"; + } +} + +const char* DX8Wrapper::Get_DX8_Debug_Monitor_Token_Name(unsigned value) +{ + switch (value) { + case D3DDMT_ENABLE: return "D3DDMT_ENABLE"; + case D3DDMT_DISABLE: return "D3DDMT_DISABLE"; + default: return "UNKNOWN"; + } +} + +const char* DX8Wrapper::Get_DX8_Blend_Op_Name(unsigned value) +{ + switch (value) { + case D3DBLENDOP_ADD: return "D3DBLENDOP_ADD"; + case D3DBLENDOP_SUBTRACT: return "D3DBLENDOP_SUBTRACT"; + case D3DBLENDOP_REVSUBTRACT: return "D3DBLENDOP_REVSUBTRACT"; + case D3DBLENDOP_MIN: return "D3DBLENDOP_MIN"; + case D3DBLENDOP_MAX: return "D3DBLENDOP_MAX"; + default: return "UNKNOWN"; + } +} + + +//============================================================================ +// DX8Wrapper::getBackBufferFormat +//============================================================================ + +WW3DFormat DX8Wrapper::getBackBufferFormat(void) +{ + return D3DFormat_To_WW3DFormat(_PresentParameters.BackBufferFormat); +} diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 68b8b535ba7..3b6153c3914 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -264,1148 +264,3 @@ void MoveRectIntoOtherRect(const RECT& inner, const RECT& outer, int* x, int* y) #include "../../Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h" - -//void -//DX8Wrapper::Set_Render_Target -//(TextureClass * texture) -//{ -// WWASSERT(texture != NULL); -// SurfaceClass * surf = texture->Get_Surface_Level(); -// WWASSERT(surf != NULL); -// Set_Render_Target(surf->Peek_D3D_Surface()); -// REF_PTR_RELEASE(surf); -//} - -/*! - * Set render target - * KM Added optional custom z target - */ -void DX8Wrapper::Set_Render_Target_With_Z -( - TextureClass* texture, - ZTextureClass* ztexture -) -{ - 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 -DX8Wrapper::Set_Render_Target(IDirect3DSwapChain8 *swap_chain) -{ - DX8_THREAD_ASSERT(); - WWASSERT (swap_chain != NULL); - - // - // Get the back buffer for the swap chain - // - LPDIRECT3DSURFACE8 render_target = NULL; - swap_chain->GetBackBuffer (0, D3DBACKBUFFER_TYPE_MONO, &render_target); - - // - // Set this back buffer as the render targer - // - Set_Render_Target (render_target); - - // - // Release our hold on the back buffer - // - if (render_target != NULL) { - render_target->Release (); - render_target = NULL; - } - - IsRenderToTexture = false; - - return ; -} - -void -DX8Wrapper::Set_Render_Target(IDirect3DSurface8* render_target, bool use_default_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; - WWASSERT(CurrentRenderTarget != NULL); - if (CurrentRenderTarget != NULL) - { - CurrentRenderTarget->AddRef(); - - // - // Switch render targets - // - 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; -// } - - 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 -} - -IDirect3DSwapChain8 * -DX8Wrapper::Create_Additional_Swap_Chain (HWND render_window) -{ - DX8_Assert(); - - // - // Configure the presentation parameters for a windowed render target - // - D3DPRESENT_PARAMETERS params = { 0 }; - params.BackBufferFormat = _PresentParameters.BackBufferFormat; - params.BackBufferCount = 1; - params.MultiSampleType = D3DMULTISAMPLE_NONE; - params.SwapEffect = D3DSWAPEFFECT_COPY_VSYNC; - params.hDeviceWindow = render_window; - params.Windowed = TRUE; - params.EnableAutoDepthStencil = TRUE; - params.AutoDepthStencilFormat = _PresentParameters.AutoDepthStencilFormat; - params.Flags = 0; - params.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT; - params.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; - - // - // Create the swap chain - // - IDirect3DSwapChain8 *swap_chain = NULL; - DX8CALL(CreateAdditionalSwapChain(¶ms, &swap_chain)); - return swap_chain; -} - -void DX8Wrapper::Flush_DX8_Resource_Manager(unsigned int bytes) -{ - DX8_Assert(); - DX8CALL(ResourceManagerDiscardBytes(bytes)); -} - -unsigned int DX8Wrapper::Get_Free_Texture_RAM() -{ - DX8_Assert(); - number_of_DX8_calls++; - return DX8Wrapper::_Get_D3D_Device8()->GetAvailableTextureMem(); -} - -// Converts a linear gamma ramp to one that is controlled by: -// Gamma - controls the curvature of the middle of the curve -// Bright - controls the minimum value of the curve -// Contrast - controls the difference between the maximum and the minimum of the curve -void DX8Wrapper::Set_Gamma(float gamma,float bright,float contrast,bool calibrate,bool uselimit) -{ - gamma=Bound(gamma,0.6f,6.0f); - bright=Bound(bright,-0.5f,0.5f); - contrast=Bound(contrast,0.5f,2.0f); - float oo_gamma=1.0f/gamma; - - DX8_Assert(); - number_of_DX8_calls++; - - DWORD flag=(calibrate?D3DSGR_CALIBRATE:D3DSGR_NO_CALIBRATION); - - D3DGAMMARAMP ramp; - float limit; - - // IML: I'm not really sure what the intent of the 'limit' variable is. It does not produce useful results for my purposes. - if (uselimit) { - limit=(contrast-1)/2*contrast; - } else { - limit = 0.0f; - } - - // HY - arrived at this equation after much trial and error. - for (int i=0; i<256; i++) { - float in,out; - in=i/256.0f; - float x=in-limit; - x=Bound(x,0.0f,1.0f); - x=powf(x,oo_gamma); - out=contrast*x+bright; - out=Bound(out,0.0f,1.0f); - ramp.red[i]=(WORD) (out*65535); - ramp.green[i]=(WORD) (out*65535); - ramp.blue[i]=(WORD) (out*65535); - } - - if (Get_Current_Caps()->Support_Gamma()) { - DX8Wrapper::_Get_D3D_Device8()->SetGammaRamp(flag,&ramp); - } else { - HWND hwnd = GetDesktopWindow(); - HDC hdc = GetDC(hwnd); - if (hdc) - { - SetDeviceGammaRamp (hdc, &ramp); - ReleaseDC (hwnd, hdc); - } - } -} - -//********************************************************************************************** -//! Resets render device to default state -/*! -*/ -void DX8Wrapper::Apply_Default_State() -{ - SNAPSHOT_SAY(("DX8Wrapper::Apply_Default_State()")); - - // only set states used in game - Set_DX8_Render_State(D3DRS_ZENABLE, TRUE); -// Set_DX8_Render_State(D3DRS_FILLMODE, D3DFILL_SOLID); - Set_DX8_Render_State(D3DRS_SHADEMODE, D3DSHADE_GOURAUD); - //Set_DX8_Render_State(D3DRS_LINEPATTERN, 0); - Set_DX8_Render_State(D3DRS_ZWRITEENABLE, TRUE); - Set_DX8_Render_State(D3DRS_ALPHATESTENABLE, FALSE); - //Set_DX8_Render_State(D3DRS_LASTPIXEL, FALSE); - Set_DX8_Render_State(D3DRS_SRCBLEND, D3DBLEND_ONE); - Set_DX8_Render_State(D3DRS_DESTBLEND, D3DBLEND_ZERO); - Set_DX8_Render_State(D3DRS_CULLMODE, D3DCULL_CW); - Set_DX8_Render_State(D3DRS_ZFUNC, D3DCMP_LESSEQUAL); - Set_DX8_Render_State(D3DRS_ALPHAREF, 0); - Set_DX8_Render_State(D3DRS_ALPHAFUNC, D3DCMP_LESSEQUAL); - Set_DX8_Render_State(D3DRS_DITHERENABLE, FALSE); - Set_DX8_Render_State(D3DRS_ALPHABLENDENABLE, FALSE); - Set_DX8_Render_State(D3DRS_FOGENABLE, FALSE); - Set_DX8_Render_State(D3DRS_SPECULARENABLE, FALSE); -// Set_DX8_Render_State(D3DRS_ZVISIBLE, FALSE); -// Set_DX8_Render_State(D3DRS_FOGCOLOR, 0); -// Set_DX8_Render_State(D3DRS_FOGTABLEMODE, D3DFOG_NONE); -// Set_DX8_Render_State(D3DRS_FOGSTART, 0); - -// Set_DX8_Render_State(D3DRS_FOGEND, WWMath::Float_As_Int(1.0f)); -// Set_DX8_Render_State(D3DRS_FOGDENSITY, WWMath::Float_As_Int(1.0f)); - - //Set_DX8_Render_State(D3DRS_EDGEANTIALIAS, FALSE); - Set_DX8_Render_State(D3DRS_ZBIAS, 0); -// Set_DX8_Render_State(D3DRS_RANGEFOGENABLE, FALSE); - Set_DX8_Render_State(D3DRS_STENCILENABLE, FALSE); - Set_DX8_Render_State(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP); - Set_DX8_Render_State(D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP); - Set_DX8_Render_State(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP); - Set_DX8_Render_State(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); - Set_DX8_Render_State(D3DRS_STENCILREF, 0); - Set_DX8_Render_State(D3DRS_STENCILMASK, 0xffffffff); - Set_DX8_Render_State(D3DRS_STENCILWRITEMASK, 0xffffffff); - Set_DX8_Render_State(D3DRS_TEXTUREFACTOR, 0); -/* Set_DX8_Render_State(D3DRS_WRAP0, D3DWRAP_U| D3DWRAP_V); - Set_DX8_Render_State(D3DRS_WRAP1, D3DWRAP_U| D3DWRAP_V); - Set_DX8_Render_State(D3DRS_WRAP2, D3DWRAP_U| D3DWRAP_V); - Set_DX8_Render_State(D3DRS_WRAP3, D3DWRAP_U| D3DWRAP_V); - Set_DX8_Render_State(D3DRS_WRAP4, D3DWRAP_U| D3DWRAP_V); - Set_DX8_Render_State(D3DRS_WRAP5, D3DWRAP_U| D3DWRAP_V); - Set_DX8_Render_State(D3DRS_WRAP6, D3DWRAP_U| D3DWRAP_V); - Set_DX8_Render_State(D3DRS_WRAP7, D3DWRAP_U| D3DWRAP_V);*/ - Set_DX8_Render_State(D3DRS_CLIPPING, TRUE); - Set_DX8_Render_State(D3DRS_LIGHTING, FALSE); - //Set_DX8_Render_State(D3DRS_AMBIENT, 0); -// Set_DX8_Render_State(D3DRS_FOGVERTEXMODE, D3DFOG_NONE); - Set_DX8_Render_State(D3DRS_COLORVERTEX, TRUE); -/* Set_DX8_Render_State(D3DRS_LOCALVIEWER, TRUE); - Set_DX8_Render_State(D3DRS_NORMALIZENORMALS, FALSE); - Set_DX8_Render_State(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1); - Set_DX8_Render_State(D3DRS_SPECULARMATERIALSOURCE, D3DMCS_COLOR2); - Set_DX8_Render_State(D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_MATERIAL); - Set_DX8_Render_State(D3DRS_EMISSIVEMATERIALSOURCE, D3DMCS_MATERIAL); - Set_DX8_Render_State(D3DRS_VERTEXBLEND, D3DVBF_DISABLE);*/ - //Set_DX8_Render_State(D3DRS_CLIPPLANEENABLE, 0); - Set_DX8_Render_State(D3DRS_SOFTWAREVERTEXPROCESSING, FALSE); - //Set_DX8_Render_State(D3DRS_POINTSIZE, 0x3f800000); - //Set_DX8_Render_State(D3DRS_POINTSIZE_MIN, 0); - //Set_DX8_Render_State(D3DRS_POINTSPRITEENABLE, FALSE); - //Set_DX8_Render_State(D3DRS_POINTSCALEENABLE, FALSE); - //Set_DX8_Render_State(D3DRS_POINTSCALE_A, 0); - //Set_DX8_Render_State(D3DRS_POINTSCALE_B, 0); - //Set_DX8_Render_State(D3DRS_POINTSCALE_C, 0); - //Set_DX8_Render_State(D3DRS_MULTISAMPLEANTIALIAS, TRUE); - //Set_DX8_Render_State(D3DRS_MULTISAMPLEMASK, 0xffffffff); - //Set_DX8_Render_State(D3DRS_PATCHEDGESTYLE, D3DPATCHEDGE_DISCRETE); - //Set_DX8_Render_State(D3DRS_PATCHSEGMENTS, 0x3f800000); - //Set_DX8_Render_State(D3DRS_DEBUGMONITORTOKEN, D3DDMT_ENABLE); - //Set_DX8_Render_State(D3DRS_POINTSIZE_MAX, Float_At_Int(64.0f)); - //Set_DX8_Render_State(D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE); - Set_DX8_Render_State(D3DRS_COLORWRITEENABLE, 0x0000000f); - //Set_DX8_Render_State(D3DRS_TWEENFACTOR, 0); - Set_DX8_Render_State(D3DRS_BLENDOP, D3DBLENDOP_ADD); - //Set_DX8_Render_State(D3DRS_POSITIONORDER, D3DORDER_CUBIC); - //Set_DX8_Render_State(D3DRS_NORMALORDER, D3DORDER_LINEAR); - - // disable TSS stages - int i; - for (i=0; iGet_Max_Textures_Per_Pass(); i++) - { - Set_DX8_Texture_Stage_State(i, D3DTSS_COLOROP, D3DTOP_DISABLE); - Set_DX8_Texture_Stage_State(i, D3DTSS_COLORARG1, D3DTA_TEXTURE); - Set_DX8_Texture_Stage_State(i, D3DTSS_COLORARG2, D3DTA_DIFFUSE); - - Set_DX8_Texture_Stage_State(i, D3DTSS_ALPHAOP, D3DTOP_DISABLE); - Set_DX8_Texture_Stage_State(i, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); - Set_DX8_Texture_Stage_State(i, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); - - /*Set_DX8_Texture_Stage_State(i, D3DTSS_BUMPENVMAT00, 0); - Set_DX8_Texture_Stage_State(i, D3DTSS_BUMPENVMAT01, 0); - Set_DX8_Texture_Stage_State(i, D3DTSS_BUMPENVMAT10, 0); - Set_DX8_Texture_Stage_State(i, D3DTSS_BUMPENVMAT11, 0); - Set_DX8_Texture_Stage_State(i, D3DTSS_BUMPENVLSCALE, 0); - Set_DX8_Texture_Stage_State(i, D3DTSS_BUMPENVLOFFSET, 0);*/ - - Set_DX8_Texture_Stage_State(i, D3DTSS_TEXCOORDINDEX, i); - - - Set_DX8_Texture_Stage_State(i, D3DTSS_ADDRESSU, D3DTADDRESS_WRAP); - Set_DX8_Texture_Stage_State(i, D3DTSS_ADDRESSV, D3DTADDRESS_WRAP); - Set_DX8_Texture_Stage_State(i, D3DTSS_BORDERCOLOR, 0); -// Set_DX8_Texture_Stage_State(i, D3DTSS_MAGFILTER, D3DTEXF_LINEAR); -// Set_DX8_Texture_Stage_State(i, D3DTSS_MINFILTER, D3DTEXF_LINEAR); -// Set_DX8_Texture_Stage_State(i, D3DTSS_MIPFILTER, D3DTEXF_LINEAR); -// Set_DX8_Texture_Stage_State(i, D3DTSS_MIPMAPLODBIAS, 0); -// Set_DX8_Texture_Stage_State(i, D3DTSS_MAXMIPLEVEL, 0); -// Set_DX8_Texture_Stage_State(i, D3DTSS_MAXANISOTROPY, 1); - //Set_DX8_Texture_Stage_State(i, D3DTSS_ADDRESSW, D3DTADDRESS_WRAP); - //Set_DX8_Texture_Stage_State(i, D3DTSS_COLORARG0, D3DTA_CURRENT); - //Set_DX8_Texture_Stage_State(i, D3DTSS_ALPHAARG0, D3DTA_CURRENT); - //Set_DX8_Texture_Stage_State(i, D3DTSS_RESULTARG, D3DTA_CURRENT); - - Set_DX8_Texture_Stage_State(i, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE); - Set_Texture(i,NULL); - } - -// DX8Wrapper::Set_Material(NULL); - VertexMaterialClass::Apply_Null(); - - for (unsigned index=0;index<4;++index) { - SNAPSHOT_SAY(("Clearing light %d to NULL",index)); - Set_DX8_Light(index,NULL); - } - - // set up simple default TSS - Vector4 vconst[MAX_VERTEX_SHADER_CONSTANTS]; - memset(vconst,0,sizeof(Vector4)*MAX_VERTEX_SHADER_CONSTANTS); - Set_Vertex_Shader_Constant(0, vconst, MAX_VERTEX_SHADER_CONSTANTS); - - Vector4 pconst[MAX_PIXEL_SHADER_CONSTANTS]; - memset(pconst,0,sizeof(Vector4)*MAX_PIXEL_SHADER_CONSTANTS); - Set_Pixel_Shader_Constant(0, pconst, MAX_PIXEL_SHADER_CONSTANTS); - - Set_Vertex_Shader(DX8_FVF_XYZNDUV2); - Set_Pixel_Shader(0); - - ShaderClass::Invalidate(); -} - -const char* DX8Wrapper::Get_DX8_Render_State_Name(D3DRENDERSTATETYPE state) -{ - switch (state) { - case D3DRS_ZENABLE : return "D3DRS_ZENABLE"; - case D3DRS_FILLMODE : return "D3DRS_FILLMODE"; - case D3DRS_SHADEMODE : return "D3DRS_SHADEMODE"; - case D3DRS_LINEPATTERN : return "D3DRS_LINEPATTERN"; - case D3DRS_ZWRITEENABLE : return "D3DRS_ZWRITEENABLE"; - case D3DRS_ALPHATESTENABLE : return "D3DRS_ALPHATESTENABLE"; - case D3DRS_LASTPIXEL : return "D3DRS_LASTPIXEL"; - case D3DRS_SRCBLEND : return "D3DRS_SRCBLEND"; - case D3DRS_DESTBLEND : return "D3DRS_DESTBLEND"; - case D3DRS_CULLMODE : return "D3DRS_CULLMODE"; - case D3DRS_ZFUNC : return "D3DRS_ZFUNC"; - case D3DRS_ALPHAREF : return "D3DRS_ALPHAREF"; - case D3DRS_ALPHAFUNC : return "D3DRS_ALPHAFUNC"; - case D3DRS_DITHERENABLE : return "D3DRS_DITHERENABLE"; - case D3DRS_ALPHABLENDENABLE : return "D3DRS_ALPHABLENDENABLE"; - case D3DRS_FOGENABLE : return "D3DRS_FOGENABLE"; - case D3DRS_SPECULARENABLE : return "D3DRS_SPECULARENABLE"; - case D3DRS_ZVISIBLE : return "D3DRS_ZVISIBLE"; - case D3DRS_FOGCOLOR : return "D3DRS_FOGCOLOR"; - case D3DRS_FOGTABLEMODE : return "D3DRS_FOGTABLEMODE"; - case D3DRS_FOGSTART : return "D3DRS_FOGSTART"; - case D3DRS_FOGEND : return "D3DRS_FOGEND"; - case D3DRS_FOGDENSITY : return "D3DRS_FOGDENSITY"; - case D3DRS_EDGEANTIALIAS : return "D3DRS_EDGEANTIALIAS"; - case D3DRS_ZBIAS : return "D3DRS_ZBIAS"; - case D3DRS_RANGEFOGENABLE : return "D3DRS_RANGEFOGENABLE"; - case D3DRS_STENCILENABLE : return "D3DRS_STENCILENABLE"; - case D3DRS_STENCILFAIL : return "D3DRS_STENCILFAIL"; - case D3DRS_STENCILZFAIL : return "D3DRS_STENCILZFAIL"; - case D3DRS_STENCILPASS : return "D3DRS_STENCILPASS"; - case D3DRS_STENCILFUNC : return "D3DRS_STENCILFUNC"; - case D3DRS_STENCILREF : return "D3DRS_STENCILREF"; - case D3DRS_STENCILMASK : return "D3DRS_STENCILMASK"; - case D3DRS_STENCILWRITEMASK : return "D3DRS_STENCILWRITEMASK"; - case D3DRS_TEXTUREFACTOR : return "D3DRS_TEXTUREFACTOR"; - case D3DRS_WRAP0 : return "D3DRS_WRAP0"; - case D3DRS_WRAP1 : return "D3DRS_WRAP1"; - case D3DRS_WRAP2 : return "D3DRS_WRAP2"; - case D3DRS_WRAP3 : return "D3DRS_WRAP3"; - case D3DRS_WRAP4 : return "D3DRS_WRAP4"; - case D3DRS_WRAP5 : return "D3DRS_WRAP5"; - case D3DRS_WRAP6 : return "D3DRS_WRAP6"; - case D3DRS_WRAP7 : return "D3DRS_WRAP7"; - case D3DRS_CLIPPING : return "D3DRS_CLIPPING"; - case D3DRS_LIGHTING : return "D3DRS_LIGHTING"; - case D3DRS_AMBIENT : return "D3DRS_AMBIENT"; - case D3DRS_FOGVERTEXMODE : return "D3DRS_FOGVERTEXMODE"; - case D3DRS_COLORVERTEX : return "D3DRS_COLORVERTEX"; - case D3DRS_LOCALVIEWER : return "D3DRS_LOCALVIEWER"; - case D3DRS_NORMALIZENORMALS : return "D3DRS_NORMALIZENORMALS"; - case D3DRS_DIFFUSEMATERIALSOURCE : return "D3DRS_DIFFUSEMATERIALSOURCE"; - case D3DRS_SPECULARMATERIALSOURCE : return "D3DRS_SPECULARMATERIALSOURCE"; - case D3DRS_AMBIENTMATERIALSOURCE : return "D3DRS_AMBIENTMATERIALSOURCE"; - case D3DRS_EMISSIVEMATERIALSOURCE : return "D3DRS_EMISSIVEMATERIALSOURCE"; - case D3DRS_VERTEXBLEND : return "D3DRS_VERTEXBLEND"; - case D3DRS_CLIPPLANEENABLE : return "D3DRS_CLIPPLANEENABLE"; - case D3DRS_SOFTWAREVERTEXPROCESSING : return "D3DRS_SOFTWAREVERTEXPROCESSING"; - case D3DRS_POINTSIZE : return "D3DRS_POINTSIZE"; - case D3DRS_POINTSIZE_MIN : return "D3DRS_POINTSIZE_MIN"; - case D3DRS_POINTSPRITEENABLE : return "D3DRS_POINTSPRITEENABLE"; - case D3DRS_POINTSCALEENABLE : return "D3DRS_POINTSCALEENABLE"; - case D3DRS_POINTSCALE_A : return "D3DRS_POINTSCALE_A"; - case D3DRS_POINTSCALE_B : return "D3DRS_POINTSCALE_B"; - case D3DRS_POINTSCALE_C : return "D3DRS_POINTSCALE_C"; - case D3DRS_MULTISAMPLEANTIALIAS : return "D3DRS_MULTISAMPLEANTIALIAS"; - case D3DRS_MULTISAMPLEMASK : return "D3DRS_MULTISAMPLEMASK"; - case D3DRS_PATCHEDGESTYLE : return "D3DRS_PATCHEDGESTYLE"; - case D3DRS_PATCHSEGMENTS : return "D3DRS_PATCHSEGMENTS"; - case D3DRS_DEBUGMONITORTOKEN : return "D3DRS_DEBUGMONITORTOKEN"; - case D3DRS_POINTSIZE_MAX : return "D3DRS_POINTSIZE_MAX"; - case D3DRS_INDEXEDVERTEXBLENDENABLE : return "D3DRS_INDEXEDVERTEXBLENDENABLE"; - case D3DRS_COLORWRITEENABLE : return "D3DRS_COLORWRITEENABLE"; - case D3DRS_TWEENFACTOR : return "D3DRS_TWEENFACTOR"; - case D3DRS_BLENDOP : return "D3DRS_BLENDOP"; -// case D3DRS_POSITIONORDER : return "D3DRS_POSITIONORDER"; -// case D3DRS_NORMALORDER : return "D3DRS_NORMALORDER"; - default : return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Texture_Stage_State_Name(D3DTEXTURESTAGESTATETYPE state) -{ - switch (state) { - case D3DTSS_COLOROP : return "D3DTSS_COLOROP"; - case D3DTSS_COLORARG1 : return "D3DTSS_COLORARG1"; - case D3DTSS_COLORARG2 : return "D3DTSS_COLORARG2"; - case D3DTSS_ALPHAOP : return "D3DTSS_ALPHAOP"; - case D3DTSS_ALPHAARG1 : return "D3DTSS_ALPHAARG1"; - case D3DTSS_ALPHAARG2 : return "D3DTSS_ALPHAARG2"; - case D3DTSS_BUMPENVMAT00 : return "D3DTSS_BUMPENVMAT00"; - case D3DTSS_BUMPENVMAT01 : return "D3DTSS_BUMPENVMAT01"; - case D3DTSS_BUMPENVMAT10 : return "D3DTSS_BUMPENVMAT10"; - case D3DTSS_BUMPENVMAT11 : return "D3DTSS_BUMPENVMAT11"; - case D3DTSS_TEXCOORDINDEX : return "D3DTSS_TEXCOORDINDEX"; - case D3DTSS_ADDRESSU : return "D3DTSS_ADDRESSU"; - case D3DTSS_ADDRESSV : return "D3DTSS_ADDRESSV"; - case D3DTSS_BORDERCOLOR : return "D3DTSS_BORDERCOLOR"; - case D3DTSS_MAGFILTER : return "D3DTSS_MAGFILTER"; - case D3DTSS_MINFILTER : return "D3DTSS_MINFILTER"; - case D3DTSS_MIPFILTER : return "D3DTSS_MIPFILTER"; - case D3DTSS_MIPMAPLODBIAS : return "D3DTSS_MIPMAPLODBIAS"; - case D3DTSS_MAXMIPLEVEL : return "D3DTSS_MAXMIPLEVEL"; - case D3DTSS_MAXANISOTROPY : return "D3DTSS_MAXANISOTROPY"; - case D3DTSS_BUMPENVLSCALE : return "D3DTSS_BUMPENVLSCALE"; - case D3DTSS_BUMPENVLOFFSET : return "D3DTSS_BUMPENVLOFFSET"; - case D3DTSS_TEXTURETRANSFORMFLAGS : return "D3DTSS_TEXTURETRANSFORMFLAGS"; - case D3DTSS_ADDRESSW : return "D3DTSS_ADDRESSW"; - case D3DTSS_COLORARG0 : return "D3DTSS_COLORARG0"; - case D3DTSS_ALPHAARG0 : return "D3DTSS_ALPHAARG0"; - case D3DTSS_RESULTARG : return "D3DTSS_RESULTARG"; - default : return "UNKNOWN"; - } -} - -void DX8Wrapper::Get_DX8_Render_State_Value_Name(StringClass& name, D3DRENDERSTATETYPE state, unsigned value) -{ - switch (state) { - case D3DRS_ZENABLE: - name=Get_DX8_ZBuffer_Type_Name(value); - break; - - case D3DRS_FILLMODE: - name=Get_DX8_Fill_Mode_Name(value); - break; - - case D3DRS_SHADEMODE: - name=Get_DX8_Shade_Mode_Name(value); - break; - - case D3DRS_LINEPATTERN: - case D3DRS_FOGCOLOR: - case D3DRS_ALPHAREF: - case D3DRS_STENCILMASK: - case D3DRS_STENCILWRITEMASK: - case D3DRS_TEXTUREFACTOR: - case D3DRS_AMBIENT: - case D3DRS_CLIPPLANEENABLE: - case D3DRS_MULTISAMPLEMASK: - name.Format("0x%x",value); - break; - - case D3DRS_ZWRITEENABLE: - case D3DRS_ALPHATESTENABLE: - case D3DRS_LASTPIXEL: - case D3DRS_DITHERENABLE: - case D3DRS_ALPHABLENDENABLE: - case D3DRS_FOGENABLE: - case D3DRS_SPECULARENABLE: - case D3DRS_STENCILENABLE: - case D3DRS_RANGEFOGENABLE: - case D3DRS_EDGEANTIALIAS: - case D3DRS_CLIPPING: - case D3DRS_LIGHTING: - case D3DRS_COLORVERTEX: - case D3DRS_LOCALVIEWER: - case D3DRS_NORMALIZENORMALS: - case D3DRS_SOFTWAREVERTEXPROCESSING: - case D3DRS_POINTSPRITEENABLE: - case D3DRS_POINTSCALEENABLE: - case D3DRS_MULTISAMPLEANTIALIAS: - case D3DRS_INDEXEDVERTEXBLENDENABLE: - name=value ? "TRUE" : "FALSE"; - break; - - case D3DRS_SRCBLEND: - case D3DRS_DESTBLEND: - name=Get_DX8_Blend_Name(value); - break; - - case D3DRS_CULLMODE: - name=Get_DX8_Cull_Mode_Name(value); - break; - - case D3DRS_ZFUNC: - case D3DRS_ALPHAFUNC: - case D3DRS_STENCILFUNC: - name=Get_DX8_Cmp_Func_Name(value); - break; - - case D3DRS_ZVISIBLE: - name="NOTSUPPORTED"; - break; - - case D3DRS_FOGTABLEMODE: - case D3DRS_FOGVERTEXMODE: - name=Get_DX8_Fog_Mode_Name(value); - break; - - case D3DRS_FOGSTART: - case D3DRS_FOGEND: - case D3DRS_FOGDENSITY: - case D3DRS_POINTSIZE: - case D3DRS_POINTSIZE_MIN: - case D3DRS_POINTSCALE_A: - case D3DRS_POINTSCALE_B: - case D3DRS_POINTSCALE_C: - case D3DRS_PATCHSEGMENTS: - case D3DRS_POINTSIZE_MAX: - case D3DRS_TWEENFACTOR: - name.Format("%f",*(float*)&value); - break; - - case D3DRS_ZBIAS: - case D3DRS_STENCILREF: - name.Format("%d",value); - break; - - case D3DRS_STENCILFAIL: - case D3DRS_STENCILZFAIL: - case D3DRS_STENCILPASS: - name=Get_DX8_Stencil_Op_Name(value); - break; - - case D3DRS_WRAP0: - case D3DRS_WRAP1: - case D3DRS_WRAP2: - case D3DRS_WRAP3: - case D3DRS_WRAP4: - case D3DRS_WRAP5: - case D3DRS_WRAP6: - case D3DRS_WRAP7: - name="0"; - if (value&D3DWRAP_U) name+="|D3DWRAP_U"; - if (value&D3DWRAP_V) name+="|D3DWRAP_V"; - if (value&D3DWRAP_W) name+="|D3DWRAP_W"; - break; - - case D3DRS_DIFFUSEMATERIALSOURCE: - case D3DRS_SPECULARMATERIALSOURCE: - case D3DRS_AMBIENTMATERIALSOURCE: - case D3DRS_EMISSIVEMATERIALSOURCE: - name=Get_DX8_Material_Source_Name(value); - break; - - case D3DRS_VERTEXBLEND: - name=Get_DX8_Vertex_Blend_Flag_Name(value); - break; - - case D3DRS_PATCHEDGESTYLE: - name=Get_DX8_Patch_Edge_Style_Name(value); - break; - - case D3DRS_DEBUGMONITORTOKEN: - name=Get_DX8_Debug_Monitor_Token_Name(value); - break; - - case D3DRS_COLORWRITEENABLE: - name="0"; - if (value&D3DCOLORWRITEENABLE_RED) name+="|D3DCOLORWRITEENABLE_RED"; - if (value&D3DCOLORWRITEENABLE_GREEN) name+="|D3DCOLORWRITEENABLE_GREEN"; - if (value&D3DCOLORWRITEENABLE_BLUE) name+="|D3DCOLORWRITEENABLE_BLUE"; - if (value&D3DCOLORWRITEENABLE_ALPHA) name+="|D3DCOLORWRITEENABLE_ALPHA"; - break; - case D3DRS_BLENDOP: - name=Get_DX8_Blend_Op_Name(value); - break; - default: - name.Format("UNKNOWN (%d)",value); - break; - } -} - -void DX8Wrapper::Get_DX8_Texture_Stage_State_Value_Name(StringClass& name, D3DTEXTURESTAGESTATETYPE state, unsigned value) -{ - switch (state) { - case D3DTSS_COLOROP: - case D3DTSS_ALPHAOP: - name=Get_DX8_Texture_Op_Name(value); - break; - - case D3DTSS_COLORARG0: - case D3DTSS_COLORARG1: - case D3DTSS_COLORARG2: - case D3DTSS_ALPHAARG0: - case D3DTSS_ALPHAARG1: - case D3DTSS_ALPHAARG2: - case D3DTSS_RESULTARG: - name=Get_DX8_Texture_Arg_Name(value); - break; - - case D3DTSS_ADDRESSU: - case D3DTSS_ADDRESSV: - case D3DTSS_ADDRESSW: - name=Get_DX8_Texture_Address_Name(value); - break; - - case D3DTSS_MAGFILTER: - case D3DTSS_MINFILTER: - case D3DTSS_MIPFILTER: - name=Get_DX8_Texture_Filter_Name(value); - break; - - case D3DTSS_TEXTURETRANSFORMFLAGS: - name=Get_DX8_Texture_Transform_Flag_Name(value); - break; - - // Floating point values - case D3DTSS_MIPMAPLODBIAS: - case D3DTSS_BUMPENVMAT00: - case D3DTSS_BUMPENVMAT01: - case D3DTSS_BUMPENVMAT10: - case D3DTSS_BUMPENVMAT11: - case D3DTSS_BUMPENVLSCALE: - case D3DTSS_BUMPENVLOFFSET: - name.Format("%f",*(float*)&value); - break; - - case D3DTSS_TEXCOORDINDEX: - if ((value&0xffff0000)==D3DTSS_TCI_CAMERASPACENORMAL) { - name.Format("D3DTSS_TCI_CAMERASPACENORMAL|%d",value&0xffff); - } - else if ((value&0xffff0000)==D3DTSS_TCI_CAMERASPACEPOSITION) { - name.Format("D3DTSS_TCI_CAMERASPACEPOSITION|%d",value&0xffff); - } - else if ((value&0xffff0000)==D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR) { - name.Format("D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR|%d",value&0xffff); - } - else { - name.Format("%d",value); - } - break; - - // Integer value - case D3DTSS_MAXMIPLEVEL: - case D3DTSS_MAXANISOTROPY: - name.Format("%d",value); - break; - // Hex values - case D3DTSS_BORDERCOLOR: - name.Format("0x%x",value); - break; - - default: - name.Format("UNKNOWN (%d)",value); - break; - } -} - -const char* DX8Wrapper::Get_DX8_Texture_Op_Name(unsigned value) -{ - switch (value) { - case D3DTOP_DISABLE : return "D3DTOP_DISABLE"; - case D3DTOP_SELECTARG1 : return "D3DTOP_SELECTARG1"; - case D3DTOP_SELECTARG2 : return "D3DTOP_SELECTARG2"; - case D3DTOP_MODULATE : return "D3DTOP_MODULATE"; - case D3DTOP_MODULATE2X : return "D3DTOP_MODULATE2X"; - case D3DTOP_MODULATE4X : return "D3DTOP_MODULATE4X"; - case D3DTOP_ADD : return "D3DTOP_ADD"; - case D3DTOP_ADDSIGNED : return "D3DTOP_ADDSIGNED"; - case D3DTOP_ADDSIGNED2X : return "D3DTOP_ADDSIGNED2X"; - case D3DTOP_SUBTRACT : return "D3DTOP_SUBTRACT"; - case D3DTOP_ADDSMOOTH : return "D3DTOP_ADDSMOOTH"; - case D3DTOP_BLENDDIFFUSEALPHA : return "D3DTOP_BLENDDIFFUSEALPHA"; - case D3DTOP_BLENDTEXTUREALPHA : return "D3DTOP_BLENDTEXTUREALPHA"; - case D3DTOP_BLENDFACTORALPHA : return "D3DTOP_BLENDFACTORALPHA"; - case D3DTOP_BLENDTEXTUREALPHAPM : return "D3DTOP_BLENDTEXTUREALPHAPM"; - case D3DTOP_BLENDCURRENTALPHA : return "D3DTOP_BLENDCURRENTALPHA"; - case D3DTOP_PREMODULATE : return "D3DTOP_PREMODULATE"; - case D3DTOP_MODULATEALPHA_ADDCOLOR : return "D3DTOP_MODULATEALPHA_ADDCOLOR"; - case D3DTOP_MODULATECOLOR_ADDALPHA : return "D3DTOP_MODULATECOLOR_ADDALPHA"; - case D3DTOP_MODULATEINVALPHA_ADDCOLOR : return "D3DTOP_MODULATEINVALPHA_ADDCOLOR"; - case D3DTOP_MODULATEINVCOLOR_ADDALPHA : return "D3DTOP_MODULATEINVCOLOR_ADDALPHA"; - case D3DTOP_BUMPENVMAP : return "D3DTOP_BUMPENVMAP"; - case D3DTOP_BUMPENVMAPLUMINANCE : return "D3DTOP_BUMPENVMAPLUMINANCE"; - case D3DTOP_DOTPRODUCT3 : return "D3DTOP_DOTPRODUCT3"; - case D3DTOP_MULTIPLYADD : return "D3DTOP_MULTIPLYADD"; - case D3DTOP_LERP : return "D3DTOP_LERP"; - default : return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Texture_Arg_Name(unsigned value) -{ - switch (value) { - case D3DTA_CURRENT : return "D3DTA_CURRENT"; - case D3DTA_DIFFUSE : return "D3DTA_DIFFUSE"; - case D3DTA_SELECTMASK : return "D3DTA_SELECTMASK"; - case D3DTA_SPECULAR : return "D3DTA_SPECULAR"; - case D3DTA_TEMP : return "D3DTA_TEMP"; - case D3DTA_TEXTURE : return "D3DTA_TEXTURE"; - case D3DTA_TFACTOR : return "D3DTA_TFACTOR"; - case D3DTA_ALPHAREPLICATE : return "D3DTA_ALPHAREPLICATE"; - case D3DTA_COMPLEMENT : return "D3DTA_COMPLEMENT"; - default : return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Texture_Filter_Name(unsigned value) -{ - switch (value) { - case D3DTEXF_NONE : return "D3DTEXF_NONE"; - case D3DTEXF_POINT : return "D3DTEXF_POINT"; - case D3DTEXF_LINEAR : return "D3DTEXF_LINEAR"; - case D3DTEXF_ANISOTROPIC : return "D3DTEXF_ANISOTROPIC"; - case D3DTEXF_FLATCUBIC : return "D3DTEXF_FLATCUBIC"; - case D3DTEXF_GAUSSIANCUBIC : return "D3DTEXF_GAUSSIANCUBIC"; - default : return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Texture_Address_Name(unsigned value) -{ - switch (value) { - case D3DTADDRESS_WRAP : return "D3DTADDRESS_WRAP"; - case D3DTADDRESS_MIRROR : return "D3DTADDRESS_MIRROR"; - case D3DTADDRESS_CLAMP : return "D3DTADDRESS_CLAMP"; - case D3DTADDRESS_BORDER : return "D3DTADDRESS_BORDER"; - case D3DTADDRESS_MIRRORONCE: return "D3DTADDRESS_MIRRORONCE"; - default : return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Texture_Transform_Flag_Name(unsigned value) -{ - switch (value) { - case D3DTTFF_DISABLE : return "D3DTTFF_DISABLE"; - case D3DTTFF_COUNT1 : return "D3DTTFF_COUNT1"; - case D3DTTFF_COUNT2 : return "D3DTTFF_COUNT2"; - case D3DTTFF_COUNT3 : return "D3DTTFF_COUNT3"; - case D3DTTFF_COUNT4 : return "D3DTTFF_COUNT4"; - case D3DTTFF_PROJECTED : return "D3DTTFF_PROJECTED"; - default : return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_ZBuffer_Type_Name(unsigned value) -{ - switch (value) { - case D3DZB_FALSE : return "D3DZB_FALSE"; - case D3DZB_TRUE : return "D3DZB_TRUE"; - case D3DZB_USEW : return "D3DZB_USEW"; - default : return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Fill_Mode_Name(unsigned value) -{ - switch (value) { - case D3DFILL_POINT : return "D3DFILL_POINT"; - case D3DFILL_WIREFRAME : return "D3DFILL_WIREFRAME"; - case D3DFILL_SOLID : return "D3DFILL_SOLID"; - default : return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Shade_Mode_Name(unsigned value) -{ - switch (value) { - case D3DSHADE_FLAT : return "D3DSHADE_FLAT"; - case D3DSHADE_GOURAUD : return "D3DSHADE_GOURAUD"; - case D3DSHADE_PHONG : return "D3DSHADE_PHONG"; - default : return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Blend_Name(unsigned value) -{ - switch (value) { - case D3DBLEND_ZERO : return "D3DBLEND_ZERO"; - case D3DBLEND_ONE : return "D3DBLEND_ONE"; - case D3DBLEND_SRCCOLOR : return "D3DBLEND_SRCCOLOR"; - case D3DBLEND_INVSRCCOLOR : return "D3DBLEND_INVSRCCOLOR"; - case D3DBLEND_SRCALPHA : return "D3DBLEND_SRCALPHA"; - case D3DBLEND_INVSRCALPHA : return "D3DBLEND_INVSRCALPHA"; - case D3DBLEND_DESTALPHA : return "D3DBLEND_DESTALPHA"; - case D3DBLEND_INVDESTALPHA : return "D3DBLEND_INVDESTALPHA"; - case D3DBLEND_DESTCOLOR : return "D3DBLEND_DESTCOLOR"; - case D3DBLEND_INVDESTCOLOR : return "D3DBLEND_INVDESTCOLOR"; - case D3DBLEND_SRCALPHASAT : return "D3DBLEND_SRCALPHASAT"; - case D3DBLEND_BOTHSRCALPHA : return "D3DBLEND_BOTHSRCALPHA"; - case D3DBLEND_BOTHINVSRCALPHA : return "D3DBLEND_BOTHINVSRCALPHA"; - default : return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Cull_Mode_Name(unsigned value) -{ - switch (value) { - case D3DCULL_NONE : return "D3DCULL_NONE"; - case D3DCULL_CW : return "D3DCULL_CW"; - case D3DCULL_CCW : return "D3DCULL_CCW"; - default : return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Cmp_Func_Name(unsigned value) -{ - switch (value) { - case D3DCMP_NEVER : return "D3DCMP_NEVER"; - case D3DCMP_LESS : return "D3DCMP_LESS"; - case D3DCMP_EQUAL : return "D3DCMP_EQUAL"; - case D3DCMP_LESSEQUAL : return "D3DCMP_LESSEQUAL"; - case D3DCMP_GREATER : return "D3DCMP_GREATER"; - case D3DCMP_NOTEQUAL : return "D3DCMP_NOTEQUAL"; - case D3DCMP_GREATEREQUAL : return "D3DCMP_GREATEREQUAL"; - case D3DCMP_ALWAYS : return "D3DCMP_ALWAYS"; - default : return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Fog_Mode_Name(unsigned value) -{ - switch (value) { - case D3DFOG_NONE : return "D3DFOG_NONE"; - case D3DFOG_EXP : return "D3DFOG_EXP"; - case D3DFOG_EXP2 : return "D3DFOG_EXP2"; - case D3DFOG_LINEAR : return "D3DFOG_LINEAR"; - default : return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Stencil_Op_Name(unsigned value) -{ - switch (value) { - case D3DSTENCILOP_KEEP : return "D3DSTENCILOP_KEEP"; - case D3DSTENCILOP_ZERO : return "D3DSTENCILOP_ZERO"; - case D3DSTENCILOP_REPLACE : return "D3DSTENCILOP_REPLACE"; - case D3DSTENCILOP_INCRSAT : return "D3DSTENCILOP_INCRSAT"; - case D3DSTENCILOP_DECRSAT : return "D3DSTENCILOP_DECRSAT"; - case D3DSTENCILOP_INVERT : return "D3DSTENCILOP_INVERT"; - case D3DSTENCILOP_INCR : return "D3DSTENCILOP_INCR"; - case D3DSTENCILOP_DECR : return "D3DSTENCILOP_DECR"; - default : return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Material_Source_Name(unsigned value) -{ - switch (value) { - case D3DMCS_MATERIAL : return "D3DMCS_MATERIAL"; - case D3DMCS_COLOR1 : return "D3DMCS_COLOR1"; - case D3DMCS_COLOR2 : return "D3DMCS_COLOR2"; - default : return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Vertex_Blend_Flag_Name(unsigned value) -{ - switch (value) { - case D3DVBF_DISABLE : return "D3DVBF_DISABLE"; - case D3DVBF_1WEIGHTS : return "D3DVBF_1WEIGHTS"; - case D3DVBF_2WEIGHTS : return "D3DVBF_2WEIGHTS"; - case D3DVBF_3WEIGHTS : return "D3DVBF_3WEIGHTS"; - case D3DVBF_TWEENING : return "D3DVBF_TWEENING"; - case D3DVBF_0WEIGHTS : return "D3DVBF_0WEIGHTS"; - default : return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Patch_Edge_Style_Name(unsigned value) -{ - switch (value) { - case D3DPATCHEDGE_DISCRETE : return "D3DPATCHEDGE_DISCRETE"; - case D3DPATCHEDGE_CONTINUOUS:return "D3DPATCHEDGE_CONTINUOUS"; - default : return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Debug_Monitor_Token_Name(unsigned value) -{ - switch (value) { - case D3DDMT_ENABLE : return "D3DDMT_ENABLE"; - case D3DDMT_DISABLE : return "D3DDMT_DISABLE"; - default : return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Blend_Op_Name(unsigned value) -{ - switch (value) { - case D3DBLENDOP_ADD : return "D3DBLENDOP_ADD"; - case D3DBLENDOP_SUBTRACT : return "D3DBLENDOP_SUBTRACT"; - case D3DBLENDOP_REVSUBTRACT: return "D3DBLENDOP_REVSUBTRACT"; - case D3DBLENDOP_MIN : return "D3DBLENDOP_MIN"; - case D3DBLENDOP_MAX : return "D3DBLENDOP_MAX"; - default : return "UNKNOWN"; - } -} - - -//============================================================================ -// DX8Wrapper::getBackBufferFormat -//============================================================================ - -WW3DFormat DX8Wrapper::getBackBufferFormat( void ) -{ - return D3DFormat_To_WW3DFormat( _PresentParameters.BackBufferFormat ); -} diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h index e3eb074348d..18c1f2831c4 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h @@ -477,6 +477,17 @@ class DX8Wrapper */ static TextureClass* Create_Render_Target(int width, int height, WW3DFormat format = WW3D_FORMAT_UNKNOWN); + // 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_Render_Target(IDirect3DSurface8* render_target, bool use_default_depth_buffer = false); diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 398ef7a1410..83965a76b2e 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -271,1223 +271,3 @@ void MoveRectIntoOtherRect(const RECT& inner, const RECT& outer, int* x, int* y) #include "../../Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h" -//********************************************************************************************** -//! 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++; - - // 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 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)) - { - WWDEBUG_SAY(("DX8Wrapper - Render target with depth format is not supported")); - return; - } - - // 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) - { - poweroftwosize = height; - } - poweroftwosize = ::Find_POT (poweroftwosize); - - if (poweroftwosize>dx8caps.MaxTextureWidth) - { - poweroftwosize=dx8caps.MaxTextureWidth; - } - - if (poweroftwosize>dx8caps.MaxTextureHeight) - { - poweroftwosize=dx8caps.MaxTextureHeight; - } - - width = height = poweroftwosize; - - // Attempt to create the render target - 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); - } - - *target=tex; - - // attempt to create the depth stencil buffer - *depth_buffer=NEW_REF - ( - ZTextureClass, - ( - width, - height, - zformat, - MIP_LEVELS_1, - TextureClass::POOL_DEFAULT - ) - ); -} - -/*! - * Set render target - * KM Added optional custom z target - */ -void DX8Wrapper::Set_Render_Target_With_Z -( - TextureClass* texture, - ZTextureClass* ztexture -) -{ - 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 -DX8Wrapper::Set_Render_Target(IDirect3DSwapChain8 *swap_chain) -{ - DX8_THREAD_ASSERT(); - WWASSERT (swap_chain != NULL); - - // - // Get the back buffer for the swap chain - // - LPDIRECT3DSURFACE8 render_target = NULL; - swap_chain->GetBackBuffer (0, D3DBACKBUFFER_TYPE_MONO, &render_target); - - // - // Set this back buffer as the render targer - // - Set_Render_Target (render_target, true); - - // - // Release our hold on the back buffer - // - if (render_target != NULL) { - render_target->Release (); - render_target = NULL; - } - - IsRenderToTexture = false; - - return ; -} - -void -DX8Wrapper::Set_Render_Target(IDirect3DSurface8 *render_target, bool use_default_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; - WWASSERT (CurrentRenderTarget != NULL); - if (CurrentRenderTarget != NULL) - { - CurrentRenderTarget->AddRef (); - - // - // Switch render targets - // - 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; -// } - - 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 -} - - -IDirect3DSwapChain8 * -DX8Wrapper::Create_Additional_Swap_Chain (HWND render_window) -{ - DX8_Assert(); - - // - // Configure the presentation parameters for a windowed render target - // - D3DPRESENT_PARAMETERS params = { 0 }; - params.BackBufferFormat = _PresentParameters.BackBufferFormat; - params.BackBufferCount = 1; - params.MultiSampleType = D3DMULTISAMPLE_NONE; - params.SwapEffect = D3DSWAPEFFECT_COPY_VSYNC; - params.hDeviceWindow = render_window; - params.Windowed = TRUE; - params.EnableAutoDepthStencil = TRUE; - params.AutoDepthStencilFormat = _PresentParameters.AutoDepthStencilFormat; - params.Flags = 0; - params.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT; - params.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; - - // - // Create the swap chain - // - IDirect3DSwapChain8 *swap_chain = NULL; - DX8CALL(CreateAdditionalSwapChain(¶ms, &swap_chain)); - return swap_chain; -} - -void DX8Wrapper::Flush_DX8_Resource_Manager(unsigned int bytes) -{ - DX8_Assert(); - DX8CALL(ResourceManagerDiscardBytes(bytes)); -} - -unsigned int DX8Wrapper::Get_Free_Texture_RAM() -{ - DX8_Assert(); - number_of_DX8_calls++; - return DX8Wrapper::_Get_D3D_Device8()->GetAvailableTextureMem(); -} - -// Converts a linear gamma ramp to one that is controlled by: -// Gamma - controls the curvature of the middle of the curve -// Bright - controls the minimum value of the curve -// Contrast - controls the difference between the maximum and the minimum of the curve -void DX8Wrapper::Set_Gamma(float gamma,float bright,float contrast,bool calibrate,bool uselimit) -{ - gamma=Bound(gamma,0.6f,6.0f); - bright=Bound(bright,-0.5f,0.5f); - contrast=Bound(contrast,0.5f,2.0f); - float oo_gamma=1.0f/gamma; - - DX8_Assert(); - number_of_DX8_calls++; - - DWORD flag=(calibrate?D3DSGR_CALIBRATE:D3DSGR_NO_CALIBRATION); - - D3DGAMMARAMP ramp; - float limit; - - // IML: I'm not really sure what the intent of the 'limit' variable is. It does not produce useful results for my purposes. - if (uselimit) { - limit=(contrast-1)/2*contrast; - } else { - limit = 0.0f; - } - - // HY - arrived at this equation after much trial and error. - for (int i=0; i<256; i++) { - float in,out; - in=i/256.0f; - float x=in-limit; - x=Bound(x,0.0f,1.0f); - x=powf(x,oo_gamma); - out=contrast*x+bright; - out=Bound(out,0.0f,1.0f); - ramp.red[i]=(WORD) (out*65535); - ramp.green[i]=(WORD) (out*65535); - ramp.blue[i]=(WORD) (out*65535); - } - - if (Get_Current_Caps()->Support_Gamma()) { - DX8Wrapper::_Get_D3D_Device8()->SetGammaRamp(flag,&ramp); - } else { - HWND hwnd = GetDesktopWindow(); - HDC hdc = GetDC(hwnd); - if (hdc) - { - SetDeviceGammaRamp (hdc, &ramp); - ReleaseDC (hwnd, hdc); - } - } -} - -//********************************************************************************************** -//! Resets render device to default state -/*! -*/ -void DX8Wrapper::Apply_Default_State() -{ - SNAPSHOT_SAY(("DX8Wrapper::Apply_Default_State()")); - - // only set states used in game - Set_DX8_Render_State(D3DRS_ZENABLE, TRUE); -// Set_DX8_Render_State(D3DRS_FILLMODE, D3DFILL_SOLID); - Set_DX8_Render_State(D3DRS_SHADEMODE, D3DSHADE_GOURAUD); - //Set_DX8_Render_State(D3DRS_LINEPATTERN, 0); - Set_DX8_Render_State(D3DRS_ZWRITEENABLE, TRUE); - Set_DX8_Render_State(D3DRS_ALPHATESTENABLE, FALSE); - //Set_DX8_Render_State(D3DRS_LASTPIXEL, FALSE); - Set_DX8_Render_State(D3DRS_SRCBLEND, D3DBLEND_ONE); - Set_DX8_Render_State(D3DRS_DESTBLEND, D3DBLEND_ZERO); - Set_DX8_Render_State(D3DRS_CULLMODE, D3DCULL_CW); - Set_DX8_Render_State(D3DRS_ZFUNC, D3DCMP_LESSEQUAL); - Set_DX8_Render_State(D3DRS_ALPHAREF, 0); - Set_DX8_Render_State(D3DRS_ALPHAFUNC, D3DCMP_LESSEQUAL); - Set_DX8_Render_State(D3DRS_DITHERENABLE, FALSE); - Set_DX8_Render_State(D3DRS_ALPHABLENDENABLE, FALSE); - Set_DX8_Render_State(D3DRS_FOGENABLE, FALSE); - Set_DX8_Render_State(D3DRS_SPECULARENABLE, FALSE); -// Set_DX8_Render_State(D3DRS_ZVISIBLE, FALSE); -// Set_DX8_Render_State(D3DRS_FOGCOLOR, 0); -// Set_DX8_Render_State(D3DRS_FOGTABLEMODE, D3DFOG_NONE); -// Set_DX8_Render_State(D3DRS_FOGSTART, 0); - -// Set_DX8_Render_State(D3DRS_FOGEND, WWMath::Float_As_Int(1.0f)); -// Set_DX8_Render_State(D3DRS_FOGDENSITY, WWMath::Float_As_Int(1.0f)); - - //Set_DX8_Render_State(D3DRS_EDGEANTIALIAS, FALSE); - Set_DX8_Render_State(D3DRS_ZBIAS, 0); -// Set_DX8_Render_State(D3DRS_RANGEFOGENABLE, FALSE); - Set_DX8_Render_State(D3DRS_STENCILENABLE, FALSE); - Set_DX8_Render_State(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP); - Set_DX8_Render_State(D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP); - Set_DX8_Render_State(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP); - Set_DX8_Render_State(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); - Set_DX8_Render_State(D3DRS_STENCILREF, 0); - Set_DX8_Render_State(D3DRS_STENCILMASK, 0xffffffff); - Set_DX8_Render_State(D3DRS_STENCILWRITEMASK, 0xffffffff); - Set_DX8_Render_State(D3DRS_TEXTUREFACTOR, 0); -/* Set_DX8_Render_State(D3DRS_WRAP0, D3DWRAP_U| D3DWRAP_V); - Set_DX8_Render_State(D3DRS_WRAP1, D3DWRAP_U| D3DWRAP_V); - Set_DX8_Render_State(D3DRS_WRAP2, D3DWRAP_U| D3DWRAP_V); - Set_DX8_Render_State(D3DRS_WRAP3, D3DWRAP_U| D3DWRAP_V); - Set_DX8_Render_State(D3DRS_WRAP4, D3DWRAP_U| D3DWRAP_V); - Set_DX8_Render_State(D3DRS_WRAP5, D3DWRAP_U| D3DWRAP_V); - Set_DX8_Render_State(D3DRS_WRAP6, D3DWRAP_U| D3DWRAP_V); - Set_DX8_Render_State(D3DRS_WRAP7, D3DWRAP_U| D3DWRAP_V);*/ - Set_DX8_Render_State(D3DRS_CLIPPING, TRUE); - Set_DX8_Render_State(D3DRS_LIGHTING, FALSE); - //Set_DX8_Render_State(D3DRS_AMBIENT, 0); -// Set_DX8_Render_State(D3DRS_FOGVERTEXMODE, D3DFOG_NONE); - Set_DX8_Render_State(D3DRS_COLORVERTEX, TRUE); -/* Set_DX8_Render_State(D3DRS_LOCALVIEWER, TRUE); - Set_DX8_Render_State(D3DRS_NORMALIZENORMALS, FALSE); - Set_DX8_Render_State(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1); - Set_DX8_Render_State(D3DRS_SPECULARMATERIALSOURCE, D3DMCS_COLOR2); - Set_DX8_Render_State(D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_MATERIAL); - Set_DX8_Render_State(D3DRS_EMISSIVEMATERIALSOURCE, D3DMCS_MATERIAL); - Set_DX8_Render_State(D3DRS_VERTEXBLEND, D3DVBF_DISABLE);*/ - //Set_DX8_Render_State(D3DRS_CLIPPLANEENABLE, 0); - Set_DX8_Render_State(D3DRS_SOFTWAREVERTEXPROCESSING, FALSE); - //Set_DX8_Render_State(D3DRS_POINTSIZE, 0x3f800000); - //Set_DX8_Render_State(D3DRS_POINTSIZE_MIN, 0); - //Set_DX8_Render_State(D3DRS_POINTSPRITEENABLE, FALSE); - //Set_DX8_Render_State(D3DRS_POINTSCALEENABLE, FALSE); - //Set_DX8_Render_State(D3DRS_POINTSCALE_A, 0); - //Set_DX8_Render_State(D3DRS_POINTSCALE_B, 0); - //Set_DX8_Render_State(D3DRS_POINTSCALE_C, 0); - //Set_DX8_Render_State(D3DRS_MULTISAMPLEANTIALIAS, TRUE); - //Set_DX8_Render_State(D3DRS_MULTISAMPLEMASK, 0xffffffff); - //Set_DX8_Render_State(D3DRS_PATCHEDGESTYLE, D3DPATCHEDGE_DISCRETE); - //Set_DX8_Render_State(D3DRS_PATCHSEGMENTS, 0x3f800000); - //Set_DX8_Render_State(D3DRS_DEBUGMONITORTOKEN, D3DDMT_ENABLE); - //Set_DX8_Render_State(D3DRS_POINTSIZE_MAX, Float_At_Int(64.0f)); - //Set_DX8_Render_State(D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE); - Set_DX8_Render_State(D3DRS_COLORWRITEENABLE, 0x0000000f); - //Set_DX8_Render_State(D3DRS_TWEENFACTOR, 0); - Set_DX8_Render_State(D3DRS_BLENDOP, D3DBLENDOP_ADD); - //Set_DX8_Render_State(D3DRS_POSITIONORDER, D3DORDER_CUBIC); - //Set_DX8_Render_State(D3DRS_NORMALORDER, D3DORDER_LINEAR); - - // disable TSS stages - int i; - for (i=0; iGet_Max_Textures_Per_Pass(); i++) - { - Set_DX8_Texture_Stage_State(i, D3DTSS_COLOROP, D3DTOP_DISABLE); - Set_DX8_Texture_Stage_State(i, D3DTSS_COLORARG1, D3DTA_TEXTURE); - Set_DX8_Texture_Stage_State(i, D3DTSS_COLORARG2, D3DTA_DIFFUSE); - - Set_DX8_Texture_Stage_State(i, D3DTSS_ALPHAOP, D3DTOP_DISABLE); - Set_DX8_Texture_Stage_State(i, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); - Set_DX8_Texture_Stage_State(i, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); - - /*Set_DX8_Texture_Stage_State(i, D3DTSS_BUMPENVMAT00, 0); - Set_DX8_Texture_Stage_State(i, D3DTSS_BUMPENVMAT01, 0); - Set_DX8_Texture_Stage_State(i, D3DTSS_BUMPENVMAT10, 0); - Set_DX8_Texture_Stage_State(i, D3DTSS_BUMPENVMAT11, 0); - Set_DX8_Texture_Stage_State(i, D3DTSS_BUMPENVLSCALE, 0); - Set_DX8_Texture_Stage_State(i, D3DTSS_BUMPENVLOFFSET, 0);*/ - - Set_DX8_Texture_Stage_State(i, D3DTSS_TEXCOORDINDEX, i); - - - Set_DX8_Texture_Stage_State(i, D3DTSS_ADDRESSU, D3DTADDRESS_WRAP); - Set_DX8_Texture_Stage_State(i, D3DTSS_ADDRESSV, D3DTADDRESS_WRAP); - Set_DX8_Texture_Stage_State(i, D3DTSS_BORDERCOLOR, 0); -// Set_DX8_Texture_Stage_State(i, D3DTSS_MAGFILTER, D3DTEXF_LINEAR); -// Set_DX8_Texture_Stage_State(i, D3DTSS_MINFILTER, D3DTEXF_LINEAR); -// Set_DX8_Texture_Stage_State(i, D3DTSS_MIPFILTER, D3DTEXF_LINEAR); -// Set_DX8_Texture_Stage_State(i, D3DTSS_MIPMAPLODBIAS, 0); -// Set_DX8_Texture_Stage_State(i, D3DTSS_MAXMIPLEVEL, 0); -// Set_DX8_Texture_Stage_State(i, D3DTSS_MAXANISOTROPY, 1); - //Set_DX8_Texture_Stage_State(i, D3DTSS_ADDRESSW, D3DTADDRESS_WRAP); - //Set_DX8_Texture_Stage_State(i, D3DTSS_COLORARG0, D3DTA_CURRENT); - //Set_DX8_Texture_Stage_State(i, D3DTSS_ALPHAARG0, D3DTA_CURRENT); - //Set_DX8_Texture_Stage_State(i, D3DTSS_RESULTARG, D3DTA_CURRENT); - - Set_DX8_Texture_Stage_State(i, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE); - Set_Texture(i,NULL); - } - -// DX8Wrapper::Set_Material(NULL); - VertexMaterialClass::Apply_Null(); - - for (unsigned index=0;index<4;++index) { - SNAPSHOT_SAY(("Clearing light %d to NULL",index)); - Set_DX8_Light(index,NULL); - } - - // set up simple default TSS - Vector4 vconst[MAX_VERTEX_SHADER_CONSTANTS]; - memset(vconst,0,sizeof(Vector4)*MAX_VERTEX_SHADER_CONSTANTS); - Set_Vertex_Shader_Constant(0, vconst, MAX_VERTEX_SHADER_CONSTANTS); - - Vector4 pconst[MAX_PIXEL_SHADER_CONSTANTS]; - memset(pconst,0,sizeof(Vector4)*MAX_PIXEL_SHADER_CONSTANTS); - Set_Pixel_Shader_Constant(0, pconst, MAX_PIXEL_SHADER_CONSTANTS); - - Set_Vertex_Shader(DX8_FVF_XYZNDUV2); - Set_Pixel_Shader(0); - - ShaderClass::Invalidate(); -} - -const char* DX8Wrapper::Get_DX8_Render_State_Name(D3DRENDERSTATETYPE state) -{ - switch (state) { - case D3DRS_ZENABLE : return "D3DRS_ZENABLE"; - case D3DRS_FILLMODE : return "D3DRS_FILLMODE"; - case D3DRS_SHADEMODE : return "D3DRS_SHADEMODE"; - case D3DRS_LINEPATTERN : return "D3DRS_LINEPATTERN"; - case D3DRS_ZWRITEENABLE : return "D3DRS_ZWRITEENABLE"; - case D3DRS_ALPHATESTENABLE : return "D3DRS_ALPHATESTENABLE"; - case D3DRS_LASTPIXEL : return "D3DRS_LASTPIXEL"; - case D3DRS_SRCBLEND : return "D3DRS_SRCBLEND"; - case D3DRS_DESTBLEND : return "D3DRS_DESTBLEND"; - case D3DRS_CULLMODE : return "D3DRS_CULLMODE"; - case D3DRS_ZFUNC : return "D3DRS_ZFUNC"; - case D3DRS_ALPHAREF : return "D3DRS_ALPHAREF"; - case D3DRS_ALPHAFUNC : return "D3DRS_ALPHAFUNC"; - case D3DRS_DITHERENABLE : return "D3DRS_DITHERENABLE"; - case D3DRS_ALPHABLENDENABLE : return "D3DRS_ALPHABLENDENABLE"; - case D3DRS_FOGENABLE : return "D3DRS_FOGENABLE"; - case D3DRS_SPECULARENABLE : return "D3DRS_SPECULARENABLE"; - case D3DRS_ZVISIBLE : return "D3DRS_ZVISIBLE"; - case D3DRS_FOGCOLOR : return "D3DRS_FOGCOLOR"; - case D3DRS_FOGTABLEMODE : return "D3DRS_FOGTABLEMODE"; - case D3DRS_FOGSTART : return "D3DRS_FOGSTART"; - case D3DRS_FOGEND : return "D3DRS_FOGEND"; - case D3DRS_FOGDENSITY : return "D3DRS_FOGDENSITY"; - case D3DRS_EDGEANTIALIAS : return "D3DRS_EDGEANTIALIAS"; - case D3DRS_ZBIAS : return "D3DRS_ZBIAS"; - case D3DRS_RANGEFOGENABLE : return "D3DRS_RANGEFOGENABLE"; - case D3DRS_STENCILENABLE : return "D3DRS_STENCILENABLE"; - case D3DRS_STENCILFAIL : return "D3DRS_STENCILFAIL"; - case D3DRS_STENCILZFAIL : return "D3DRS_STENCILZFAIL"; - case D3DRS_STENCILPASS : return "D3DRS_STENCILPASS"; - case D3DRS_STENCILFUNC : return "D3DRS_STENCILFUNC"; - case D3DRS_STENCILREF : return "D3DRS_STENCILREF"; - case D3DRS_STENCILMASK : return "D3DRS_STENCILMASK"; - case D3DRS_STENCILWRITEMASK : return "D3DRS_STENCILWRITEMASK"; - case D3DRS_TEXTUREFACTOR : return "D3DRS_TEXTUREFACTOR"; - case D3DRS_WRAP0 : return "D3DRS_WRAP0"; - case D3DRS_WRAP1 : return "D3DRS_WRAP1"; - case D3DRS_WRAP2 : return "D3DRS_WRAP2"; - case D3DRS_WRAP3 : return "D3DRS_WRAP3"; - case D3DRS_WRAP4 : return "D3DRS_WRAP4"; - case D3DRS_WRAP5 : return "D3DRS_WRAP5"; - case D3DRS_WRAP6 : return "D3DRS_WRAP6"; - case D3DRS_WRAP7 : return "D3DRS_WRAP7"; - case D3DRS_CLIPPING : return "D3DRS_CLIPPING"; - case D3DRS_LIGHTING : return "D3DRS_LIGHTING"; - case D3DRS_AMBIENT : return "D3DRS_AMBIENT"; - case D3DRS_FOGVERTEXMODE : return "D3DRS_FOGVERTEXMODE"; - case D3DRS_COLORVERTEX : return "D3DRS_COLORVERTEX"; - case D3DRS_LOCALVIEWER : return "D3DRS_LOCALVIEWER"; - case D3DRS_NORMALIZENORMALS : return "D3DRS_NORMALIZENORMALS"; - case D3DRS_DIFFUSEMATERIALSOURCE : return "D3DRS_DIFFUSEMATERIALSOURCE"; - case D3DRS_SPECULARMATERIALSOURCE : return "D3DRS_SPECULARMATERIALSOURCE"; - case D3DRS_AMBIENTMATERIALSOURCE : return "D3DRS_AMBIENTMATERIALSOURCE"; - case D3DRS_EMISSIVEMATERIALSOURCE : return "D3DRS_EMISSIVEMATERIALSOURCE"; - case D3DRS_VERTEXBLEND : return "D3DRS_VERTEXBLEND"; - case D3DRS_CLIPPLANEENABLE : return "D3DRS_CLIPPLANEENABLE"; - case D3DRS_SOFTWAREVERTEXPROCESSING : return "D3DRS_SOFTWAREVERTEXPROCESSING"; - case D3DRS_POINTSIZE : return "D3DRS_POINTSIZE"; - case D3DRS_POINTSIZE_MIN : return "D3DRS_POINTSIZE_MIN"; - case D3DRS_POINTSPRITEENABLE : return "D3DRS_POINTSPRITEENABLE"; - case D3DRS_POINTSCALEENABLE : return "D3DRS_POINTSCALEENABLE"; - case D3DRS_POINTSCALE_A : return "D3DRS_POINTSCALE_A"; - case D3DRS_POINTSCALE_B : return "D3DRS_POINTSCALE_B"; - case D3DRS_POINTSCALE_C : return "D3DRS_POINTSCALE_C"; - case D3DRS_MULTISAMPLEANTIALIAS : return "D3DRS_MULTISAMPLEANTIALIAS"; - case D3DRS_MULTISAMPLEMASK : return "D3DRS_MULTISAMPLEMASK"; - case D3DRS_PATCHEDGESTYLE : return "D3DRS_PATCHEDGESTYLE"; - case D3DRS_PATCHSEGMENTS : return "D3DRS_PATCHSEGMENTS"; - case D3DRS_DEBUGMONITORTOKEN : return "D3DRS_DEBUGMONITORTOKEN"; - case D3DRS_POINTSIZE_MAX : return "D3DRS_POINTSIZE_MAX"; - case D3DRS_INDEXEDVERTEXBLENDENABLE : return "D3DRS_INDEXEDVERTEXBLENDENABLE"; - case D3DRS_COLORWRITEENABLE : return "D3DRS_COLORWRITEENABLE"; - case D3DRS_TWEENFACTOR : return "D3DRS_TWEENFACTOR"; - case D3DRS_BLENDOP : return "D3DRS_BLENDOP"; -// case D3DRS_POSITIONORDER : return "D3DRS_POSITIONORDER"; -// case D3DRS_NORMALORDER : return "D3DRS_NORMALORDER"; - default : return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Texture_Stage_State_Name(D3DTEXTURESTAGESTATETYPE state) -{ - switch (state) { - case D3DTSS_COLOROP : return "D3DTSS_COLOROP"; - case D3DTSS_COLORARG1 : return "D3DTSS_COLORARG1"; - case D3DTSS_COLORARG2 : return "D3DTSS_COLORARG2"; - case D3DTSS_ALPHAOP : return "D3DTSS_ALPHAOP"; - case D3DTSS_ALPHAARG1 : return "D3DTSS_ALPHAARG1"; - case D3DTSS_ALPHAARG2 : return "D3DTSS_ALPHAARG2"; - case D3DTSS_BUMPENVMAT00 : return "D3DTSS_BUMPENVMAT00"; - case D3DTSS_BUMPENVMAT01 : return "D3DTSS_BUMPENVMAT01"; - case D3DTSS_BUMPENVMAT10 : return "D3DTSS_BUMPENVMAT10"; - case D3DTSS_BUMPENVMAT11 : return "D3DTSS_BUMPENVMAT11"; - case D3DTSS_TEXCOORDINDEX : return "D3DTSS_TEXCOORDINDEX"; - case D3DTSS_ADDRESSU : return "D3DTSS_ADDRESSU"; - case D3DTSS_ADDRESSV : return "D3DTSS_ADDRESSV"; - case D3DTSS_BORDERCOLOR : return "D3DTSS_BORDERCOLOR"; - case D3DTSS_MAGFILTER : return "D3DTSS_MAGFILTER"; - case D3DTSS_MINFILTER : return "D3DTSS_MINFILTER"; - case D3DTSS_MIPFILTER : return "D3DTSS_MIPFILTER"; - case D3DTSS_MIPMAPLODBIAS : return "D3DTSS_MIPMAPLODBIAS"; - case D3DTSS_MAXMIPLEVEL : return "D3DTSS_MAXMIPLEVEL"; - case D3DTSS_MAXANISOTROPY : return "D3DTSS_MAXANISOTROPY"; - case D3DTSS_BUMPENVLSCALE : return "D3DTSS_BUMPENVLSCALE"; - case D3DTSS_BUMPENVLOFFSET : return "D3DTSS_BUMPENVLOFFSET"; - case D3DTSS_TEXTURETRANSFORMFLAGS : return "D3DTSS_TEXTURETRANSFORMFLAGS"; - case D3DTSS_ADDRESSW : return "D3DTSS_ADDRESSW"; - case D3DTSS_COLORARG0 : return "D3DTSS_COLORARG0"; - case D3DTSS_ALPHAARG0 : return "D3DTSS_ALPHAARG0"; - case D3DTSS_RESULTARG : return "D3DTSS_RESULTARG"; - default : return "UNKNOWN"; - } -} - -void DX8Wrapper::Get_DX8_Render_State_Value_Name(StringClass& name, D3DRENDERSTATETYPE state, unsigned value) -{ - switch (state) { - case D3DRS_ZENABLE: - name=Get_DX8_ZBuffer_Type_Name(value); - break; - - case D3DRS_FILLMODE: - name=Get_DX8_Fill_Mode_Name(value); - break; - - case D3DRS_SHADEMODE: - name=Get_DX8_Shade_Mode_Name(value); - break; - - case D3DRS_LINEPATTERN: - case D3DRS_FOGCOLOR: - case D3DRS_ALPHAREF: - case D3DRS_STENCILMASK: - case D3DRS_STENCILWRITEMASK: - case D3DRS_TEXTUREFACTOR: - case D3DRS_AMBIENT: - case D3DRS_CLIPPLANEENABLE: - case D3DRS_MULTISAMPLEMASK: - name.Format("0x%x",value); - break; - - case D3DRS_ZWRITEENABLE: - case D3DRS_ALPHATESTENABLE: - case D3DRS_LASTPIXEL: - case D3DRS_DITHERENABLE: - case D3DRS_ALPHABLENDENABLE: - case D3DRS_FOGENABLE: - case D3DRS_SPECULARENABLE: - case D3DRS_STENCILENABLE: - case D3DRS_RANGEFOGENABLE: - case D3DRS_EDGEANTIALIAS: - case D3DRS_CLIPPING: - case D3DRS_LIGHTING: - case D3DRS_COLORVERTEX: - case D3DRS_LOCALVIEWER: - case D3DRS_NORMALIZENORMALS: - case D3DRS_SOFTWAREVERTEXPROCESSING: - case D3DRS_POINTSPRITEENABLE: - case D3DRS_POINTSCALEENABLE: - case D3DRS_MULTISAMPLEANTIALIAS: - case D3DRS_INDEXEDVERTEXBLENDENABLE: - name=value ? "TRUE" : "FALSE"; - break; - - case D3DRS_SRCBLEND: - case D3DRS_DESTBLEND: - name=Get_DX8_Blend_Name(value); - break; - - case D3DRS_CULLMODE: - name=Get_DX8_Cull_Mode_Name(value); - break; - - case D3DRS_ZFUNC: - case D3DRS_ALPHAFUNC: - case D3DRS_STENCILFUNC: - name=Get_DX8_Cmp_Func_Name(value); - break; - - case D3DRS_ZVISIBLE: - name="NOTSUPPORTED"; - break; - - case D3DRS_FOGTABLEMODE: - case D3DRS_FOGVERTEXMODE: - name=Get_DX8_Fog_Mode_Name(value); - break; - - case D3DRS_FOGSTART: - case D3DRS_FOGEND: - case D3DRS_FOGDENSITY: - case D3DRS_POINTSIZE: - case D3DRS_POINTSIZE_MIN: - case D3DRS_POINTSCALE_A: - case D3DRS_POINTSCALE_B: - case D3DRS_POINTSCALE_C: - case D3DRS_PATCHSEGMENTS: - case D3DRS_POINTSIZE_MAX: - case D3DRS_TWEENFACTOR: - name.Format("%f",*(float*)&value); - break; - - case D3DRS_ZBIAS: - case D3DRS_STENCILREF: - name.Format("%d",value); - break; - - case D3DRS_STENCILFAIL: - case D3DRS_STENCILZFAIL: - case D3DRS_STENCILPASS: - name=Get_DX8_Stencil_Op_Name(value); - break; - - case D3DRS_WRAP0: - case D3DRS_WRAP1: - case D3DRS_WRAP2: - case D3DRS_WRAP3: - case D3DRS_WRAP4: - case D3DRS_WRAP5: - case D3DRS_WRAP6: - case D3DRS_WRAP7: - name="0"; - if (value&D3DWRAP_U) name+="|D3DWRAP_U"; - if (value&D3DWRAP_V) name+="|D3DWRAP_V"; - if (value&D3DWRAP_W) name+="|D3DWRAP_W"; - break; - - case D3DRS_DIFFUSEMATERIALSOURCE: - case D3DRS_SPECULARMATERIALSOURCE: - case D3DRS_AMBIENTMATERIALSOURCE: - case D3DRS_EMISSIVEMATERIALSOURCE: - name=Get_DX8_Material_Source_Name(value); - break; - - case D3DRS_VERTEXBLEND: - name=Get_DX8_Vertex_Blend_Flag_Name(value); - break; - - case D3DRS_PATCHEDGESTYLE: - name=Get_DX8_Patch_Edge_Style_Name(value); - break; - - case D3DRS_DEBUGMONITORTOKEN: - name=Get_DX8_Debug_Monitor_Token_Name(value); - break; - - case D3DRS_COLORWRITEENABLE: - name="0"; - if (value&D3DCOLORWRITEENABLE_RED) name+="|D3DCOLORWRITEENABLE_RED"; - if (value&D3DCOLORWRITEENABLE_GREEN) name+="|D3DCOLORWRITEENABLE_GREEN"; - if (value&D3DCOLORWRITEENABLE_BLUE) name+="|D3DCOLORWRITEENABLE_BLUE"; - if (value&D3DCOLORWRITEENABLE_ALPHA) name+="|D3DCOLORWRITEENABLE_ALPHA"; - break; - case D3DRS_BLENDOP: - name=Get_DX8_Blend_Op_Name(value); - break; - default: - name.Format("UNKNOWN (%d)",value); - break; - } -} - -void DX8Wrapper::Get_DX8_Texture_Stage_State_Value_Name(StringClass& name, D3DTEXTURESTAGESTATETYPE state, unsigned value) -{ - switch (state) { - case D3DTSS_COLOROP: - case D3DTSS_ALPHAOP: - name=Get_DX8_Texture_Op_Name(value); - break; - - case D3DTSS_COLORARG0: - case D3DTSS_COLORARG1: - case D3DTSS_COLORARG2: - case D3DTSS_ALPHAARG0: - case D3DTSS_ALPHAARG1: - case D3DTSS_ALPHAARG2: - case D3DTSS_RESULTARG: - name=Get_DX8_Texture_Arg_Name(value); - break; - - case D3DTSS_ADDRESSU: - case D3DTSS_ADDRESSV: - case D3DTSS_ADDRESSW: - name=Get_DX8_Texture_Address_Name(value); - break; - - case D3DTSS_MAGFILTER: - case D3DTSS_MINFILTER: - case D3DTSS_MIPFILTER: - name=Get_DX8_Texture_Filter_Name(value); - break; - - case D3DTSS_TEXTURETRANSFORMFLAGS: - name=Get_DX8_Texture_Transform_Flag_Name(value); - break; - - // Floating point values - case D3DTSS_MIPMAPLODBIAS: - case D3DTSS_BUMPENVMAT00: - case D3DTSS_BUMPENVMAT01: - case D3DTSS_BUMPENVMAT10: - case D3DTSS_BUMPENVMAT11: - case D3DTSS_BUMPENVLSCALE: - case D3DTSS_BUMPENVLOFFSET: - name.Format("%f",*(float*)&value); - break; - - case D3DTSS_TEXCOORDINDEX: - if ((value&0xffff0000)==D3DTSS_TCI_CAMERASPACENORMAL) { - name.Format("D3DTSS_TCI_CAMERASPACENORMAL|%d",value&0xffff); - } - else if ((value&0xffff0000)==D3DTSS_TCI_CAMERASPACEPOSITION) { - name.Format("D3DTSS_TCI_CAMERASPACEPOSITION|%d",value&0xffff); - } - else if ((value&0xffff0000)==D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR) { - name.Format("D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR|%d",value&0xffff); - } - else { - name.Format("%d",value); - } - break; - - // Integer value - case D3DTSS_MAXMIPLEVEL: - case D3DTSS_MAXANISOTROPY: - name.Format("%d",value); - break; - // Hex values - case D3DTSS_BORDERCOLOR: - name.Format("0x%x",value); - break; - - default: - name.Format("UNKNOWN (%d)",value); - break; - } -} - -const char* DX8Wrapper::Get_DX8_Texture_Op_Name(unsigned value) -{ - switch (value) { - case D3DTOP_DISABLE : return "D3DTOP_DISABLE"; - case D3DTOP_SELECTARG1 : return "D3DTOP_SELECTARG1"; - case D3DTOP_SELECTARG2 : return "D3DTOP_SELECTARG2"; - case D3DTOP_MODULATE : return "D3DTOP_MODULATE"; - case D3DTOP_MODULATE2X : return "D3DTOP_MODULATE2X"; - case D3DTOP_MODULATE4X : return "D3DTOP_MODULATE4X"; - case D3DTOP_ADD : return "D3DTOP_ADD"; - case D3DTOP_ADDSIGNED : return "D3DTOP_ADDSIGNED"; - case D3DTOP_ADDSIGNED2X : return "D3DTOP_ADDSIGNED2X"; - case D3DTOP_SUBTRACT : return "D3DTOP_SUBTRACT"; - case D3DTOP_ADDSMOOTH : return "D3DTOP_ADDSMOOTH"; - case D3DTOP_BLENDDIFFUSEALPHA : return "D3DTOP_BLENDDIFFUSEALPHA"; - case D3DTOP_BLENDTEXTUREALPHA : return "D3DTOP_BLENDTEXTUREALPHA"; - case D3DTOP_BLENDFACTORALPHA : return "D3DTOP_BLENDFACTORALPHA"; - case D3DTOP_BLENDTEXTUREALPHAPM : return "D3DTOP_BLENDTEXTUREALPHAPM"; - case D3DTOP_BLENDCURRENTALPHA : return "D3DTOP_BLENDCURRENTALPHA"; - case D3DTOP_PREMODULATE : return "D3DTOP_PREMODULATE"; - case D3DTOP_MODULATEALPHA_ADDCOLOR : return "D3DTOP_MODULATEALPHA_ADDCOLOR"; - case D3DTOP_MODULATECOLOR_ADDALPHA : return "D3DTOP_MODULATECOLOR_ADDALPHA"; - case D3DTOP_MODULATEINVALPHA_ADDCOLOR : return "D3DTOP_MODULATEINVALPHA_ADDCOLOR"; - case D3DTOP_MODULATEINVCOLOR_ADDALPHA : return "D3DTOP_MODULATEINVCOLOR_ADDALPHA"; - case D3DTOP_BUMPENVMAP : return "D3DTOP_BUMPENVMAP"; - case D3DTOP_BUMPENVMAPLUMINANCE : return "D3DTOP_BUMPENVMAPLUMINANCE"; - case D3DTOP_DOTPRODUCT3 : return "D3DTOP_DOTPRODUCT3"; - case D3DTOP_MULTIPLYADD : return "D3DTOP_MULTIPLYADD"; - case D3DTOP_LERP : return "D3DTOP_LERP"; - default : return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Texture_Arg_Name(unsigned value) -{ - switch (value) { - case D3DTA_CURRENT : return "D3DTA_CURRENT"; - case D3DTA_DIFFUSE : return "D3DTA_DIFFUSE"; - case D3DTA_SELECTMASK : return "D3DTA_SELECTMASK"; - case D3DTA_SPECULAR : return "D3DTA_SPECULAR"; - case D3DTA_TEMP : return "D3DTA_TEMP"; - case D3DTA_TEXTURE : return "D3DTA_TEXTURE"; - case D3DTA_TFACTOR : return "D3DTA_TFACTOR"; - case D3DTA_ALPHAREPLICATE : return "D3DTA_ALPHAREPLICATE"; - case D3DTA_COMPLEMENT : return "D3DTA_COMPLEMENT"; - default : return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Texture_Filter_Name(unsigned value) -{ - switch (value) { - case D3DTEXF_NONE : return "D3DTEXF_NONE"; - case D3DTEXF_POINT : return "D3DTEXF_POINT"; - case D3DTEXF_LINEAR : return "D3DTEXF_LINEAR"; - case D3DTEXF_ANISOTROPIC : return "D3DTEXF_ANISOTROPIC"; - case D3DTEXF_FLATCUBIC : return "D3DTEXF_FLATCUBIC"; - case D3DTEXF_GAUSSIANCUBIC : return "D3DTEXF_GAUSSIANCUBIC"; - default : return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Texture_Address_Name(unsigned value) -{ - switch (value) { - case D3DTADDRESS_WRAP : return "D3DTADDRESS_WRAP"; - case D3DTADDRESS_MIRROR : return "D3DTADDRESS_MIRROR"; - case D3DTADDRESS_CLAMP : return "D3DTADDRESS_CLAMP"; - case D3DTADDRESS_BORDER : return "D3DTADDRESS_BORDER"; - case D3DTADDRESS_MIRRORONCE: return "D3DTADDRESS_MIRRORONCE"; - default : return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Texture_Transform_Flag_Name(unsigned value) -{ - switch (value) { - case D3DTTFF_DISABLE : return "D3DTTFF_DISABLE"; - case D3DTTFF_COUNT1 : return "D3DTTFF_COUNT1"; - case D3DTTFF_COUNT2 : return "D3DTTFF_COUNT2"; - case D3DTTFF_COUNT3 : return "D3DTTFF_COUNT3"; - case D3DTTFF_COUNT4 : return "D3DTTFF_COUNT4"; - case D3DTTFF_PROJECTED : return "D3DTTFF_PROJECTED"; - default : return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_ZBuffer_Type_Name(unsigned value) -{ - switch (value) { - case D3DZB_FALSE : return "D3DZB_FALSE"; - case D3DZB_TRUE : return "D3DZB_TRUE"; - case D3DZB_USEW : return "D3DZB_USEW"; - default : return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Fill_Mode_Name(unsigned value) -{ - switch (value) { - case D3DFILL_POINT : return "D3DFILL_POINT"; - case D3DFILL_WIREFRAME : return "D3DFILL_WIREFRAME"; - case D3DFILL_SOLID : return "D3DFILL_SOLID"; - default : return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Shade_Mode_Name(unsigned value) -{ - switch (value) { - case D3DSHADE_FLAT : return "D3DSHADE_FLAT"; - case D3DSHADE_GOURAUD : return "D3DSHADE_GOURAUD"; - case D3DSHADE_PHONG : return "D3DSHADE_PHONG"; - default : return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Blend_Name(unsigned value) -{ - switch (value) { - case D3DBLEND_ZERO : return "D3DBLEND_ZERO"; - case D3DBLEND_ONE : return "D3DBLEND_ONE"; - case D3DBLEND_SRCCOLOR : return "D3DBLEND_SRCCOLOR"; - case D3DBLEND_INVSRCCOLOR : return "D3DBLEND_INVSRCCOLOR"; - case D3DBLEND_SRCALPHA : return "D3DBLEND_SRCALPHA"; - case D3DBLEND_INVSRCALPHA : return "D3DBLEND_INVSRCALPHA"; - case D3DBLEND_DESTALPHA : return "D3DBLEND_DESTALPHA"; - case D3DBLEND_INVDESTALPHA : return "D3DBLEND_INVDESTALPHA"; - case D3DBLEND_DESTCOLOR : return "D3DBLEND_DESTCOLOR"; - case D3DBLEND_INVDESTCOLOR : return "D3DBLEND_INVDESTCOLOR"; - case D3DBLEND_SRCALPHASAT : return "D3DBLEND_SRCALPHASAT"; - case D3DBLEND_BOTHSRCALPHA : return "D3DBLEND_BOTHSRCALPHA"; - case D3DBLEND_BOTHINVSRCALPHA : return "D3DBLEND_BOTHINVSRCALPHA"; - default : return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Cull_Mode_Name(unsigned value) -{ - switch (value) { - case D3DCULL_NONE : return "D3DCULL_NONE"; - case D3DCULL_CW : return "D3DCULL_CW"; - case D3DCULL_CCW : return "D3DCULL_CCW"; - default : return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Cmp_Func_Name(unsigned value) -{ - switch (value) { - case D3DCMP_NEVER : return "D3DCMP_NEVER"; - case D3DCMP_LESS : return "D3DCMP_LESS"; - case D3DCMP_EQUAL : return "D3DCMP_EQUAL"; - case D3DCMP_LESSEQUAL : return "D3DCMP_LESSEQUAL"; - case D3DCMP_GREATER : return "D3DCMP_GREATER"; - case D3DCMP_NOTEQUAL : return "D3DCMP_NOTEQUAL"; - case D3DCMP_GREATEREQUAL : return "D3DCMP_GREATEREQUAL"; - case D3DCMP_ALWAYS : return "D3DCMP_ALWAYS"; - default : return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Fog_Mode_Name(unsigned value) -{ - switch (value) { - case D3DFOG_NONE : return "D3DFOG_NONE"; - case D3DFOG_EXP : return "D3DFOG_EXP"; - case D3DFOG_EXP2 : return "D3DFOG_EXP2"; - case D3DFOG_LINEAR : return "D3DFOG_LINEAR"; - default : return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Stencil_Op_Name(unsigned value) -{ - switch (value) { - case D3DSTENCILOP_KEEP : return "D3DSTENCILOP_KEEP"; - case D3DSTENCILOP_ZERO : return "D3DSTENCILOP_ZERO"; - case D3DSTENCILOP_REPLACE : return "D3DSTENCILOP_REPLACE"; - case D3DSTENCILOP_INCRSAT : return "D3DSTENCILOP_INCRSAT"; - case D3DSTENCILOP_DECRSAT : return "D3DSTENCILOP_DECRSAT"; - case D3DSTENCILOP_INVERT : return "D3DSTENCILOP_INVERT"; - case D3DSTENCILOP_INCR : return "D3DSTENCILOP_INCR"; - case D3DSTENCILOP_DECR : return "D3DSTENCILOP_DECR"; - default : return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Material_Source_Name(unsigned value) -{ - switch (value) { - case D3DMCS_MATERIAL : return "D3DMCS_MATERIAL"; - case D3DMCS_COLOR1 : return "D3DMCS_COLOR1"; - case D3DMCS_COLOR2 : return "D3DMCS_COLOR2"; - default : return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Vertex_Blend_Flag_Name(unsigned value) -{ - switch (value) { - case D3DVBF_DISABLE : return "D3DVBF_DISABLE"; - case D3DVBF_1WEIGHTS : return "D3DVBF_1WEIGHTS"; - case D3DVBF_2WEIGHTS : return "D3DVBF_2WEIGHTS"; - case D3DVBF_3WEIGHTS : return "D3DVBF_3WEIGHTS"; - case D3DVBF_TWEENING : return "D3DVBF_TWEENING"; - case D3DVBF_0WEIGHTS : return "D3DVBF_0WEIGHTS"; - default : return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Patch_Edge_Style_Name(unsigned value) -{ - switch (value) { - case D3DPATCHEDGE_DISCRETE : return "D3DPATCHEDGE_DISCRETE"; - case D3DPATCHEDGE_CONTINUOUS:return "D3DPATCHEDGE_CONTINUOUS"; - default : return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Debug_Monitor_Token_Name(unsigned value) -{ - switch (value) { - case D3DDMT_ENABLE : return "D3DDMT_ENABLE"; - case D3DDMT_DISABLE : return "D3DDMT_DISABLE"; - default : return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Blend_Op_Name(unsigned value) -{ - switch (value) { - case D3DBLENDOP_ADD : return "D3DBLENDOP_ADD"; - case D3DBLENDOP_SUBTRACT : return "D3DBLENDOP_SUBTRACT"; - case D3DBLENDOP_REVSUBTRACT: return "D3DBLENDOP_REVSUBTRACT"; - case D3DBLENDOP_MIN : return "D3DBLENDOP_MIN"; - case D3DBLENDOP_MAX : return "D3DBLENDOP_MAX"; - default : return "UNKNOWN"; - } -} - - -//============================================================================ -// DX8Wrapper::getBackBufferFormat -//============================================================================ - -WW3DFormat DX8Wrapper::getBackBufferFormat( void ) -{ - return D3DFormat_To_WW3DFormat( _PresentParameters.BackBufferFormat ); -} From b738e026a0d597995db21bf2b8150ba4094b3163 Mon Sep 17 00:00:00 2001 From: ryan-de-boer Date: Fri, 1 Aug 2025 17:45:59 +0800 Subject: [PATCH 15/20] Unify to beginning of dx8wrapper.cpp --- .../Common/Graphics/DX8/dx8wrapper_common.h | 271 +++++++++++++++++ .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 265 ----------------- .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 272 ------------------ 3 files changed, 271 insertions(+), 537 deletions(-) diff --git a/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h b/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h index 6e384a9431d..7d258b1bfbe 100644 --- a/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h +++ b/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h @@ -1,3 +1,274 @@ +/* +** Command & Conquer Generals Zero Hour(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/dx8wrapper.cpp $* + * * + * Original Author:: Jani Penttinen * + * * + * $Author:: Kenny Mitchell * + * * + * $Modtime:: 08/05/02 1:27p $* + * * + * $Revision:: 170 $* + * * + * 06/26/02 KM Matrix name change to avoid MAX conflicts * + * 06/27/02 KM Render to shadow buffer texture support * + * 06/27/02 KM Shader system updates * + * 08/05/02 KM Texture class redesign + *---------------------------------------------------------------------------------------------* + * Functions: * + * DX8Wrapper::_Update_Texture -- Copies a texture from system memory to video memory * + * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + //#define CREATE_DX8_MULTI_THREADED + //#define CREATE_DX8_FPU_PRESERVE +#define WW3D_DEVTYPE D3DDEVTYPE_HAL + +#if defined(_MSC_VER) && _MSC_VER < 1300 +#undef WINVER +#define WINVER 0x0500 // Required to access GetMonitorInfo in VC6. +#endif + +#include "dx8wrapper.h" +#include "dx8webbrowser.h" +#include "dx8fvf.h" +#include "dx8vertexbuffer.h" +#include "dx8indexbuffer.h" +#include "dx8renderer.h" +#include "ww3d.h" +#include "camera.h" +#include "wwstring.h" +#include "matrix4.h" +#include "vertmaterial.h" +#include "rddesc.h" +#include "lightenvironment.h" +#include "statistics.h" +#include "registry.h" +#include "boxrobj.h" +#include "pointgr.h" +#include "render2d.h" +#include "sortingrenderer.h" +#include "shattersystem.h" +#include "light.h" +#include "assetmgr.h" +#include "textureloader.h" +#include "missingtexture.h" +#include "thread.h" +#include +#include +#include "pot.h" +#include "wwprofile.h" +#include "ffactory.h" +#include "dx8caps.h" +#include "formconv.h" +#include "dx8texman.h" +#include "bound.h" +#include "dx8webbrowser.h" + +#include "shdlib.h" + +const int DEFAULT_RESOLUTION_WIDTH = 640; +const int DEFAULT_RESOLUTION_HEIGHT = 480; +const int DEFAULT_BIT_DEPTH = 32; +const int DEFAULT_TEXTURE_BIT_DEPTH = 16; + +bool DX8Wrapper_IsWindowed = true; + +// FPU_PRESERVE +int DX8Wrapper_PreserveFPU = 0; + +/*********************************************************************************** +** +** DX8Wrapper Static Variables +** +***********************************************************************************/ + +static HWND _Hwnd = NULL; +bool DX8Wrapper::IsInitted = false; +bool DX8Wrapper::_EnableTriangleDraw = true; + +int DX8Wrapper::CurRenderDevice = -1; +int DX8Wrapper::ResolutionWidth = DEFAULT_RESOLUTION_WIDTH; +int DX8Wrapper::ResolutionHeight = DEFAULT_RESOLUTION_HEIGHT; +int DX8Wrapper::BitDepth = DEFAULT_BIT_DEPTH; +int DX8Wrapper::TextureBitDepth = DEFAULT_TEXTURE_BIT_DEPTH; +bool DX8Wrapper::IsWindowed = false; +D3DFORMAT DX8Wrapper::DisplayFormat = D3DFMT_UNKNOWN; + +D3DMATRIX DX8Wrapper::old_world; +D3DMATRIX DX8Wrapper::old_view; +D3DMATRIX DX8Wrapper::old_prj; + +// shader system additions KJM v +DWORD DX8Wrapper::Vertex_Shader = 0; +DWORD DX8Wrapper::Pixel_Shader = 0; + +Vector4 DX8Wrapper::Vertex_Shader_Constants[MAX_VERTEX_SHADER_CONSTANTS]; +Vector4 DX8Wrapper::Pixel_Shader_Constants[MAX_PIXEL_SHADER_CONSTANTS]; + +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]; +IDirect3DBaseTexture8* DX8Wrapper::Textures[MAX_TEXTURE_STAGES]; +RenderStateStruct DX8Wrapper::render_state; +unsigned DX8Wrapper::render_state_changed; + +bool DX8Wrapper::FogEnable = false; +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; +unsigned DX8Wrapper::material_changes = 0; +unsigned DX8Wrapper::vertex_buffer_changes = 0; +unsigned DX8Wrapper::index_buffer_changes = 0; +unsigned DX8Wrapper::light_changes = 0; +unsigned DX8Wrapper::texture_changes = 0; +unsigned DX8Wrapper::render_state_changes = 0; +unsigned DX8Wrapper::texture_stage_state_changes = 0; +unsigned DX8Wrapper::draw_calls = 0; +unsigned DX8Wrapper::_MainThreadID = 0; +bool DX8Wrapper::CurrentDX8LightEnables[4]; +bool DX8Wrapper::IsDeviceLost; +int DX8Wrapper::ZBias; +float DX8Wrapper::ZNear; +float DX8Wrapper::ZFar; +Matrix4x4 DX8Wrapper::ProjectionMatrix; +Matrix4x4 DX8Wrapper::DX8Transforms[D3DTS_WORLD + 1]; + +DX8Caps* DX8Wrapper::CurrentCaps = 0; + +// Hack test... this disables rendering of batches of too few polygons. +unsigned DX8Wrapper::DrawPolygonLowBoundLimit = 0; + +D3DADAPTER_IDENTIFIER8 DX8Wrapper::CurrentAdapterIdentifier; + +unsigned long DX8Wrapper::FrameCount = 0; + +bool _DX8SingleThreaded = false; + +unsigned number_of_DX8_calls = 0; +static unsigned last_frame_matrix_changes = 0; +static unsigned last_frame_material_changes = 0; +static unsigned last_frame_vertex_buffer_changes = 0; +static unsigned last_frame_index_buffer_changes = 0; +static unsigned last_frame_light_changes = 0; +static unsigned last_frame_texture_changes = 0; +static unsigned last_frame_render_state_changes = 0; +static unsigned last_frame_texture_stage_state_changes = 0; +static unsigned last_frame_number_of_DX8_calls = 0; +static unsigned last_frame_draw_calls = 0; + +static D3DDISPLAYMODE DesktopMode; + +static D3DPRESENT_PARAMETERS _PresentParameters; +static DynamicVectorClass _RenderDeviceNameTable; +static DynamicVectorClass _RenderDeviceShortNameTable; +static DynamicVectorClass _RenderDeviceDescriptionTable; + + +typedef IDirect3D8* (WINAPI* Direct3DCreate8Type) (UINT SDKVersion); +Direct3DCreate8Type Direct3DCreate8Ptr = NULL; +HINSTANCE D3D8Lib = NULL; + +DX8_CleanupHook* DX8Wrapper::m_pCleanupHook = NULL; +#ifdef EXTENDED_STATS +DX8_Stats DX8Wrapper::stats; +#endif +/*********************************************************************************** +** +** DX8Wrapper Implementation +** +***********************************************************************************/ + +void Log_DX8_ErrorCode(unsigned res) +{ + char tmp[256] = ""; + + HRESULT new_res = D3DXGetErrorStringA( + res, + tmp, + sizeof(tmp)); + + if (new_res == D3D_OK) { + WWDEBUG_SAY((tmp)); + } + + WWASSERT(0); +} + +void Non_Fatal_Log_DX8_ErrorCode(unsigned res, const char* file, int line) +{ + char tmp[256] = ""; + + HRESULT new_res = D3DXGetErrorStringA( + res, + tmp, + sizeof(tmp)); + + if (new_res == D3D_OK) { + WWDEBUG_SAY(("DX8 Error: %s, File: %s, Line: %d", tmp, file, line)); + } +} + +// TheSuperHackers @info helmutbuhler 14/04/2025 +// Helper function that moves x and y such that the inner rect fits into the outer rect. +// If the inner rect already is in the outer rect, then this does nothing. +// If the inner rect is larger than the outer rect, then the inner rect will be aligned to the top left of the outer rect. +void MoveRectIntoOtherRect(const RECT& inner, const RECT& outer, int* x, int* y) +{ + int dx = 0; + if (inner.right > outer.right) + dx = outer.right - inner.right; + if (inner.left < outer.left) + dx = outer.left - inner.left; + + int dy = 0; + if (inner.bottom > outer.bottom) + dy = outer.bottom - inner.bottom; + if (inner.top < outer.top) + dy = outer.top - inner.top; + + *x += dx; + *y += dy; +} + bool DX8Wrapper::Init(void* hwnd, bool lite) { WWASSERT(!IsInitted); diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 3b6153c3914..56e5bdf2496 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -1,266 +1 @@ -/* -** 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:: /VSS_Sync/ww3d2/dx8wrapper.cpp $* - * * - * Original Author:: Jani Penttinen * - * * - * $Author:: Vss_sync $* - * * - * $Modtime:: 8/29/01 7:29p $* - * * - * $Revision:: 134 $* - * * - *---------------------------------------------------------------------------------------------* - * Functions: * - * DX8Wrapper::_Update_Texture -- Copies a texture from system memory to video memory * - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - -//#define CREATE_DX8_MULTI_THREADED -//#define CREATE_DX8_FPU_PRESERVE -#define WW3D_DEVTYPE D3DDEVTYPE_HAL - -#if defined(_MSC_VER) && _MSC_VER < 1300 -#undef WINVER -#define WINVER 0x0500 // Required to access GetMonitorInfo in VC6. -#endif - -#include "dx8wrapper.h" -#include "dx8webbrowser.h" -#include "dx8fvf.h" -#include "dx8vertexbuffer.h" -#include "dx8indexbuffer.h" -#include "dx8renderer.h" -#include "ww3d.h" -#include "camera.h" -#include "wwstring.h" -#include "matrix4.h" -#include "vertmaterial.h" -#include "rddesc.h" -#include "lightenvironment.h" -#include "statistics.h" -#include "registry.h" -#include "boxrobj.h" -#include "pointgr.h" -#include "render2d.h" -#include "sortingrenderer.h" -#include "shattersystem.h" -#include "light.h" -#include "assetmgr.h" -#include "textureloader.h" -#include "missingtexture.h" -#include "thread.h" -#include -#include -#include "pot.h" -#include "wwprofile.h" -#include "ffactory.h" -#include "dx8caps.h" -#include "formconv.h" -#include "dx8texman.h" -#include "bound.h" -#include "dx8webbrowser.h" - -#include "shdlib.h" - - -const int DEFAULT_RESOLUTION_WIDTH = 640; -const int DEFAULT_RESOLUTION_HEIGHT = 480; -const int DEFAULT_BIT_DEPTH = 32; -const int DEFAULT_TEXTURE_BIT_DEPTH = 16; - -bool DX8Wrapper_IsWindowed = true; - -// FPU_PRESERVE -int DX8Wrapper_PreserveFPU = 0; - -/*********************************************************************************** -** -** DX8Wrapper Static Variables -** -***********************************************************************************/ - -static HWND _Hwnd = NULL; -bool DX8Wrapper::IsInitted = false; -bool DX8Wrapper::_EnableTriangleDraw = true; - -int DX8Wrapper::CurRenderDevice = -1; -int DX8Wrapper::ResolutionWidth = DEFAULT_RESOLUTION_WIDTH; -int DX8Wrapper::ResolutionHeight = DEFAULT_RESOLUTION_HEIGHT; -int DX8Wrapper::BitDepth = DEFAULT_BIT_DEPTH; -int DX8Wrapper::TextureBitDepth = DEFAULT_TEXTURE_BIT_DEPTH; -bool DX8Wrapper::IsWindowed = false; -D3DFORMAT DX8Wrapper::DisplayFormat = D3DFMT_UNKNOWN; - -D3DMATRIX DX8Wrapper::old_world; -D3DMATRIX DX8Wrapper::old_view; -D3DMATRIX DX8Wrapper::old_prj; - -// shader system additions KJM v -DWORD DX8Wrapper::Vertex_Shader = 0; -DWORD DX8Wrapper::Pixel_Shader = 0; - -Vector4 DX8Wrapper::Vertex_Shader_Constants[MAX_VERTEX_SHADER_CONSTANTS]; -Vector4 DX8Wrapper::Pixel_Shader_Constants[MAX_PIXEL_SHADER_CONSTANTS]; - -LightEnvironmentClass* DX8Wrapper::Light_Environment = NULL; -RenderInfoClass* DX8Wrapper::Render_Info = NULL; - -ZTextureClass* DX8Wrapper::Shadow_Map[MAX_SHADOW_MAPS]; -DWORD DX8Wrapper::Vertex_Processing_Behavior = 0; -Vector3 DX8Wrapper::Ambient_Color; -// shader system additions KJM ^ -bool DX8Wrapper::world_identity; -unsigned DX8Wrapper::RenderStates[256]; -unsigned DX8Wrapper::TextureStageStates[MAX_TEXTURE_STAGES][32]; -IDirect3DBaseTexture8 * DX8Wrapper::Textures[MAX_TEXTURE_STAGES]; -RenderStateStruct DX8Wrapper::render_state; -unsigned DX8Wrapper::render_state_changed; - -bool DX8Wrapper::FogEnable = false; -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; -unsigned DX8Wrapper::material_changes = 0; -unsigned DX8Wrapper::vertex_buffer_changes = 0; -unsigned DX8Wrapper::index_buffer_changes = 0; -unsigned DX8Wrapper::light_changes = 0; -unsigned DX8Wrapper::texture_changes = 0; -unsigned DX8Wrapper::render_state_changes = 0; -unsigned DX8Wrapper::texture_stage_state_changes = 0; -unsigned DX8Wrapper::draw_calls = 0; -unsigned DX8Wrapper::_MainThreadID = 0; -bool DX8Wrapper::CurrentDX8LightEnables[4]; -bool DX8Wrapper::IsDeviceLost; -int DX8Wrapper::ZBias; -float DX8Wrapper::ZNear; -float DX8Wrapper::ZFar; -Matrix4x4 DX8Wrapper::ProjectionMatrix; -Matrix4x4 DX8Wrapper::DX8Transforms[D3DTS_WORLD+1]; - -DX8Caps* DX8Wrapper::CurrentCaps = 0; - -// Hack test... this disables rendering of batches of too few polygons. -unsigned DX8Wrapper::DrawPolygonLowBoundLimit=0; - -D3DADAPTER_IDENTIFIER8 DX8Wrapper::CurrentAdapterIdentifier; - -unsigned long DX8Wrapper::FrameCount = 0; - -bool _DX8SingleThreaded = false; - -unsigned number_of_DX8_calls = 0; -static unsigned last_frame_matrix_changes = 0; -static unsigned last_frame_material_changes = 0; -static unsigned last_frame_vertex_buffer_changes = 0; -static unsigned last_frame_index_buffer_changes = 0; -static unsigned last_frame_light_changes = 0; -static unsigned last_frame_texture_changes = 0; -static unsigned last_frame_render_state_changes = 0; -static unsigned last_frame_texture_stage_state_changes = 0; -static unsigned last_frame_number_of_DX8_calls = 0; -static unsigned last_frame_draw_calls = 0; - -static D3DPRESENT_PARAMETERS _PresentParameters; -static DynamicVectorClass _RenderDeviceNameTable; -static DynamicVectorClass _RenderDeviceShortNameTable; -static DynamicVectorClass _RenderDeviceDescriptionTable; - - -typedef IDirect3D8* (WINAPI *Direct3DCreate8Type) (UINT SDKVersion); -Direct3DCreate8Type Direct3DCreate8Ptr = NULL; -HINSTANCE D3D8Lib = NULL; - -DX8_CleanupHook *DX8Wrapper::m_pCleanupHook=NULL; -#ifdef EXTENDED_STATS -DX8_Stats DX8Wrapper::stats; -#endif -/*********************************************************************************** -** -** DX8Wrapper Implementation -** -***********************************************************************************/ - -void Log_DX8_ErrorCode(unsigned res) -{ - char tmp[256]=""; - - HRESULT new_res=D3DXGetErrorStringA( - res, - tmp, - sizeof(tmp)); - - if (new_res==D3D_OK) { - WWDEBUG_SAY((tmp)); - } - - WWASSERT(0); -} - -void Non_Fatal_Log_DX8_ErrorCode(unsigned res,const char * file,int line) -{ - char tmp[256]=""; - - HRESULT new_res=D3DXGetErrorStringA( - res, - tmp, - sizeof(tmp)); - - if (new_res==D3D_OK) { - WWDEBUG_SAY(("DX8 Error: %s, File: %s, Line: %d",tmp,file,line)); - } -} - -// TheSuperHackers @info helmutbuhler 14/04/2025 -// Helper function that moves x and y such that the inner rect fits into the outer rect. -// If the inner rect already is in the outer rect, then this does nothing. -// If the inner rect is larger than the outer rect, then the inner rect will be aligned to the top left of the outer rect. -void MoveRectIntoOtherRect(const RECT& inner, const RECT& outer, int* x, int* y) -{ - int dx = 0; - if (inner.right > outer.right) - dx = outer.right-inner.right; - if (inner.left < outer.left) - dx = outer.left-inner.left; - - int dy = 0; - if (inner.bottom > outer.bottom) - dy = outer.bottom-inner.bottom; - if (inner.top < outer.top) - dy = outer.top-inner.top; - - *x += dx; - *y += dy; -} - #include "../../Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h" - diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 83965a76b2e..56e5bdf2496 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -1,273 +1 @@ -/* -** Command & Conquer Generals Zero Hour(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/dx8wrapper.cpp $* - * * - * Original Author:: Jani Penttinen * - * * - * $Author:: Kenny Mitchell * - * * - * $Modtime:: 08/05/02 1:27p $* - * * - * $Revision:: 170 $* - * * - * 06/26/02 KM Matrix name change to avoid MAX conflicts * - * 06/27/02 KM Render to shadow buffer texture support * - * 06/27/02 KM Shader system updates * - * 08/05/02 KM Texture class redesign - *---------------------------------------------------------------------------------------------* - * Functions: * - * DX8Wrapper::_Update_Texture -- Copies a texture from system memory to video memory * - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - -//#define CREATE_DX8_MULTI_THREADED -//#define CREATE_DX8_FPU_PRESERVE -#define WW3D_DEVTYPE D3DDEVTYPE_HAL - -#if defined(_MSC_VER) && _MSC_VER < 1300 -#undef WINVER -#define WINVER 0x0500 // Required to access GetMonitorInfo in VC6. -#endif - -#include "dx8wrapper.h" -#include "dx8webbrowser.h" -#include "dx8fvf.h" -#include "dx8vertexbuffer.h" -#include "dx8indexbuffer.h" -#include "dx8renderer.h" -#include "ww3d.h" -#include "camera.h" -#include "wwstring.h" -#include "matrix4.h" -#include "vertmaterial.h" -#include "rddesc.h" -#include "lightenvironment.h" -#include "statistics.h" -#include "registry.h" -#include "boxrobj.h" -#include "pointgr.h" -#include "render2d.h" -#include "sortingrenderer.h" -#include "shattersystem.h" -#include "light.h" -#include "assetmgr.h" -#include "textureloader.h" -#include "missingtexture.h" -#include "thread.h" -#include -#include -#include "pot.h" -#include "wwprofile.h" -#include "ffactory.h" -#include "dx8caps.h" -#include "formconv.h" -#include "dx8texman.h" -#include "bound.h" -#include "dx8webbrowser.h" - -#include "shdlib.h" - -const int DEFAULT_RESOLUTION_WIDTH = 640; -const int DEFAULT_RESOLUTION_HEIGHT = 480; -const int DEFAULT_BIT_DEPTH = 32; -const int DEFAULT_TEXTURE_BIT_DEPTH = 16; - -bool DX8Wrapper_IsWindowed = true; - -// FPU_PRESERVE -int DX8Wrapper_PreserveFPU = 0; - -/*********************************************************************************** -** -** DX8Wrapper Static Variables -** -***********************************************************************************/ - -static HWND _Hwnd = NULL; -bool DX8Wrapper::IsInitted = false; -bool DX8Wrapper::_EnableTriangleDraw = true; - -int DX8Wrapper::CurRenderDevice = -1; -int DX8Wrapper::ResolutionWidth = DEFAULT_RESOLUTION_WIDTH; -int DX8Wrapper::ResolutionHeight = DEFAULT_RESOLUTION_HEIGHT; -int DX8Wrapper::BitDepth = DEFAULT_BIT_DEPTH; -int DX8Wrapper::TextureBitDepth = DEFAULT_TEXTURE_BIT_DEPTH; -bool DX8Wrapper::IsWindowed = false; -D3DFORMAT DX8Wrapper::DisplayFormat = D3DFMT_UNKNOWN; - -D3DMATRIX DX8Wrapper::old_world; -D3DMATRIX DX8Wrapper::old_view; -D3DMATRIX DX8Wrapper::old_prj; - -// shader system additions KJM v -DWORD DX8Wrapper::Vertex_Shader = 0; -DWORD DX8Wrapper::Pixel_Shader = 0; - -Vector4 DX8Wrapper::Vertex_Shader_Constants[MAX_VERTEX_SHADER_CONSTANTS]; -Vector4 DX8Wrapper::Pixel_Shader_Constants[MAX_PIXEL_SHADER_CONSTANTS]; - -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]; -IDirect3DBaseTexture8 * DX8Wrapper::Textures[MAX_TEXTURE_STAGES]; -RenderStateStruct DX8Wrapper::render_state; -unsigned DX8Wrapper::render_state_changed; - -bool DX8Wrapper::FogEnable = false; -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; -unsigned DX8Wrapper::material_changes = 0; -unsigned DX8Wrapper::vertex_buffer_changes = 0; -unsigned DX8Wrapper::index_buffer_changes = 0; -unsigned DX8Wrapper::light_changes = 0; -unsigned DX8Wrapper::texture_changes = 0; -unsigned DX8Wrapper::render_state_changes = 0; -unsigned DX8Wrapper::texture_stage_state_changes = 0; -unsigned DX8Wrapper::draw_calls = 0; -unsigned DX8Wrapper::_MainThreadID = 0; -bool DX8Wrapper::CurrentDX8LightEnables[4]; -bool DX8Wrapper::IsDeviceLost; -int DX8Wrapper::ZBias; -float DX8Wrapper::ZNear; -float DX8Wrapper::ZFar; -Matrix4x4 DX8Wrapper::ProjectionMatrix; -Matrix4x4 DX8Wrapper::DX8Transforms[D3DTS_WORLD+1]; - -DX8Caps* DX8Wrapper::CurrentCaps = 0; - -// Hack test... this disables rendering of batches of too few polygons. -unsigned DX8Wrapper::DrawPolygonLowBoundLimit=0; - -D3DADAPTER_IDENTIFIER8 DX8Wrapper::CurrentAdapterIdentifier; - -unsigned long DX8Wrapper::FrameCount = 0; - -bool _DX8SingleThreaded = false; - -unsigned number_of_DX8_calls = 0; -static unsigned last_frame_matrix_changes = 0; -static unsigned last_frame_material_changes = 0; -static unsigned last_frame_vertex_buffer_changes = 0; -static unsigned last_frame_index_buffer_changes = 0; -static unsigned last_frame_light_changes = 0; -static unsigned last_frame_texture_changes = 0; -static unsigned last_frame_render_state_changes = 0; -static unsigned last_frame_texture_stage_state_changes = 0; -static unsigned last_frame_number_of_DX8_calls = 0; -static unsigned last_frame_draw_calls = 0; - -static D3DDISPLAYMODE DesktopMode; - -static D3DPRESENT_PARAMETERS _PresentParameters; -static DynamicVectorClass _RenderDeviceNameTable; -static DynamicVectorClass _RenderDeviceShortNameTable; -static DynamicVectorClass _RenderDeviceDescriptionTable; - - -typedef IDirect3D8* (WINAPI *Direct3DCreate8Type) (UINT SDKVersion); -Direct3DCreate8Type Direct3DCreate8Ptr = NULL; -HINSTANCE D3D8Lib = NULL; - -DX8_CleanupHook *DX8Wrapper::m_pCleanupHook=NULL; -#ifdef EXTENDED_STATS -DX8_Stats DX8Wrapper::stats; -#endif -/*********************************************************************************** -** -** DX8Wrapper Implementation -** -***********************************************************************************/ - -void Log_DX8_ErrorCode(unsigned res) -{ - char tmp[256]=""; - - HRESULT new_res=D3DXGetErrorStringA( - res, - tmp, - sizeof(tmp)); - - if (new_res==D3D_OK) { - WWDEBUG_SAY((tmp)); - } - - WWASSERT(0); -} - -void Non_Fatal_Log_DX8_ErrorCode(unsigned res,const char * file,int line) -{ - char tmp[256]=""; - - HRESULT new_res=D3DXGetErrorStringA( - res, - tmp, - sizeof(tmp)); - - if (new_res==D3D_OK) { - WWDEBUG_SAY(("DX8 Error: %s, File: %s, Line: %d",tmp,file,line)); - } -} - -// TheSuperHackers @info helmutbuhler 14/04/2025 -// Helper function that moves x and y such that the inner rect fits into the outer rect. -// If the inner rect already is in the outer rect, then this does nothing. -// If the inner rect is larger than the outer rect, then the inner rect will be aligned to the top left of the outer rect. -void MoveRectIntoOtherRect(const RECT& inner, const RECT& outer, int* x, int* y) -{ - int dx = 0; - if (inner.right > outer.right) - dx = outer.right-inner.right; - if (inner.left < outer.left) - dx = outer.left-inner.left; - - int dy = 0; - if (inner.bottom > outer.bottom) - dy = outer.bottom-inner.bottom; - if (inner.top < outer.top) - dy = outer.top-inner.top; - - *x += dx; - *y += dy; -} - #include "../../Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h" - From b9f857278a9afca3d1a050f78854852f37f95ddc Mon Sep 17 00:00:00 2001 From: ryan-de-boer Date: Fri, 1 Aug 2025 18:14:16 +0800 Subject: [PATCH 16/20] Unify the dx8wrapper.h --- .../Graphics/DX8/dx8wrapper_header_common.h | 1516 +++++++++++++++++ .../Source/WWVegas/WW3D2/dx8caps.cpp | 2 + .../Libraries/Source/WWVegas/WW3D2/dx8caps.h | 2 + .../Source/WWVegas/WW3D2/dx8renderer.cpp | 17 +- .../Source/WWVegas/WW3D2/dx8wrapper.h | 1441 +--------------- .../Source/WWVegas/WW3D2/dx8wrapper.h | 1515 +--------------- 6 files changed, 1531 insertions(+), 2962 deletions(-) create mode 100644 Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_header_common.h diff --git a/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_header_common.h b/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_header_common.h new file mode 100644 index 00000000000..414256e15a6 --- /dev/null +++ b/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_header_common.h @@ -0,0 +1,1516 @@ +/* +** Command & Conquer Generals Zero Hour(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/dx8wrapper.h $* + * * + * Original Author:: Jani Penttinen * + * * + * Author : Kenny Mitchell * + * * + * $Modtime:: 08/05/02 2:40p $* + * * + * $Revision:: 92 $* + * * + * 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: * + * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef DX8_WRAPPER_H +#define DX8_WRAPPER_H + +#include "always.h" +#include "dllist.h" +#include "d3d8.h" +#include "matrix4.h" +#include "statistics.h" +#include "wwstring.h" +#include "lightenvironment.h" +#include "shader.h" +#include "vector4.h" +#include "cpudetect.h" +#include "dx8caps.h" + +#include "texture.h" +#include "dx8vertexbuffer.h" +#include "dx8indexbuffer.h" +#include "vertmaterial.h" + + /* + ** Registry value names + */ +#define VALUE_NAME_RENDER_DEVICE_NAME "RenderDeviceName" +#define VALUE_NAME_RENDER_DEVICE_WIDTH "RenderDeviceWidth" +#define VALUE_NAME_RENDER_DEVICE_HEIGHT "RenderDeviceHeight" +#define VALUE_NAME_RENDER_DEVICE_DEPTH "RenderDeviceDepth" +#define VALUE_NAME_RENDER_DEVICE_WINDOWED "RenderDeviceWindowed" +#define VALUE_NAME_RENDER_DEVICE_TEXTURE_DEPTH "RenderDeviceTextureDepth" + +const unsigned MAX_TEXTURE_STAGES = 8; +const unsigned MAX_VERTEX_STREAMS = 2; +const unsigned MAX_VERTEX_SHADER_CONSTANTS = 96; +const unsigned MAX_PIXEL_SHADER_CONSTANTS = 8; +const unsigned MAX_SHADOW_MAPS = 1; + +#define prevVer +#define nextVer + + +enum { + BUFFER_TYPE_DX8, + BUFFER_TYPE_SORTING, + BUFFER_TYPE_DYNAMIC_DX8, + BUFFER_TYPE_DYNAMIC_SORTING, + BUFFER_TYPE_INVALID +}; + +class VertexMaterialClass; +class CameraClass; +class LightEnvironmentClass; +class RenderDeviceDescClass; +class VertexBufferClass; +class DynamicVBAccessClass; +class IndexBufferClass; +class DynamicIBAccessClass; +class TextureClass; +class ZTextureClass; +class LightClass; +class SurfaceClass; +class DX8Caps; + +#define DX8_RECORD_MATRIX_CHANGE() matrix_changes++ +#define DX8_RECORD_MATERIAL_CHANGE() material_changes++ +#define DX8_RECORD_VERTEX_BUFFER_CHANGE() vertex_buffer_changes++ +#define DX8_RECORD_INDEX_BUFFER_CHANGE() index_buffer_changes++ +#define DX8_RECORD_LIGHT_CHANGE() light_changes++ +#define DX8_RECORD_TEXTURE_CHANGE() texture_changes++ +#define DX8_RECORD_RENDER_STATE_CHANGE() render_state_changes++ +#define DX8_RECORD_TEXTURE_STAGE_STATE_CHANGE() texture_stage_state_changes++ +#define DX8_RECORD_DRAW_CALLS() draw_calls++ + +extern unsigned number_of_DX8_calls; +extern bool _DX8SingleThreaded; + +void DX8_Assert(); +void Log_DX8_ErrorCode(unsigned res); + +WWINLINE void DX8_ErrorCode(unsigned res) +{ + if (res == D3D_OK) return; + Log_DX8_ErrorCode(res); +} + +#ifdef WWDEBUG +#define DX8CALL_HRES(x,res) DX8_Assert(); res = DX8Wrapper::_Get_D3D_Device8()->x; DX8_ErrorCode(res); number_of_DX8_calls++; +#define DX8CALL(x) DX8_Assert(); DX8_ErrorCode(DX8Wrapper::_Get_D3D_Device8()->x); number_of_DX8_calls++; +#define DX8CALL_D3D(x) DX8_Assert(); DX8_ErrorCode(DX8Wrapper::_Get_D3D8()->x); number_of_DX8_calls++; +#define DX8_THREAD_ASSERT() if (_DX8SingleThreaded) { WWASSERT_PRINT(DX8Wrapper::_Get_Main_Thread_ID()==ThreadClass::_Get_Current_Thread_ID(),"DX8Wrapper::DX8 calls must be called from the main thread!"); } +#else +#define DX8CALL_HRES(x,res) res = DX8Wrapper::_Get_D3D_Device8()->x; number_of_DX8_calls++; +#define DX8CALL(x) DX8Wrapper::_Get_D3D_Device8()->x; number_of_DX8_calls++; +#define DX8CALL_D3D(x) DX8Wrapper::_Get_D3D8()->x; number_of_DX8_calls++; +#define DX8_THREAD_ASSERT() ; +#endif + + +#define no_EXTENDED_STATS +// EXTENDED_STATS collects additional timing statistics by turning off parts +// of the 3D drawing system (terrain, objects, etc.) +#ifdef EXTENDED_STATS +class DX8_Stats +{ +public: + bool m_showingStats; + bool m_disableTerrain; + bool m_disableWater; + bool m_disableObjects; + bool m_disableOverhead; + bool m_disableConsole; + int m_debugLinesToShow; + int m_sleepTime; +public: + DX8_Stats::DX8_Stats(void) { + m_disableConsole = m_showingStats = m_disableTerrain = m_disableWater = m_disableOverhead = m_disableObjects = false; + m_sleepTime = 0; + m_debugLinesToShow = -1; // -1 means show all expected lines of output + } +}; +#endif + + +// This virtual interface was added for the Generals RTS. +// It is called before resetting the dx8 device to ensure +// that all dx8 resources are released. Otherwise reset fails. jba. +class DX8_CleanupHook +{ +public: + virtual void ReleaseResources(void) = 0; + virtual void ReAcquireResources(void) = 0; +}; + + +struct RenderStateStruct +{ + ShaderClass shader; + VertexMaterialClass* material; + TextureBaseClass* Textures[MAX_TEXTURE_STAGES]; + D3DLIGHT8 Lights[4]; + bool LightEnable[4]; + //unsigned lightsHash; + Matrix4x4 world; + Matrix4x4 view; + unsigned vertex_buffer_types[MAX_VERTEX_STREAMS]; + unsigned index_buffer_type; + unsigned short vba_offset; + unsigned short vba_count; + unsigned short iba_offset; + VertexBufferClass* vertex_buffers[MAX_VERTEX_STREAMS]; + IndexBufferClass* index_buffer; + unsigned short index_base_offset; + + RenderStateStruct(); + ~RenderStateStruct(); + + RenderStateStruct& operator= (const RenderStateStruct& src); +}; + +/** +** DX8Wrapper +** +** DX8 interface wrapper class. This encapsulates the DX8 interface; adding redundant state +** detection, stat tracking, etc etc. In general, we will wrap all DX8 calls with at least +** an WWINLINE function so that we can add stat tracking, etc if needed. Direct access to the +** D3D device will require "friend" status and should be granted only in extreme circumstances :-) +*/ +class DX8Wrapper +{ + enum ChangedStates { + WORLD_CHANGED = 1 << 0, + VIEW_CHANGED = 1 << 1, + LIGHT0_CHANGED = 1 << 2, + LIGHT1_CHANGED = 1 << 3, + LIGHT2_CHANGED = 1 << 4, + LIGHT3_CHANGED = 1 << 5, + TEXTURE0_CHANGED = 1 << 6, + TEXTURE1_CHANGED = 1 << 7, + TEXTURE2_CHANGED = 1 << 8, + TEXTURE3_CHANGED = 1 << 9, + MATERIAL_CHANGED = 1 << 14, + SHADER_CHANGED = 1 << 15, + VERTEX_BUFFER_CHANGED = 1 << 16, + INDEX_BUFFER_CHANGED = 1 << 17, + WORLD_IDENTITY = 1 << 18, + VIEW_IDENTITY = 1 << 19, + + TEXTURES_CHANGED = + TEXTURE0_CHANGED | TEXTURE1_CHANGED | TEXTURE2_CHANGED | TEXTURE3_CHANGED, + LIGHTS_CHANGED = + LIGHT0_CHANGED | LIGHT1_CHANGED | LIGHT2_CHANGED | LIGHT3_CHANGED, + }; + + static void Draw_Sorting_IB_VB( + unsigned primitive_type, + unsigned short start_index, + unsigned short polygon_count, + unsigned short min_vertex_index, + unsigned short vertex_count); + + static void Draw( + unsigned primitive_type, + unsigned short start_index, + unsigned short polygon_count, + unsigned short min_vertex_index = 0, + unsigned short vertex_count = 0); + +public: +#ifdef EXTENDED_STATS + static DX8_Stats stats; +#endif + + static bool Init(void* hwnd, bool lite = false); + static void Shutdown(void); + + static void SetCleanupHook(DX8_CleanupHook* pCleanupHook) { m_pCleanupHook = pCleanupHook; }; + /* + ** Some WW3D sub-systems need to be initialized after the device is created and shutdown + ** before the device is released. + */ + static void Do_Onetime_Device_Dependent_Inits(void); + static void Do_Onetime_Device_Dependent_Shutdowns(void); + + static bool Is_Device_Lost() { return IsDeviceLost; } + static bool Is_Initted(void) { return IsInitted; } + + static bool Has_Stencil(void); + static void Get_Format_Name(unsigned int format, StringClass* tex_format); + + /* + ** Rendering + */ + static void Begin_Scene(void); + static void End_Scene(bool flip_frame = true); + + // Flip until the primary buffer is visible. + static void Flip_To_Primary(void); + + static void Clear(bool clear_color, bool clear_z_stencil, const Vector3& color, float dest_alpha = 0.0f, float z = 1.0f, unsigned int stencil = 0); + + static void Set_Viewport(CONST D3DVIEWPORT8* pViewport); + + static void Set_Vertex_Buffer(const VertexBufferClass* vb, unsigned stream = 0); + static void Set_Vertex_Buffer(const DynamicVBAccessClass& vba); + static void Set_Index_Buffer(const IndexBufferClass* ib, unsigned short index_base_offset); + static void Set_Index_Buffer(const DynamicIBAccessClass& iba, unsigned short index_base_offset); + static void Set_Index_Buffer_Index_Offset(unsigned offset); + + static void Get_Render_State(RenderStateStruct& state); + static void Set_Render_State(const RenderStateStruct& state); + static void Release_Render_State(); + + static void Set_DX8_Material(const D3DMATERIAL8* mat); + + static void Set_Gamma(float gamma, float bright, float contrast, bool calibrate = true, bool uselimit = true); + + // Set_ and Get_Transform() functions take the matrix in Westwood convention format. + + static void Set_DX8_ZBias(int zbias); + static void Set_Projection_Transform_With_Z_Bias(const Matrix4x4& matrix, float znear, float zfar); // pointer to 16 matrices + + static void Set_Transform(D3DTRANSFORMSTATETYPE transform, const Matrix4x4& m); + static void Set_Transform(D3DTRANSFORMSTATETYPE transform, const Matrix3D& m); + static void Get_Transform(D3DTRANSFORMSTATETYPE transform, Matrix4x4& m); + static void Set_World_Identity(); + static void Set_View_Identity(); + static bool Is_World_Identity(); + static bool Is_View_Identity(); + + // Note that *_DX8_Transform() functions take the matrix in DX8 format - transposed from Westwood convention. + + static void _Set_DX8_Transform(D3DTRANSFORMSTATETYPE transform, const Matrix4x4& m); + static void _Set_DX8_Transform(D3DTRANSFORMSTATETYPE transform, const Matrix3D& m); + static void _Get_DX8_Transform(D3DTRANSFORMSTATETYPE transform, Matrix4x4& m); + + static void Set_DX8_Light(int index, D3DLIGHT8* light); + static void Set_DX8_Render_State(D3DRENDERSTATETYPE state, unsigned value); + static void Set_DX8_Clip_Plane(DWORD Index, CONST float* pPlane); + static void Set_DX8_Texture_Stage_State(unsigned stage, D3DTEXTURESTAGESTATETYPE state, unsigned value); + static void Set_DX8_Texture(unsigned int stage, IDirect3DBaseTexture8* texture); + static void Set_Light_Environment(LightEnvironmentClass* light_env); + static LightEnvironmentClass* Get_Light_Environment() { return Light_Environment; } + static void Set_Fog(bool enable, const Vector3& color, float start, float end); + + static WWINLINE const D3DLIGHT8& Peek_Light(unsigned index); + static WWINLINE bool Is_Light_Enabled(unsigned index); + + static bool Validate_Device(void); + + // Deferred + + static void Set_Shader(const ShaderClass& shader); + static void Get_Shader(ShaderClass& shader); + static void Set_Texture(unsigned stage, TextureBaseClass* texture); + static void Set_Material(const VertexMaterialClass* material); + static void Set_Light(unsigned index, const D3DLIGHT8* light); + static void Set_Light(unsigned index, const LightClass& light); + + static void Apply_Render_State_Changes(); // Apply deferred render state changes (will be called automatically by Draw...) + + static void Draw_Triangles( + unsigned buffer_type, + unsigned short start_index, + unsigned short polygon_count, + unsigned short min_vertex_index, + unsigned short vertex_count); + static void Draw_Triangles( + unsigned short start_index, + unsigned short polygon_count, + unsigned short min_vertex_index, + unsigned short vertex_count); + static void Draw_Strip( + unsigned short start_index, + unsigned short index_count, + unsigned short min_vertex_index, + unsigned short vertex_count); + + /* + ** 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, + unsigned int height, + WW3DFormat format, + MipCountType mip_level_count, + D3DPOOL pool = D3DPOOL_MANAGED, + bool rendertarget = false + ); + static IDirect3DTexture8* _Create_DX8_Texture(const char* filename, MipCountType mip_level_count); + static IDirect3DTexture8* _Create_DX8_Texture(IDirect3DSurface8* surface, MipCountType mip_level_count); + + static IDirect3DSurface8* _Create_DX8_Surface(unsigned int width, unsigned int height, WW3DFormat format); + static IDirect3DSurface8* _Create_DX8_Surface(const char* filename); + static IDirect3DSurface8* _Get_DX8_Front_Buffer(); + static SurfaceClass* _Get_DX8_Back_Buffer(unsigned int num = 0); + + static void _Copy_DX8_Rects( + IDirect3DSurface8* pSourceSurface, + CONST RECT* pSourceRectsArray, + UINT cRects, + IDirect3DSurface8* pDestinationSurface, + CONST POINT* pDestPointsArray + ); + + static void _Update_Texture(TextureClass* system, TextureClass* video); + static void Flush_DX8_Resource_Manager(unsigned int bytes = 0); + static unsigned int Get_Free_Texture_RAM(); + + static unsigned _Get_Main_Thread_ID() { return _MainThreadID; } + static const D3DADAPTER_IDENTIFIER8& Get_Current_Adapter_Identifier() { return CurrentAdapterIdentifier; } + + /* + ** Statistics + */ + static void Begin_Statistics(); + static void End_Statistics(); + static unsigned Get_Last_Frame_Matrix_Changes(); + static unsigned Get_Last_Frame_Material_Changes(); + static unsigned Get_Last_Frame_Vertex_Buffer_Changes(); + static unsigned Get_Last_Frame_Index_Buffer_Changes(); + static unsigned Get_Last_Frame_Light_Changes(); + static unsigned Get_Last_Frame_Texture_Changes(); + static unsigned Get_Last_Frame_Render_State_Changes(); + static unsigned Get_Last_Frame_Texture_Stage_State_Changes(); + static unsigned Get_Last_Frame_DX8_Calls(); + static unsigned Get_Last_Frame_Draw_Calls(); + + static unsigned long Get_FrameCount(void); + + // Needed by shader class + static bool Get_Fog_Enable() { return FogEnable; } + static D3DCOLOR Get_Fog_Color() { return FogColor; } + + // Utilities + static Vector4 Convert_Color(unsigned color); + static unsigned int Convert_Color(const Vector4& color); + static unsigned int Convert_Color(const Vector3& color, const float alpha); + static void Clamp_Color(Vector4& color); + static unsigned int Convert_Color_Clamp(const Vector4& color); + + static void Set_Alpha(const float alpha, unsigned int& color); + + static void _Enable_Triangle_Draw(bool enable) { _EnableTriangleDraw = enable; } + static bool _Is_Triangle_Draw_Enabled() { return _EnableTriangleDraw; } + + /* + ** Additional swap chain interface + ** + ** Use this interface to render to multiple windows (in windowed mode). + ** To render to an additional window, the sequence of calls should look + ** something like this: + ** + ** DX8Wrapper::Set_Render_Target (swap_chain_ptr); + ** + ** WW3D::Begin_Render (true, true, Vector3 (0, 0, 0)); + ** WW3D::Render (scene, camera, FALSE, FALSE); + ** WW3D::End_Render (); + ** + ** swap_chain_ptr->Present (NULL, NULL, NULL, NULL); + ** + ** DX8Wrapper::Set_Render_Target ((IDirect3DSurface8 *)NULL); + ** + */ + static IDirect3DSwapChain8* Create_Additional_Swap_Chain(HWND render_window); + + /* + ** 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, 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(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(); + + static void Set_Vertex_Shader(DWORD vertex_shader); + static void Set_Pixel_Shader(DWORD pixel_shader); + + static void Set_Vertex_Shader_Constant(int reg, const void* data, int count); + static void Set_Pixel_Shader_Constant(int reg, const void* data, int count); + + static DWORD Get_Vertex_Processing_Behavior() { return Vertex_Processing_Behavior; } + + // Needed by scene lighting class + static void Set_Ambient(const Vector3& color); + static const Vector3& Get_Ambient() { return Ambient_Color; } + // shader system updates KJM ^ + + + + + static IDirect3DDevice8* _Get_D3D_Device8() { return D3DDevice; } + static IDirect3D8* _Get_D3D8() { return D3DInterface; } + /// Returns the display format - added by TR for video playback - not part of W3D + static WW3DFormat getBackBufferFormat(void); + static bool Reset_Device(bool reload_assets = true); + + static const DX8Caps* Get_Current_Caps() { WWASSERT(CurrentCaps); return CurrentCaps; } + + static bool Registry_Save_Render_Device(const char* sub_key); + static bool Registry_Load_Render_Device(const char* sub_key, bool resize_window); + + static const char* Get_DX8_Render_State_Name(D3DRENDERSTATETYPE state); + static const char* Get_DX8_Texture_Stage_State_Name(D3DTEXTURESTAGESTATETYPE state); + static unsigned Get_DX8_Render_State(D3DRENDERSTATETYPE state) { return RenderStates[state]; } + + // Names of the specific values of render states and texture stage states + static void Get_DX8_Texture_Stage_State_Value_Name(StringClass& name, D3DTEXTURESTAGESTATETYPE state, unsigned value); + static void Get_DX8_Render_State_Value_Name(StringClass& name, D3DRENDERSTATETYPE state, unsigned value); + + static const char* Get_DX8_Texture_Address_Name(unsigned value); + static const char* Get_DX8_Texture_Filter_Name(unsigned value); + static const char* Get_DX8_Texture_Arg_Name(unsigned value); + static const char* Get_DX8_Texture_Op_Name(unsigned value); + static const char* Get_DX8_Texture_Transform_Flag_Name(unsigned value); + static const char* Get_DX8_ZBuffer_Type_Name(unsigned value); + static const char* Get_DX8_Fill_Mode_Name(unsigned value); + static const char* Get_DX8_Shade_Mode_Name(unsigned value); + static const char* Get_DX8_Blend_Name(unsigned value); + static const char* Get_DX8_Cull_Mode_Name(unsigned value); + static const char* Get_DX8_Cmp_Func_Name(unsigned value); + static const char* Get_DX8_Fog_Mode_Name(unsigned value); + static const char* Get_DX8_Stencil_Op_Name(unsigned value); + static const char* Get_DX8_Material_Source_Name(unsigned value); + static const char* Get_DX8_Vertex_Blend_Flag_Name(unsigned value); + static const char* Get_DX8_Patch_Edge_Style_Name(unsigned value); + static const char* Get_DX8_Debug_Monitor_Token_Name(unsigned value); + static const char* Get_DX8_Blend_Op_Name(unsigned value); + + static void Invalidate_Cached_Render_States(void); + + static void Set_Draw_Polygon_Low_Bound_Limit(unsigned n) { DrawPolygonLowBoundLimit = n; } + +protected: + + static bool Create_Device(void); + static void Release_Device(void); + + static void Reset_Statistics(); + static void Enumerate_Devices(); + static void Set_Default_Global_Render_States(void); + + /* + ** Device Selection Code. + ** For backward compatibility, the public interface for these functions is in the ww3d. + ** header file. These functions are protected so that we aren't exposing two interfaces. + */ + static bool Set_Any_Render_Device(void); + static bool Set_Render_Device(const char* dev_name, int width = -1, int height = -1, int bits = -1, int windowed = -1, bool resize_window = false); + static bool Set_Render_Device(int dev = -1, int resx = -1, int resy = -1, int bits = -1, int windowed = -1, bool resize_window = false, bool reset_device = false, bool restore_assets = true); + static bool Set_Next_Render_Device(void); + static bool Toggle_Windowed(void); + + static int Get_Render_Device_Count(void); + static int Get_Render_Device(void); + static const RenderDeviceDescClass& Get_Render_Device_Desc(int deviceidx); + static const char* Get_Render_Device_Name(int device_index); + static bool Set_Device_Resolution(int width = -1, int height = -1, int bits = -1, int windowed = -1, bool resize_window = false); + static void Get_Device_Resolution(int& set_w, int& set_h, int& set_bits, bool& set_windowed); + static void Get_Render_Target_Resolution(int& set_w, int& set_h, int& set_bits, bool& set_windowed); + static int Get_Device_Resolution_Width(void) { return ResolutionWidth; } + static int Get_Device_Resolution_Height(void) { return ResolutionHeight; } + + static bool Registry_Save_Render_Device(const char* sub_key, int device, int width, int height, int depth, bool windowed, int texture_depth); + static bool Registry_Load_Render_Device(const char* sub_key, char* device, int device_len, int& width, int& height, int& depth, int& windowed, int& texture_depth); + static bool Is_Windowed(void) { return IsWindowed; } + + static void Set_Texture_Bitdepth(int depth) { WWASSERT(depth == 16 || depth == 32); TextureBitDepth = depth; } + static int Get_Texture_Bitdepth(void) { return TextureBitDepth; } + + static void Set_Swap_Interval(int swap); + static int Get_Swap_Interval(void); + static void Set_Polygon_Mode(int mode); + + /* + ** Internal functions + */ + static void Resize_And_Position_Window(); + static bool Find_Color_And_Z_Mode(int resx, int resy, int bitdepth, D3DFORMAT* set_colorbuffer, D3DFORMAT* set_backbuffer, D3DFORMAT* set_zmode); + static bool Find_Color_Mode(D3DFORMAT colorbuffer, int resx, int resy, UINT* mode); + static bool Find_Z_Mode(D3DFORMAT colorbuffer, D3DFORMAT backbuffer, D3DFORMAT* zmode); + static bool Test_Z_Mode(D3DFORMAT colorbuffer, D3DFORMAT backbuffer, D3DFORMAT zmode); + static void Compute_Caps(WW3DFormat display_format); + + /* + ** Protected Member Variables + */ + + static DX8_CleanupHook* m_pCleanupHook; + + static RenderStateStruct render_state; + static unsigned render_state_changed; + static Matrix4x4 DX8Transforms[D3DTS_WORLD + 1]; + + static bool IsInitted; + static bool IsDeviceLost; + static void* Hwnd; + static unsigned _MainThreadID; + + static bool _EnableTriangleDraw; + + static int CurRenderDevice; + static int ResolutionWidth; + static int ResolutionHeight; + static int BitDepth; + static int TextureBitDepth; + static bool IsWindowed; + static D3DFORMAT DisplayFormat; + + static D3DMATRIX old_world; + static D3DMATRIX old_view; + static D3DMATRIX old_prj; + + // shader system updates KJM v + static DWORD Vertex_Shader; + static DWORD Pixel_Shader; + + static Vector4 Vertex_Shader_Constants[MAX_VERTEX_SHADER_CONSTANTS]; + static Vector4 Pixel_Shader_Constants[MAX_PIXEL_SHADER_CONSTANTS]; + + static LightEnvironmentClass* Light_Environment; + static RenderInfoClass* Render_Info; + + static DWORD Vertex_Processing_Behavior; + + static ZTextureClass* Shadow_Map[MAX_SHADOW_MAPS]; + + static Vector3 Ambient_Color; + // shader system updates KJM ^ + + static bool world_identity; + static unsigned RenderStates[256]; + static unsigned TextureStageStates[MAX_TEXTURE_STAGES][32]; + static IDirect3DBaseTexture8* Textures[MAX_TEXTURE_STAGES]; + + // These fog settings are constant for all objects in a given scene, + // unlike the matching renderstates which vary based on shader settings. + static bool FogEnable; + static D3DCOLOR FogColor; + + static unsigned matrix_changes; + static unsigned material_changes; + static unsigned vertex_buffer_changes; + static unsigned index_buffer_changes; + static unsigned light_changes; + static unsigned texture_changes; + static unsigned render_state_changes; + static unsigned texture_stage_state_changes; + static unsigned draw_calls; + static bool CurrentDX8LightEnables[4]; + + static unsigned long FrameCount; + + static DX8Caps* CurrentCaps; + + static D3DADAPTER_IDENTIFIER8 CurrentAdapterIdentifier; + + static IDirect3D8* D3DInterface; //d3d8; + static IDirect3DDevice8* D3DDevice; //d3ddevice8; + + static IDirect3DSurface8* CurrentRenderTarget; + static IDirect3DSurface8* CurrentDepthBuffer; + static IDirect3DSurface8* DefaultRenderTarget; + static IDirect3DSurface8* DefaultDepthBuffer; + + static unsigned DrawPolygonLowBoundLimit; + + static bool IsRenderToTexture; + + static int ZBias; + static float ZNear; + static float ZFar; + static Matrix4x4 ProjectionMatrix; + + friend void DX8_Assert(); + friend class WW3D; + friend class DX8IndexBufferClass; + friend class DX8VertexBufferClass; +}; + +// shader system updates KJM v +WWINLINE void DX8Wrapper::Set_Vertex_Shader(DWORD vertex_shader) +{ +#if 0 //(gth) some code is bypassing this acessor function so we can't count on this variable... + // may be incorrect if shaders are created and destroyed dynamically + if (Vertex_Shader == vertex_shader) return; +#endif + + Vertex_Shader = vertex_shader; + DX8CALL(SetVertexShader(Vertex_Shader)); +} + +WWINLINE void DX8Wrapper::Set_Pixel_Shader(DWORD pixel_shader) +{ + // may be incorrect if shaders are created and destroyed dynamically + if (Pixel_Shader == pixel_shader) return; + + Pixel_Shader = pixel_shader; + DX8CALL(SetPixelShader(Pixel_Shader)); +} + +WWINLINE void DX8Wrapper::Set_Vertex_Shader_Constant(int reg, const void* data, int count) +{ + int memsize = sizeof(Vector4) * count; + + // may be incorrect if shaders are created and destroyed dynamically + if (memcmp(data, &Vertex_Shader_Constants[reg], memsize) == 0) return; + + memcpy(&Vertex_Shader_Constants[reg], data, memsize); + DX8CALL(SetVertexShaderConstant(reg, data, count)); +} + +WWINLINE void DX8Wrapper::Set_Pixel_Shader_Constant(int reg, const void* data, int count) +{ + int memsize = sizeof(Vector4) * count; + + // may be incorrect if shaders are created and destroyed dynamically + if (memcmp(data, &Pixel_Shader_Constants[reg], memsize) == 0) return; + + memcpy(&Pixel_Shader_Constants[reg], data, memsize); + DX8CALL(SetPixelShaderConstant(reg, data, count)); +} +// shader system updates KJM ^ + + +WWINLINE void DX8Wrapper::_Set_DX8_Transform(D3DTRANSFORMSTATETYPE transform, const Matrix4x4& m) +{ + WWASSERT(transform <= D3DTS_WORLD); +#if 0 // (gth) this optimization is breaking generals because they set the transform behind our backs. + if (m != DX8Transforms[transform]) +#endif + { + DX8Transforms[transform] = m; + SNAPSHOT_SAY(("DX8 - SetTransform %d [%f,%f,%f,%f][%f,%f,%f,%f][%f,%f,%f,%f][%f,%f,%f,%f]", transform, m[0][0], m[0][1], m[0][2], m[0][3], m[1][0], m[1][1], m[1][2], m[1][3], m[2][0], m[2][1], m[2][2], m[2][3], m[3][0], m[3][1], m[3][2], m[3][3])); + DX8_RECORD_MATRIX_CHANGE(); + DX8CALL(SetTransform(transform, (D3DMATRIX*)&m)); + } +} + + +WWINLINE void DX8Wrapper::_Set_DX8_Transform(D3DTRANSFORMSTATETYPE transform, const Matrix3D& m) +{ + WWASSERT(transform <= D3DTS_WORLD); + Matrix4x4 mtx(m); +#if 0 // (gth) this optimization is breaking generals because they set the transform behind our backs. + if (mtx != DX8Transforms[transform]) +#endif + { + DX8Transforms[transform] = mtx; + SNAPSHOT_SAY(("DX8 - SetTransform %d [%f,%f,%f,%f][%f,%f,%f,%f][%f,%f,%f,%f]", transform, m[0][0], m[0][1], m[0][2], m[0][3], m[1][0], m[1][1], m[1][2], m[1][3], m[2][0], m[2][1], m[2][2], m[2][3])); + DX8_RECORD_MATRIX_CHANGE(); + DX8CALL(SetTransform(transform, (D3DMATRIX*)&m)); + } +} + +WWINLINE void DX8Wrapper::_Get_DX8_Transform(D3DTRANSFORMSTATETYPE transform, Matrix4x4& m) +{ + DX8CALL(GetTransform(transform, (D3DMATRIX*)&m)); +} + +// ---------------------------------------------------------------------------- +// +// Set the index offset for the current index buffer +// +// ---------------------------------------------------------------------------- + +WWINLINE void DX8Wrapper::Set_Index_Buffer_Index_Offset(unsigned offset) +{ + if (render_state.index_base_offset == offset) return; + render_state.index_base_offset = offset; + render_state_changed |= INDEX_BUFFER_CHANGED; +} + +// ---------------------------------------------------------------------------- +// Set the fog settings. This function should be used, rather than setting the +// appropriate renderstates directly, because the shader sets some of the +// renderstates on a per-mesh / per-pass basis depending on global fog states +// (stored in the wrapper) as well as the shader settings. +// This function should be called rarely - once per scene would be appropriate. +// ---------------------------------------------------------------------------- + +WWINLINE void DX8Wrapper::Set_Fog(bool enable, const Vector3& color, float start, float end) +{ + // Set global states + FogEnable = enable; + FogColor = Convert_Color(color, 0.0f); + + // Invalidate the current shader (since the renderstates set by the shader + // depend on the global fog settings as well as the actual shader settings) + ShaderClass::Invalidate(); + + // Set renderstates which are not affected by the shader + Set_DX8_Render_State(D3DRS_FOGSTART, *(DWORD*)(&start)); + Set_DX8_Render_State(D3DRS_FOGEND, *(DWORD*)(&end)); +} + + +WWINLINE void DX8Wrapper::Set_Ambient(const Vector3& color) +{ + Ambient_Color = color; + Set_DX8_Render_State(D3DRS_AMBIENT, DX8Wrapper::Convert_Color(color, 0.0f)); +} + +// ---------------------------------------------------------------------------- +// +// Set vertex buffer to be used in the subsequent render calls. If there was +// a vertex buffer being used earlier, release the reference to it. Passing +// NULL just will release the vertex buffer. +// +// ---------------------------------------------------------------------------- + +WWINLINE void DX8Wrapper::Set_DX8_Material(const D3DMATERIAL8* mat) +{ + DX8_RECORD_MATERIAL_CHANGE(); + WWASSERT(mat); + SNAPSHOT_SAY(("DX8 - SetMaterial")); + DX8CALL(SetMaterial(mat)); +} + +WWINLINE void DX8Wrapper::Set_DX8_Light(int index, D3DLIGHT8* light) +{ + if (light) { + DX8_RECORD_LIGHT_CHANGE(); + DX8CALL(SetLight(index, light)); + DX8CALL(LightEnable(index, TRUE)); + CurrentDX8LightEnables[index] = true; + SNAPSHOT_SAY(("DX8 - SetLight %d", index)); + } + else if (CurrentDX8LightEnables[index]) { + DX8_RECORD_LIGHT_CHANGE(); + CurrentDX8LightEnables[index] = false; + DX8CALL(LightEnable(index, FALSE)); + SNAPSHOT_SAY(("DX8 - DisableLight %d", index)); + } +} + +WWINLINE void DX8Wrapper::Set_DX8_Render_State(D3DRENDERSTATETYPE state, unsigned value) +{ + // Can't monitor state changes because setShader call to GERD may change the states! + if (RenderStates[state] == value) return; + +#ifdef MESH_RENDER_SNAPSHOT_ENABLED + if (WW3D::Is_Snapshot_Activated()) { + StringClass value_name(0, true); + Get_DX8_Render_State_Value_Name(value_name, state, value); + SNAPSHOT_SAY(("DX8 - SetRenderState(state: %s, value: %s)", + Get_DX8_Render_State_Name(state), + value_name.str())); + } +#endif + + RenderStates[state] = value; + DX8CALL(SetRenderState(state, value)); + DX8_RECORD_RENDER_STATE_CHANGE(); +} + +WWINLINE void DX8Wrapper::Set_DX8_Clip_Plane(DWORD Index, CONST float* pPlane) +{ + DX8CALL(SetClipPlane(Index, pPlane)); +} + +WWINLINE void DX8Wrapper::Set_DX8_Texture_Stage_State(unsigned stage, D3DTEXTURESTAGESTATETYPE state, unsigned value) +{ + if (stage >= MAX_TEXTURE_STAGES) + { + DX8CALL(SetTextureStageState(stage, state, value)); + return; + } + + // Can't monitor state changes because setShader call to GERD may change the states! + if (TextureStageStates[stage][(unsigned int)state] == value) return; +#ifdef MESH_RENDER_SNAPSHOT_ENABLED + if (WW3D::Is_Snapshot_Activated()) { + StringClass value_name(0, true); + Get_DX8_Texture_Stage_State_Value_Name(value_name, state, value); + SNAPSHOT_SAY(("DX8 - SetTextureStageState(stage: %d, state: %s, value: %s)", + stage, + Get_DX8_Texture_Stage_State_Name(state), + value_name.str())); + } +#endif + + TextureStageStates[stage][(unsigned int)state] = value; + DX8CALL(SetTextureStageState(stage, state, value)); + DX8_RECORD_TEXTURE_STAGE_STATE_CHANGE(); +} + +WWINLINE void DX8Wrapper::Set_DX8_Texture(unsigned int stage, IDirect3DBaseTexture8* texture) +{ + if (stage >= MAX_TEXTURE_STAGES) + { + DX8CALL(SetTexture(stage, texture)); + return; + } + + if (Textures[stage] == texture) return; + + SNAPSHOT_SAY(("DX8 - SetTexture(%x) ", texture)); + + if (Textures[stage]) Textures[stage]->Release(); + Textures[stage] = texture; + if (Textures[stage]) Textures[stage]->AddRef(); + DX8CALL(SetTexture(stage, texture)); + DX8_RECORD_TEXTURE_CHANGE(); +} + +WWINLINE void DX8Wrapper::_Copy_DX8_Rects( + IDirect3DSurface8* pSourceSurface, + CONST RECT* pSourceRectsArray, + UINT cRects, + IDirect3DSurface8* pDestinationSurface, + CONST POINT* pDestPointsArray +) +{ + DX8CALL(CopyRects( + pSourceSurface, + pSourceRectsArray, + cRects, + pDestinationSurface, + pDestPointsArray)); +} + +WWINLINE Vector4 DX8Wrapper::Convert_Color(unsigned color) +{ + Vector4 col; + col[3] = ((color & 0xff000000) >> 24) / 255.0f; + col[0] = ((color & 0xff0000) >> 16) / 255.0f; + col[1] = ((color & 0xff00) >> 8) / 255.0f; + col[2] = ((color & 0xff) >> 0) / 255.0f; + // col=Vector4(1.0f,1.0f,1.0f,1.0f); + return col; +} + +#if 0 +WWINLINE unsigned int DX8Wrapper::Convert_Color(const Vector3& color, const float alpha) +{ + WWASSERT(color.X <= 1.0f); + WWASSERT(color.Y <= 1.0f); + WWASSERT(color.Z <= 1.0f); + WWASSERT(alpha <= 1.0f); + WWASSERT(color.X >= 0.0f); + WWASSERT(color.Y >= 0.0f); + WWASSERT(color.Z >= 0.0f); + WWASSERT(alpha >= 0.0f); + + return D3DCOLOR_COLORVALUE(color.X, color.Y, color.Z, alpha); +} +WWINLINE unsigned int DX8Wrapper::Convert_Color(const Vector4& color) +{ + WWASSERT(color.X <= 1.0f); + WWASSERT(color.Y <= 1.0f); + WWASSERT(color.Z <= 1.0f); + WWASSERT(color.W <= 1.0f); + WWASSERT(color.X >= 0.0f); + WWASSERT(color.Y >= 0.0f); + WWASSERT(color.Z >= 0.0f); + WWASSERT(color.W >= 0.0f); + + return D3DCOLOR_COLORVALUE(color.X, color.Y, color.Z, color.W); +} +#else + +// ---------------------------------------------------------------------------- +// +// Convert RGBA color from float vector to 32 bit integer +// Note: Color vector needs to be clamped to [0...1] range! +// +// ---------------------------------------------------------------------------- + +WWINLINE unsigned int DX8Wrapper::Convert_Color(const Vector3& color, float alpha) +{ +#if defined(_MSC_VER) && _MSC_VER < 1300 + const float scale = 255.0; + unsigned int col; + + // Multiply r, g, b and a components (0.0,...,1.0) by 255 and convert to integer. Or the integer values togerher + // such that 32 bit ingeger has AAAAAAAARRRRRRRRGGGGGGGGBBBBBBBB. + __asm + { + sub esp, 20 // space for a, r, g and b float plus fpu rounding mode + + // Store the fpu rounding mode + + fwait + fstcw[esp + 16] // store control word to stack + mov eax, [esp + 16] // load it to eax + mov edi, eax // take copy + and eax, ~(1024 | 2048) // mask out certain bits + or eax, (1024 | 2048) // or with precision control value "truncate" + sub edi, eax // did it change? + jz skip // .. if not, skip + mov[esp], eax // .. change control word + fldcw[esp] + skip: + + // Convert the color + + mov esi, dword ptr color + fld dword ptr[scale] + + fld dword ptr[esi] // r + fld dword ptr[esi + 4] // g + fld dword ptr[esi + 8] // b + fld dword ptr[alpha] // a + fld st(4) + fmul st(4), st + fmul st(3), st + fmul st(2), st + fmulp st(1), st + fistp dword ptr[esp + 0] // a + fistp dword ptr[esp + 4] // b + fistp dword ptr[esp + 8] // g + fistp dword ptr[esp + 12] // r + mov ecx, [esp] // a + mov eax, [esp + 4] // b + mov edx, [esp + 8] // g + mov ebx, [esp + 12] // r + shl ecx, 24 // a << 24 + shl ebx, 16 // r << 16 + shl edx, 8 // g << 8 + or eax, ecx // (a << 24) | b + or eax, ebx // (a << 24) | (r << 16) | b + or eax, edx // (a << 24) | (r << 16) | (g << 8) | b + + fstp st(0) + + // Restore fpu rounding mode + + cmp edi, 0 // did we change the value? + je not_changed // nope... skip now... + fwait + fldcw[esp + 16]; + not_changed: + add esp, 20 + + mov col, eax + } + return col; +#else + return color.Convert_To_ARGB(alpha); +#endif // defined(_MSC_VER) && _MSC_VER < 1300 +} + +// ---------------------------------------------------------------------------- +// +// Clamp color vector to [0...1] range +// +// ---------------------------------------------------------------------------- + +WWINLINE void DX8Wrapper::Clamp_Color(Vector4& color) +{ +#if defined(_MSC_VER) && _MSC_VER < 1300 + if (CPUDetectClass::Has_CMOV_Instruction()) { + __asm + { + mov esi, dword ptr color + + mov edx, 0x3f800000 + + mov edi, dword ptr[esi] + mov ebx, edi + sar edi, 31 + not edi // mask is now zero if negative value + and edi, ebx + cmp edi, edx // if no less than 1.0 set to 1.0 + cmovnb edi, edx + mov dword ptr[esi], edi + + mov edi, dword ptr[esi + 4] + mov ebx, edi + sar edi, 31 + not edi // mask is now zero if negative value + and edi, ebx + cmp edi, edx // if no less than 1.0 set to 1.0 + cmovnb edi, edx + mov dword ptr[esi + 4], edi + + mov edi, dword ptr[esi + 8] + mov ebx, edi + sar edi, 31 + not edi // mask is now zero if negative value + and edi, ebx + cmp edi, edx // if no less than 1.0 set to 1.0 + cmovnb edi, edx + mov dword ptr[esi + 8], edi + + mov edi, dword ptr[esi + 12] + mov ebx, edi + sar edi, 31 + not edi // mask is now zero if negative value + and edi, ebx + cmp edi, edx // if no less than 1.0 set to 1.0 + cmovnb edi, edx + mov dword ptr[esi + 12], edi + } + return; + } +#endif // defined(_MSC_VER) && _MSC_VER < 1300 + + for (int i = 0; i < 4; ++i) { + float f = (color[i] < 0.0f) ? 0.0f : color[i]; + color[i] = (f > 1.0f) ? 1.0f : f; + } +} + +// ---------------------------------------------------------------------------- +// +// Convert RGBA color from float vector to 32 bit integer +// +// ---------------------------------------------------------------------------- + +WWINLINE unsigned int DX8Wrapper::Convert_Color(const Vector4& color) +{ + return Convert_Color(reinterpret_cast(color), color[3]); +} + +WWINLINE unsigned int DX8Wrapper::Convert_Color_Clamp(const Vector4& color) +{ + Vector4 clamped_color = color; + DX8Wrapper::Clamp_Color(clamped_color); + return Convert_Color(reinterpret_cast(clamped_color), clamped_color[3]); +} + +#endif + + +WWINLINE void DX8Wrapper::Set_Alpha(const float alpha, unsigned int& color) +{ + unsigned char* component = (unsigned char*)&color; + + component[3] = 255.0f * alpha; +} + +WWINLINE void DX8Wrapper::Get_Render_State(RenderStateStruct& state) +{ + state = render_state; +} + +WWINLINE void DX8Wrapper::Get_Shader(ShaderClass& shader) +{ + shader = render_state.shader; +} + +WWINLINE void DX8Wrapper::Set_Texture(unsigned stage, TextureBaseClass* texture) +{ + WWASSERT(stage < (unsigned int)CurrentCaps->Get_Max_Textures_Per_Pass()); + if (texture == render_state.Textures[stage]) return; + REF_PTR_SET(render_state.Textures[stage], texture); + render_state_changed |= (TEXTURE0_CHANGED << stage); +} + +WWINLINE void DX8Wrapper::Set_Material(const VertexMaterialClass* material) +{ + /* if (material && render_state.material && + // !stricmp(material->Get_Name(),render_state.material->Get_Name())) { + material->Get_CRC()!=render_state.material->Get_CRC()) { + return; + } + */ + // if (material==render_state.material) { + // return; + // } + REF_PTR_SET(render_state.material, const_cast(material)); + render_state_changed |= MATERIAL_CHANGED; + SNAPSHOT_SAY(("DX8Wrapper::Set_Material(%s)", material ? material->Get_Name() : "NULL")); +} + +WWINLINE void DX8Wrapper::Set_Shader(const ShaderClass& shader) +{ + if (!ShaderClass::ShaderDirty && ((unsigned&)shader == (unsigned&)render_state.shader)) { + return; + } + render_state.shader = shader; + render_state_changed |= SHADER_CHANGED; +#ifdef MESH_RENDER_SNAPSHOT_ENABLED + StringClass str; +#endif + SNAPSHOT_SAY(("DX8Wrapper::Set_Shader(%s)", shader.Get_Description(str).str())); +} + +WWINLINE void DX8Wrapper::Set_Projection_Transform_With_Z_Bias(const Matrix4x4& matrix, float znear, float zfar) +{ + ZFar = zfar; + ZNear = znear; + ProjectionMatrix = matrix.Transpose(); + + if (!Get_Current_Caps()->Support_ZBias() && ZNear != ZFar) { + Matrix4x4 tmp = ProjectionMatrix; + float tmp_zbias = ZBias; + tmp_zbias *= (1.0f / 16.0f); + tmp_zbias *= 1.0f / (ZFar - ZNear); + tmp[2][2] -= tmp_zbias * tmp[3][2]; + DX8CALL(SetTransform(D3DTS_PROJECTION, (D3DMATRIX*)&tmp)); + } + else { + DX8CALL(SetTransform(D3DTS_PROJECTION, (D3DMATRIX*)&ProjectionMatrix)); + } +} + +WWINLINE void DX8Wrapper::Set_DX8_ZBias(int zbias) +{ + if (zbias == ZBias) return; + if (zbias > 15) zbias = 15; + if (zbias < 0) zbias = 0; + ZBias = zbias; + + if (!Get_Current_Caps()->Support_ZBias() && ZNear != ZFar) { + Matrix4x4 tmp = ProjectionMatrix; + float tmp_zbias = ZBias; + tmp_zbias *= (1.0f / 16.0f); + tmp_zbias *= 1.0f / (ZFar - ZNear); + tmp[2][2] -= tmp_zbias * tmp[3][2]; + DX8CALL(SetTransform(D3DTS_PROJECTION, (D3DMATRIX*)&tmp)); + } + else { + Set_DX8_Render_State(D3DRS_ZBIAS, ZBias); + } +} + +WWINLINE void DX8Wrapper::Set_Transform(D3DTRANSFORMSTATETYPE transform, const Matrix4x4& m) +{ + switch ((int)transform) { + case D3DTS_WORLD: + render_state.world = m.Transpose(); + render_state_changed |= (unsigned)WORLD_CHANGED; + render_state_changed &= ~(unsigned)WORLD_IDENTITY; + break; + case D3DTS_VIEW: + render_state.view = m.Transpose(); + render_state_changed |= (unsigned)VIEW_CHANGED; + render_state_changed &= ~(unsigned)VIEW_IDENTITY; + break; + case D3DTS_PROJECTION: + { + Matrix4x4 ProjectionMatrix = m.Transpose(); + ZFar = 0.0f; + ZNear = 0.0f; + DX8CALL(SetTransform(D3DTS_PROJECTION, (D3DMATRIX*)&ProjectionMatrix)); + } + break; + default: + DX8_RECORD_MATRIX_CHANGE(); + Matrix4x4 m2 = m.Transpose(); + DX8CALL(SetTransform(transform, (D3DMATRIX*)&m2)); + break; + } +} + +WWINLINE void DX8Wrapper::Set_Transform(D3DTRANSFORMSTATETYPE transform, const Matrix3D& m) +{ + Matrix4x4 m2(m); + switch ((int)transform) { + case D3DTS_WORLD: + render_state.world = m2.Transpose(); + render_state_changed |= (unsigned)WORLD_CHANGED; + render_state_changed &= ~(unsigned)WORLD_IDENTITY; + break; + case D3DTS_VIEW: + render_state.view = m2.Transpose(); + render_state_changed |= (unsigned)VIEW_CHANGED; + render_state_changed &= ~(unsigned)VIEW_IDENTITY; + break; + default: + DX8_RECORD_MATRIX_CHANGE(); + m2 = m2.Transpose(); + DX8CALL(SetTransform(transform, (D3DMATRIX*)&m2)); + break; + } +} + +WWINLINE void DX8Wrapper::Set_World_Identity() +{ + if (render_state_changed & (unsigned)WORLD_IDENTITY) return; + render_state.world.Make_Identity(); + render_state_changed |= (unsigned)WORLD_CHANGED | (unsigned)WORLD_IDENTITY; +} + +WWINLINE void DX8Wrapper::Set_View_Identity() +{ + if (render_state_changed & (unsigned)VIEW_IDENTITY) return; + render_state.view.Make_Identity(); + render_state_changed |= (unsigned)VIEW_CHANGED | (unsigned)VIEW_IDENTITY; +} + +WWINLINE bool DX8Wrapper::Is_World_Identity() +{ + return !!(render_state_changed & (unsigned)WORLD_IDENTITY); +} + +WWINLINE bool DX8Wrapper::Is_View_Identity() +{ + return !!(render_state_changed & (unsigned)VIEW_IDENTITY); +} + +WWINLINE void DX8Wrapper::Get_Transform(D3DTRANSFORMSTATETYPE transform, Matrix4x4& m) +{ + D3DMATRIX mat; + + switch ((int)transform) { + case D3DTS_WORLD: + if (render_state_changed & WORLD_IDENTITY) m.Make_Identity(); + else m = render_state.world.Transpose(); + break; + case D3DTS_VIEW: + if (render_state_changed & VIEW_IDENTITY) m.Make_Identity(); + else m = render_state.view.Transpose(); + break; + default: + DX8CALL(GetTransform(transform, &mat)); + m = *(Matrix4x4*)&mat; + m = m.Transpose(); + break; + } +} + +WWINLINE const D3DLIGHT8& DX8Wrapper::Peek_Light(unsigned index) +{ + return render_state.Lights[index];; +} + +WWINLINE bool DX8Wrapper::Is_Light_Enabled(unsigned index) +{ + return render_state.LightEnable[index]; +} + + +WWINLINE void DX8Wrapper::Set_Render_State(const RenderStateStruct& state) +{ + int i; + + if (render_state.index_buffer) { + render_state.index_buffer->Release_Engine_Ref(); + } + + for (i = 0; i < MAX_VERTEX_STREAMS; ++i) + { + if (render_state.vertex_buffers[i]) + { + render_state.vertex_buffers[i]->Release_Engine_Ref(); + } + } + + render_state = state; + render_state_changed = 0xffffffff; + + if (render_state.index_buffer) { + render_state.index_buffer->Add_Engine_Ref(); + } + + for (i = 0; i < MAX_VERTEX_STREAMS; ++i) + { + if (render_state.vertex_buffers[i]) + { + render_state.vertex_buffers[i]->Add_Engine_Ref(); + } + } +} + +WWINLINE void DX8Wrapper::Release_Render_State() +{ + int i; + + if (render_state.index_buffer) { + render_state.index_buffer->Release_Engine_Ref(); + } + + for (i = 0; i < MAX_VERTEX_STREAMS; ++i) { + if (render_state.vertex_buffers[i]) { + render_state.vertex_buffers[i]->Release_Engine_Ref(); + } + } + + for (i = 0; i < MAX_VERTEX_STREAMS; ++i) { + REF_PTR_RELEASE(render_state.vertex_buffers[i]); + } + REF_PTR_RELEASE(render_state.index_buffer); + REF_PTR_RELEASE(render_state.material); + + + for (i = 0; i < MAX_TEXTURE_STAGES; ++i) + { + REF_PTR_RELEASE(render_state.Textures[i]); + } +} + + +WWINLINE RenderStateStruct::RenderStateStruct() + : + material(0), + index_buffer(0) +{ + unsigned i; + for (i = 0; i < MAX_VERTEX_STREAMS; ++i) vertex_buffers[i] = 0; + for (i = 0; i < MAX_TEXTURE_STAGES; ++i) Textures[i] = 0; + //lightsHash = (unsigned)this; +} + +WWINLINE RenderStateStruct::~RenderStateStruct() +{ + unsigned i; + REF_PTR_RELEASE(material); + for (i = 0; i < MAX_VERTEX_STREAMS; ++i) { + REF_PTR_RELEASE(vertex_buffers[i]); + } + REF_PTR_RELEASE(index_buffer); + + for (i = 0; i < MAX_TEXTURE_STAGES; ++i) + { + REF_PTR_RELEASE(Textures[i]); + } +} + + +WWINLINE unsigned flimby(char* name, unsigned crib) +{ + unsigned lnt prevVer = 0x00000000; + unsigned D3D2_BASE_VEC nextVer = 0; + for (unsigned t = 0; t < crib; ++t) + { + (D3D2_BASE_VEC)nextVer += name[t]; + (D3D2_BASE_VEC)nextVer %= 32; + (D3D2_BASE_VEC)nextVer--; + (lnt)prevVer ^= (1 << (D3D2_BASE_VEC)prevVer); + } + return (lnt)prevVer; +} + +WWINLINE RenderStateStruct& RenderStateStruct::operator= (const RenderStateStruct& src) +{ + unsigned i; + REF_PTR_SET(material, src.material); + for (i = 0; i < MAX_VERTEX_STREAMS; ++i) { + REF_PTR_SET(vertex_buffers[i], src.vertex_buffers[i]); + } + REF_PTR_SET(index_buffer, src.index_buffer); + + for (i = 0; i < MAX_TEXTURE_STAGES; ++i) + { + REF_PTR_SET(Textures[i], src.Textures[i]); + } + + LightEnable[0] = src.LightEnable[0]; + LightEnable[1] = src.LightEnable[1]; + LightEnable[2] = src.LightEnable[2]; + LightEnable[3] = src.LightEnable[3]; + if (LightEnable[0]) { + Lights[0] = src.Lights[0]; + if (LightEnable[1]) { + Lights[1] = src.Lights[1]; + if (LightEnable[2]) { + Lights[2] = src.Lights[2]; + if (LightEnable[3]) { + Lights[3] = src.Lights[3]; + } + } + } + + + //lightsHash = flimby((char*)(&Lights[0]), sizeof(D3DLIGHT8)-1 ); + + } + + shader = src.shader; + world = src.world; + view = src.view; + for (i = 0; i < MAX_VERTEX_STREAMS; ++i) { + vertex_buffer_types[i] = src.vertex_buffer_types[i]; + } + index_buffer_type = src.index_buffer_type; + vba_offset = src.vba_offset; + vba_count = src.vba_count; + iba_offset = src.iba_offset; + index_base_offset = src.index_base_offset; + + return *this; +} + + +#endif diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8caps.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8caps.cpp index c83542d6be8..e9a4735ce6d 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8caps.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8caps.cpp @@ -547,6 +547,8 @@ void DX8Caps::Compute_Caps(WW3DFormat display_format, const D3DADAPTER_IDENTIFIE SupportNPatches=false; } + SupportZBias = ((Caps.RasterCaps & D3DPRASTERCAPS_ZBIAS) == D3DPRASTERCAPS_ZBIAS); + if ((caps.TextureOpCaps&D3DTEXOPCAPS_DOTPRODUCT3)==D3DTEXOPCAPS_DOTPRODUCT3) { SupportDot3=true; diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8caps.h b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8caps.h index e3206918075..7c1579f2680 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8caps.h +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8caps.h @@ -217,6 +217,7 @@ class DX8Caps bool Support_NPatches() const { return SupportNPatches; } bool Support_Bump_Envmap() const { return SupportBumpEnvmap; } bool Support_Bump_Envmap_Luminance() const { return SupportBumpEnvmapLuminance; } + bool Support_ZBias() const { return SupportZBias; } bool Support_Dot3() const { return SupportDot3; } int Get_Max_Textures_Per_Pass() const { return MaxTexturesPerPass; } @@ -281,6 +282,7 @@ class DX8Caps bool SupportTextureFormat[WW3D_FORMAT_COUNT]; bool SupportRenderToTextureFormat[WW3D_FORMAT_COUNT]; bool SupportDepthStencilFormat[WW3D_ZFORMAT_COUNT]; + bool SupportZBias; bool SupportDot3; int MaxTexturesPerPass; int VertexShaderVersion; diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8renderer.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8renderer.cpp index 85d831483ac..f6a22d1f8ef 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8renderer.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8renderer.cpp @@ -186,7 +186,7 @@ inline static bool Equal_Material(const VertexMaterialClass* mat1,const VertexMa DX8TextureCategoryClass::DX8TextureCategoryClass( DX8FVFCategoryContainer* container_, TextureClass** texs, - ShaderClass shd, + ShaderClass shd, VertexMaterialClass* mat, int pass_) : @@ -196,13 +196,13 @@ DX8TextureCategoryClass::DX8TextureCategoryClass( material(mat), container(container_) { - WWASSERT(pass>=0); - WWASSERT(pass= 0); + WWASSERT(pass < DX8FVFCategoryContainer::MAX_PASSES); - - for (int a=0;aAdd_Ref(); @@ -1175,7 +1175,8 @@ void DX8FVFCategoryContainer::Generate_Texture_Categories(Vertex_Split_Table& sp for (int i=0;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:: /VSS_Sync/ww3d2/dx8wrapper.h $* - * * - * Original Author:: Jani Penttinen * - * * - * $Author:: Vss_sync $* - * * - * $Modtime:: 8/29/01 7:29p $* - * * - * $Revision:: 76 $* - * * - *---------------------------------------------------------------------------------------------* - * Functions: * - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - -#if defined(_MSC_VER) -#pragma once -#endif - -#ifndef DX8_WRAPPER_H -#define DX8_WRAPPER_H - -#include "always.h" -#include "dllist.h" -#include "d3d8.h" -#include "matrix4.h" -#include "statistics.h" -#include "wwstring.h" -#include "lightenvironment.h" -#include "shader.h" -#include "vector4.h" -#include "cpudetect.h" -#include "dx8caps.h" - -#include "texture.h" -#include "dx8vertexbuffer.h" -#include "dx8indexbuffer.h" -#include "vertmaterial.h" - -/* -** Registry value names -*/ -#define VALUE_NAME_RENDER_DEVICE_NAME "RenderDeviceName" -#define VALUE_NAME_RENDER_DEVICE_WIDTH "RenderDeviceWidth" -#define VALUE_NAME_RENDER_DEVICE_HEIGHT "RenderDeviceHeight" -#define VALUE_NAME_RENDER_DEVICE_DEPTH "RenderDeviceDepth" -#define VALUE_NAME_RENDER_DEVICE_WINDOWED "RenderDeviceWindowed" -#define VALUE_NAME_RENDER_DEVICE_TEXTURE_DEPTH "RenderDeviceTextureDepth" - -const unsigned MAX_TEXTURE_STAGES=2; -const unsigned MAX_VERTEX_STREAMS=2; -const unsigned MAX_VERTEX_SHADER_CONSTANTS=96; -const unsigned MAX_PIXEL_SHADER_CONSTANTS=8; -const unsigned MAX_SHADOW_MAPS=1; - -#define prevVer -#define nextVer - - -enum { - BUFFER_TYPE_DX8, - BUFFER_TYPE_SORTING, - BUFFER_TYPE_DYNAMIC_DX8, - BUFFER_TYPE_DYNAMIC_SORTING, - BUFFER_TYPE_INVALID -}; - -class VertexMaterialClass; -class CameraClass; -class LightEnvironmentClass; -class RenderDeviceDescClass; -class VertexBufferClass; -class DynamicVBAccessClass; -class IndexBufferClass; -class DynamicIBAccessClass; -class TextureClass; -class LightClass; -class SurfaceClass; - -class ZTextureClass; - -#define DX8_RECORD_MATRIX_CHANGE() matrix_changes++ -#define DX8_RECORD_MATERIAL_CHANGE() material_changes++ -#define DX8_RECORD_VERTEX_BUFFER_CHANGE() vertex_buffer_changes++ -#define DX8_RECORD_INDEX_BUFFER_CHANGE() index_buffer_changes++ -#define DX8_RECORD_LIGHT_CHANGE() light_changes++ -#define DX8_RECORD_TEXTURE_CHANGE() texture_changes++ -#define DX8_RECORD_RENDER_STATE_CHANGE() render_state_changes++ -#define DX8_RECORD_TEXTURE_STAGE_STATE_CHANGE() texture_stage_state_changes++ -#define DX8_RECORD_DRAW_CALLS() draw_calls++ - -extern unsigned number_of_DX8_calls; -extern bool _DX8SingleThreaded; - -void DX8_Assert(); -void Log_DX8_ErrorCode(unsigned res); - -WWINLINE void DX8_ErrorCode(unsigned res) -{ - if (res==D3D_OK) return; - Log_DX8_ErrorCode(res); -} - -#ifdef WWDEBUG -#define DX8CALL_HRES(x,res) DX8_Assert(); res = DX8Wrapper::_Get_D3D_Device8()->x; DX8_ErrorCode(res); number_of_DX8_calls++; -#define DX8CALL(x) DX8_Assert(); DX8_ErrorCode(DX8Wrapper::_Get_D3D_Device8()->x); number_of_DX8_calls++; -#define DX8CALL_D3D(x) DX8_Assert(); DX8_ErrorCode(DX8Wrapper::_Get_D3D8()->x); number_of_DX8_calls++; -#define DX8_THREAD_ASSERT() if (_DX8SingleThreaded) { WWASSERT_PRINT(DX8Wrapper::_Get_Main_Thread_ID()==ThreadClass::_Get_Current_Thread_ID(),"DX8Wrapper::DX8 calls must be called from the main thread!"); } -#else -#define DX8CALL_HRES(x,res) res = DX8Wrapper::_Get_D3D_Device8()->x; number_of_DX8_calls++; -#define DX8CALL(x) DX8Wrapper::_Get_D3D_Device8()->x; number_of_DX8_calls++; -#define DX8CALL_D3D(x) DX8Wrapper::_Get_D3D8()->x; number_of_DX8_calls++; -#define DX8_THREAD_ASSERT() ; -#endif - - -#define no_EXTENDED_STATS -// EXTENDED_STATS collects additional timing statistics by turning off parts -// of the 3D drawing system (terrain, objects, etc.) -#ifdef EXTENDED_STATS -class DX8_Stats -{ -public: - bool m_showingStats; - bool m_disableTerrain; - bool m_disableWater; - bool m_disableObjects; - bool m_disableOverhead; - bool m_disableConsole; - int m_debugLinesToShow; - int m_sleepTime; -public: - DX8_Stats::DX8_Stats(void) { - m_disableConsole = m_showingStats = m_disableTerrain = m_disableWater = m_disableOverhead = m_disableObjects = false; - m_sleepTime = 0; - m_debugLinesToShow = -1; // -1 means show all expected lines of output - } -}; -#endif - - -// This virtual interface was added for the Generals RTS. -// It is called before resetting the dx8 device to ensure -// that all dx8 resources are released. Otherwise reset fails. jba. -class DX8_CleanupHook -{ -public: - virtual void ReleaseResources(void)=0; - virtual void ReAcquireResources(void)=0; -}; - - -struct RenderStateStruct -{ - ShaderClass shader; - VertexMaterialClass* material; - TextureBaseClass * Textures[MAX_TEXTURE_STAGES]; - D3DLIGHT8 Lights[4]; - bool LightEnable[4]; - //unsigned lightsHash; - Matrix4x4 world; - Matrix4x4 view; - unsigned vertex_buffer_types[MAX_VERTEX_STREAMS]; - unsigned index_buffer_type; - unsigned short vba_offset; - unsigned short vba_count; - unsigned short iba_offset; - VertexBufferClass* vertex_buffers[MAX_VERTEX_STREAMS]; - IndexBufferClass* index_buffer; - unsigned short index_base_offset; - - RenderStateStruct(); - ~RenderStateStruct(); - - RenderStateStruct& operator= (const RenderStateStruct& src); -}; - -/** -** DX8Wrapper -** -** DX8 interface wrapper class. This encapsulates the DX8 interface; adding redundant state -** detection, stat tracking, etc etc. In general, we will wrap all DX8 calls with at least -** an WWINLINE function so that we can add stat tracking, etc if needed. Direct access to the -** D3D device will require "friend" status and should be granted only in extreme circumstances :-) -*/ -class DX8Wrapper -{ - enum ChangedStates { - WORLD_CHANGED = 1<<0, - VIEW_CHANGED = 1<<1, - LIGHT0_CHANGED = 1<<2, - LIGHT1_CHANGED = 1<<3, - LIGHT2_CHANGED = 1<<4, - LIGHT3_CHANGED = 1<<5, - TEXTURE0_CHANGED= 1<<6, - TEXTURE1_CHANGED= 1<<7, - TEXTURE2_CHANGED= 1<<8, - TEXTURE3_CHANGED= 1<<9, - MATERIAL_CHANGED= 1<<14, - SHADER_CHANGED = 1<<15, - VERTEX_BUFFER_CHANGED = 1<<16, - INDEX_BUFFER_CHANGED = 1 << 17, - WORLD_IDENTITY= 1<<18, - VIEW_IDENTITY= 1<<19, - - TEXTURES_CHANGED= - TEXTURE0_CHANGED|TEXTURE1_CHANGED|TEXTURE2_CHANGED|TEXTURE3_CHANGED, - LIGHTS_CHANGED= - LIGHT0_CHANGED|LIGHT1_CHANGED|LIGHT2_CHANGED|LIGHT3_CHANGED, - }; - - static void Draw_Sorting_IB_VB( - unsigned primitive_type, - unsigned short start_index, - unsigned short polygon_count, - unsigned short min_vertex_index, - unsigned short vertex_count); - - static void Draw( - unsigned primitive_type, - unsigned short start_index, - unsigned short polygon_count, - unsigned short min_vertex_index=0, - unsigned short vertex_count=0); - -public: -#ifdef EXTENDED_STATS - static DX8_Stats stats; -#endif - - static bool Init(void * hwnd, bool lite = false); - static void Shutdown(void); - - static void SetCleanupHook(DX8_CleanupHook *pCleanupHook) {m_pCleanupHook = pCleanupHook;}; - /* - ** Some WW3D sub-systems need to be initialized after the device is created and shutdown - ** before the device is released. - */ - static void Do_Onetime_Device_Dependent_Inits(void); - static void Do_Onetime_Device_Dependent_Shutdowns(void); - - static bool Is_Device_Lost() { return IsDeviceLost; } - static bool Is_Initted(void) { return IsInitted; } - - static bool Has_Stencil (void); - static void Get_Format_Name(unsigned int format, StringClass *tex_format); - - /* - ** Rendering - */ - static void Begin_Scene(void); - static void End_Scene(bool flip_frame = true); - - // Flip until the primary buffer is visible. - static void Flip_To_Primary(void); - - static void Clear(bool clear_color, bool clear_z_stencil, const Vector3 &color, float dest_alpha=0.0f, float z=1.0f, unsigned int stencil=0); - - static void Set_Viewport(CONST D3DVIEWPORT8* pViewport); - - static void Set_Vertex_Buffer(const VertexBufferClass* vb, unsigned stream = 0); - static void Set_Vertex_Buffer(const DynamicVBAccessClass& vba); - static void Set_Index_Buffer(const IndexBufferClass* ib,unsigned short index_base_offset); - static void Set_Index_Buffer(const DynamicIBAccessClass& iba,unsigned short index_base_offset); - static void Set_Index_Buffer_Index_Offset(unsigned offset); - - static void Get_Render_State(RenderStateStruct& state); - static void Set_Render_State(const RenderStateStruct& state); - static void Release_Render_State(); - - static void Set_DX8_Material(const D3DMATERIAL8* mat); - - static void Set_Gamma(float gamma,float bright,float contrast,bool calibrate=true,bool uselimit=true); - - // Set_ and Get_Transform() functions take the matrix in Westwood convention format. - - static void Set_Transform(D3DTRANSFORMSTATETYPE transform,const Matrix4x4& m); - static void Set_Transform(D3DTRANSFORMSTATETYPE transform,const Matrix3D& m); - static void Get_Transform(D3DTRANSFORMSTATETYPE transform, Matrix4x4& m); - static void Set_World_Identity(); - static void Set_View_Identity(); - static bool Is_World_Identity(); - static bool Is_View_Identity(); - - // Note that *_DX8_Transform() functions take the matrix in DX8 format - transposed from Westwood convention. - - static void _Set_DX8_Transform(D3DTRANSFORMSTATETYPE transform,const Matrix4x4& m); - static void _Set_DX8_Transform(D3DTRANSFORMSTATETYPE transform,const Matrix3D& m); - static void _Get_DX8_Transform(D3DTRANSFORMSTATETYPE transform, Matrix4x4& m); - - static void Set_DX8_Light(int index,D3DLIGHT8* light); - static void Set_DX8_Render_State(D3DRENDERSTATETYPE state, unsigned value); - static void Set_DX8_Clip_Plane(DWORD Index, CONST float* pPlane); - static void Set_DX8_Texture_Stage_State(unsigned stage, D3DTEXTURESTAGESTATETYPE state, unsigned value); - static void Set_DX8_Texture(unsigned int stage, IDirect3DBaseTexture8* texture); - static void Set_Light_Environment(LightEnvironmentClass* light_env); - static LightEnvironmentClass* Get_Light_Environment() { return Light_Environment; } - static void Set_Fog(bool enable, const Vector3 &color, float start, float end); - - static WWINLINE const D3DLIGHT8& Peek_Light(unsigned index); - static WWINLINE bool Is_Light_Enabled(unsigned index); - - static bool Validate_Device(void); - - // Deferred - - static void Set_Shader(const ShaderClass& shader); - static void Get_Shader(ShaderClass& shader); - static void Set_Texture(unsigned stage,TextureBaseClass* texture); - static void Set_Material(const VertexMaterialClass* material); - static void Set_Light(unsigned index,const D3DLIGHT8* light); - static void Set_Light(unsigned index,const LightClass &light); - - static void Apply_Render_State_Changes(); // Apply deferred render state changes (will be called automatically by Draw...) - - static void Draw_Triangles( - unsigned buffer_type, - unsigned short start_index, - unsigned short polygon_count, - unsigned short min_vertex_index, - unsigned short vertex_count); - static void Draw_Triangles( - unsigned short start_index, - unsigned short polygon_count, - unsigned short min_vertex_index, - unsigned short vertex_count); - static void Draw_Strip( - unsigned short start_index, - unsigned short index_count, - unsigned short min_vertex_index, - unsigned short vertex_count); - - /* - ** 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, - unsigned int height, - WW3DFormat format, - MipCountType mip_level_count, - D3DPOOL pool=D3DPOOL_MANAGED, - bool rendertarget=false - ); - static IDirect3DTexture8 * _Create_DX8_Texture(const char *filename, MipCountType mip_level_count); - static IDirect3DTexture8 * _Create_DX8_Texture(IDirect3DSurface8 *surface, MipCountType mip_level_count); - - static IDirect3DSurface8 * _Create_DX8_Surface(unsigned int width, unsigned int height, WW3DFormat format); - static IDirect3DSurface8 * _Create_DX8_Surface(const char *filename); - static IDirect3DSurface8 * _Get_DX8_Front_Buffer(); - static SurfaceClass * _Get_DX8_Back_Buffer(unsigned int num=0); - - static void _Copy_DX8_Rects( - IDirect3DSurface8* pSourceSurface, - CONST RECT* pSourceRectsArray, - UINT cRects, - IDirect3DSurface8* pDestinationSurface, - CONST POINT* pDestPointsArray - ); - - static void _Update_Texture(TextureClass *system, TextureClass *video); - static void Flush_DX8_Resource_Manager(unsigned int bytes=0); - static unsigned int Get_Free_Texture_RAM(); - - static unsigned _Get_Main_Thread_ID() { return _MainThreadID; } - static const D3DADAPTER_IDENTIFIER8& Get_Current_Adapter_Identifier() { return CurrentAdapterIdentifier; } - - /* - ** Statistics - */ - static void Begin_Statistics(); - static void End_Statistics(); - static unsigned Get_Last_Frame_Matrix_Changes(); - static unsigned Get_Last_Frame_Material_Changes(); - static unsigned Get_Last_Frame_Vertex_Buffer_Changes(); - static unsigned Get_Last_Frame_Index_Buffer_Changes(); - static unsigned Get_Last_Frame_Light_Changes(); - static unsigned Get_Last_Frame_Texture_Changes(); - static unsigned Get_Last_Frame_Render_State_Changes(); - static unsigned Get_Last_Frame_Texture_Stage_State_Changes(); - static unsigned Get_Last_Frame_DX8_Calls(); - static unsigned Get_Last_Frame_Draw_Calls(); - - static unsigned long Get_FrameCount(void); - - // Needed by shader class - static bool Get_Fog_Enable() { return FogEnable; } - static D3DCOLOR Get_Fog_Color() { return FogColor; } - - // Utilities - static Vector4 Convert_Color(unsigned color); - static unsigned int Convert_Color(const Vector4& color); - static unsigned int Convert_Color(const Vector3& color, const float alpha); - static void Clamp_Color(Vector4& color); - static unsigned int Convert_Color_Clamp(const Vector4& color); - - static void Set_Alpha (const float alpha, unsigned int &color); - - static void _Enable_Triangle_Draw(bool enable) { _EnableTriangleDraw=enable; } - static bool _Is_Triangle_Draw_Enabled() { return _EnableTriangleDraw; } - - /* - ** Additional swap chain interface - ** - ** Use this interface to render to multiple windows (in windowed mode). - ** To render to an additional window, the sequence of calls should look - ** something like this: - ** - ** DX8Wrapper::Set_Render_Target (swap_chain_ptr); - ** - ** WW3D::Begin_Render (true, true, Vector3 (0, 0, 0)); - ** WW3D::Render (scene, camera, FALSE, FALSE); - ** WW3D::End_Render (); - ** - ** swap_chain_ptr->Present (NULL, NULL, NULL, NULL); - ** - ** DX8Wrapper::Set_Render_Target ((IDirect3DSurface8 *)NULL); - ** - */ - static IDirect3DSwapChain8 * Create_Additional_Swap_Chain (HWND render_window); - - /* - ** 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, WW3DFormat format = WW3D_FORMAT_UNKNOWN); - - // 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_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(IDirect3DSwapChain8* swap_chain); - static bool Is_Render_To_Texture(void) { return IsRenderToTexture; } - - // shader system udpates KJM v - static void Apply_Default_State(); - - static void Set_Vertex_Shader(DWORD vertex_shader); - static void Set_Pixel_Shader(DWORD pixel_shader); - - static void Set_Vertex_Shader_Constant(int reg, const void* data, int count); - static void Set_Pixel_Shader_Constant(int reg, const void* data, int count); - - static ZTextureClass* Shadow_Map[MAX_SHADOW_MAPS]; - - static DWORD Get_Vertex_Processing_Behavior() { return Vertex_Processing_Behavior; } - - // Needed by scene lighting class - static void Set_Ambient(const Vector3& color); - static const Vector3& Get_Ambient() { return Ambient_Color; } - // shader system updates KJM ^ - - - - - static IDirect3DDevice8* _Get_D3D_Device8() { return D3DDevice; } - static IDirect3D8* _Get_D3D8() { return D3DInterface; } - /// Returns the display format - added by TR for video playback - not part of W3D - static WW3DFormat getBackBufferFormat( void ); - static bool Reset_Device(bool reload_assets=true); - - static const DX8Caps* Get_Current_Caps() { WWASSERT(CurrentCaps); return CurrentCaps; } - - static bool Registry_Save_Render_Device( const char * sub_key ); - static bool Registry_Load_Render_Device( const char * sub_key, bool resize_window ); - - static const char* Get_DX8_Render_State_Name(D3DRENDERSTATETYPE state); - static const char* Get_DX8_Texture_Stage_State_Name(D3DTEXTURESTAGESTATETYPE state); - static unsigned Get_DX8_Render_State(D3DRENDERSTATETYPE state) { return RenderStates[state]; } - - // Names of the specific values of render states and texture stage states - static void Get_DX8_Texture_Stage_State_Value_Name(StringClass& name, D3DTEXTURESTAGESTATETYPE state, unsigned value); - static void Get_DX8_Render_State_Value_Name(StringClass& name, D3DRENDERSTATETYPE state, unsigned value); - - static const char* Get_DX8_Texture_Address_Name(unsigned value); - static const char* Get_DX8_Texture_Filter_Name(unsigned value); - static const char* Get_DX8_Texture_Arg_Name(unsigned value); - static const char* Get_DX8_Texture_Op_Name(unsigned value); - static const char* Get_DX8_Texture_Transform_Flag_Name(unsigned value); - static const char* Get_DX8_ZBuffer_Type_Name(unsigned value); - static const char* Get_DX8_Fill_Mode_Name(unsigned value); - static const char* Get_DX8_Shade_Mode_Name(unsigned value); - static const char* Get_DX8_Blend_Name(unsigned value); - static const char* Get_DX8_Cull_Mode_Name(unsigned value); - static const char* Get_DX8_Cmp_Func_Name(unsigned value); - static const char* Get_DX8_Fog_Mode_Name(unsigned value); - static const char* Get_DX8_Stencil_Op_Name(unsigned value); - static const char* Get_DX8_Material_Source_Name(unsigned value); - static const char* Get_DX8_Vertex_Blend_Flag_Name(unsigned value); - static const char* Get_DX8_Patch_Edge_Style_Name(unsigned value); - static const char* Get_DX8_Debug_Monitor_Token_Name(unsigned value); - static const char* Get_DX8_Blend_Op_Name(unsigned value); - - static void Invalidate_Cached_Render_States(void); - - static void Set_Draw_Polygon_Low_Bound_Limit(unsigned n) { DrawPolygonLowBoundLimit=n; } - -protected: - - static bool Create_Device(void); - static void Release_Device(void); - - static void Reset_Statistics(); - static void Enumerate_Devices(); - static void Set_Default_Global_Render_States(void); - - /* - ** Device Selection Code. - ** For backward compatibility, the public interface for these functions is in the ww3d. - ** header file. These functions are protected so that we aren't exposing two interfaces. - */ - static bool Set_Any_Render_Device(void); - static bool Set_Render_Device(const char * dev_name,int width=-1,int height=-1,int bits=-1,int windowed=-1,bool resize_window=false); - static bool Set_Render_Device(int dev=-1,int resx=-1,int resy=-1,int bits=-1,int windowed=-1,bool resize_window = false, bool reset_device = false, bool restore_assets=true); - static bool Set_Next_Render_Device(void); - static bool Toggle_Windowed(void); - - static int Get_Render_Device_Count(void); - static int Get_Render_Device(void); - static const RenderDeviceDescClass & Get_Render_Device_Desc(int deviceidx); - static const char * Get_Render_Device_Name(int device_index); - static bool Set_Device_Resolution(int width=-1,int height=-1,int bits=-1,int windowed=-1, bool resize_window=false); - static void Get_Device_Resolution(int & set_w,int & set_h,int & set_bits,bool & set_windowed); - static void Get_Render_Target_Resolution(int & set_w,int & set_h,int & set_bits,bool & set_windowed); - static int Get_Device_Resolution_Width(void) { return ResolutionWidth; } - static int Get_Device_Resolution_Height(void) { return ResolutionHeight; } - - static bool Registry_Save_Render_Device( const char *sub_key, int device, int width, int height, int depth, bool windowed, int texture_depth); - static bool Registry_Load_Render_Device( const char * sub_key, char *device, int device_len, int &width, int &height, int &depth, int &windowed, int &texture_depth); - static bool Is_Windowed(void) { return IsWindowed; } - - static void Set_Texture_Bitdepth(int depth) { WWASSERT(depth==16 || depth==32); TextureBitDepth = depth; } - static int Get_Texture_Bitdepth(void) { return TextureBitDepth; } - - static void Set_Swap_Interval(int swap); - static int Get_Swap_Interval(void); - static void Set_Polygon_Mode(int mode); - - /* - ** Internal functions - */ - static void Resize_And_Position_Window(); - static bool Find_Color_And_Z_Mode(int resx,int resy,int bitdepth,D3DFORMAT * set_colorbuffer,D3DFORMAT * set_backbuffer, D3DFORMAT * set_zmode); - static bool Find_Color_Mode(D3DFORMAT colorbuffer, int resx, int resy, UINT *mode); - static bool Find_Z_Mode(D3DFORMAT colorbuffer,D3DFORMAT backbuffer, D3DFORMAT *zmode); - static bool Test_Z_Mode(D3DFORMAT colorbuffer,D3DFORMAT backbuffer, D3DFORMAT zmode); - static void Compute_Caps(WW3DFormat display_format); - - /* - ** Protected Member Variables - */ - - static DX8_CleanupHook *m_pCleanupHook; - - static RenderStateStruct render_state; - static unsigned render_state_changed; - static Matrix4x4 DX8Transforms[D3DTS_WORLD+1]; - - static bool IsInitted; - static bool IsDeviceLost; - static void * Hwnd; - static unsigned _MainThreadID; - - static bool _EnableTriangleDraw; - - static int CurRenderDevice; - static int ResolutionWidth; - static int ResolutionHeight; - static int BitDepth; - static int TextureBitDepth; - static bool IsWindowed; - static D3DFORMAT DisplayFormat; - - static D3DMATRIX old_world; - static D3DMATRIX old_view; - static D3DMATRIX old_prj; - - // shader system updates KJM v - static DWORD Vertex_Shader; - static DWORD Pixel_Shader; - - static Vector4 Vertex_Shader_Constants[MAX_VERTEX_SHADER_CONSTANTS]; - static Vector4 Pixel_Shader_Constants[MAX_PIXEL_SHADER_CONSTANTS]; - - static LightEnvironmentClass* Light_Environment; - static RenderInfoClass* Render_Info; - - static DWORD Vertex_Processing_Behavior; - static Vector3 Ambient_Color; - // shader system updates KJM ^ - - static bool world_identity; - static unsigned RenderStates[256]; - static unsigned TextureStageStates[MAX_TEXTURE_STAGES][32]; - static IDirect3DBaseTexture8 * Textures[MAX_TEXTURE_STAGES]; - - // These fog settings are constant for all objects in a given scene, - // unlike the matching renderstates which vary based on shader settings. - static bool FogEnable; - static D3DCOLOR FogColor; - - static unsigned matrix_changes; - static unsigned material_changes; - static unsigned vertex_buffer_changes; - static unsigned index_buffer_changes; - static unsigned light_changes; - static unsigned texture_changes; - static unsigned render_state_changes; - static unsigned texture_stage_state_changes; - static unsigned draw_calls; - static bool CurrentDX8LightEnables[4]; - - static unsigned long FrameCount; - - static DX8Caps* CurrentCaps; - - static D3DADAPTER_IDENTIFIER8 CurrentAdapterIdentifier; - - static IDirect3D8 * D3DInterface; //d3d8; - static IDirect3DDevice8 * D3DDevice; //d3ddevice8; - - static IDirect3DSurface8 * CurrentRenderTarget; - static IDirect3DSurface8* CurrentDepthBuffer; - static IDirect3DSurface8 * DefaultRenderTarget; - static IDirect3DSurface8* DefaultDepthBuffer; - static unsigned DrawPolygonLowBoundLimit; - - static bool IsRenderToTexture; - - static int ZBias; - static float ZNear; - static float ZFar; - static Matrix4x4 ProjectionMatrix; - - friend void DX8_Assert(); - friend class WW3D; - friend class DX8IndexBufferClass; - friend class DX8VertexBufferClass; -}; - -// shader system updates KJM v -WWINLINE void DX8Wrapper::Set_Vertex_Shader(DWORD vertex_shader) -{ -#if 0 //(gth) some code is bypassing this acessor function so we can't count on this variable... - // may be incorrect if shaders are created and destroyed dynamically - if (Vertex_Shader==vertex_shader) return; -#endif - - Vertex_Shader=vertex_shader; - DX8CALL(SetVertexShader(Vertex_Shader)); -} - -WWINLINE void DX8Wrapper::Set_Pixel_Shader(DWORD pixel_shader) -{ - // may be incorrect if shaders are created and destroyed dynamically - if (Pixel_Shader==pixel_shader) return; - - Pixel_Shader=pixel_shader; - DX8CALL(SetPixelShader(Pixel_Shader)); -} - -WWINLINE void DX8Wrapper::Set_Vertex_Shader_Constant(int reg, const void* data, int count) -{ - int memsize=sizeof(Vector4)*count; - - // may be incorrect if shaders are created and destroyed dynamically - if (memcmp(data, &Vertex_Shader_Constants[reg],memsize)==0) return; - - memcpy(&Vertex_Shader_Constants[reg],data,memsize); - DX8CALL(SetVertexShaderConstant(reg,data,count)); -} - -WWINLINE void DX8Wrapper::Set_Pixel_Shader_Constant(int reg, const void* data, int count) -{ - int memsize=sizeof(Vector4)*count; - - // may be incorrect if shaders are created and destroyed dynamically - if (memcmp(data, &Pixel_Shader_Constants[reg],memsize)==0) return; - - memcpy(&Pixel_Shader_Constants[reg],data,memsize); - DX8CALL(SetPixelShaderConstant(reg,data,count)); -} -// shader system updates KJM ^ - - -WWINLINE void DX8Wrapper::_Set_DX8_Transform(D3DTRANSFORMSTATETYPE transform,const Matrix4x4& m) -{ - WWASSERT(transform<=D3DTS_WORLD); -#if 0 // (gth) this optimization is breaking generals because they set the transform behind our backs. - if (m!=DX8Transforms[transform]) -#endif - { - DX8Transforms[transform]=m; - SNAPSHOT_SAY(("DX8 - SetTransform %d [%f,%f,%f,%f][%f,%f,%f,%f][%f,%f,%f,%f][%f,%f,%f,%f]",transform,m[0][0],m[0][1],m[0][2],m[0][3],m[1][0],m[1][1],m[1][2],m[1][3],m[2][0],m[2][1],m[2][2],m[2][3],m[3][0],m[3][1],m[3][2],m[3][3])); - DX8_RECORD_MATRIX_CHANGE(); - DX8CALL(SetTransform(transform,(D3DMATRIX*)&m)); - } -} - - -WWINLINE void DX8Wrapper::_Set_DX8_Transform(D3DTRANSFORMSTATETYPE transform,const Matrix3D& m) -{ - WWASSERT(transform<=D3DTS_WORLD); - Matrix4x4 mtx(m); -#if 0 // (gth) this optimization is breaking generals because they set the transform behind our backs. - if (mtx!=DX8Transforms[transform]) -#endif - { - DX8Transforms[transform]=mtx; - SNAPSHOT_SAY(("DX8 - SetTransform %d [%f,%f,%f,%f][%f,%f,%f,%f][%f,%f,%f,%f]",transform,m[0][0],m[0][1],m[0][2],m[0][3],m[1][0],m[1][1],m[1][2],m[1][3],m[2][0],m[2][1],m[2][2],m[2][3])); - DX8_RECORD_MATRIX_CHANGE(); - DX8CALL(SetTransform(transform,(D3DMATRIX*)&m)); - } -} - -WWINLINE void DX8Wrapper::_Get_DX8_Transform(D3DTRANSFORMSTATETYPE transform, Matrix4x4& m) -{ - DX8CALL(GetTransform(transform,(D3DMATRIX*)&m)); -} - -// ---------------------------------------------------------------------------- -// -// Set the index offset for the current index buffer -// -// ---------------------------------------------------------------------------- - -WWINLINE void DX8Wrapper::Set_Index_Buffer_Index_Offset(unsigned offset) -{ - if (render_state.index_base_offset==offset) return; - render_state.index_base_offset=offset; - render_state_changed|=INDEX_BUFFER_CHANGED; -} - -// ---------------------------------------------------------------------------- -// Set the fog settings. This function should be used, rather than setting the -// appropriate renderstates directly, because the shader sets some of the -// renderstates on a per-mesh / per-pass basis depending on global fog states -// (stored in the wrapper) as well as the shader settings. -// This function should be called rarely - once per scene would be appropriate. -// ---------------------------------------------------------------------------- - -WWINLINE void DX8Wrapper::Set_Fog(bool enable, const Vector3 &color, float start, float end) -{ - // Set global states - FogEnable = enable; - FogColor = Convert_Color(color,0.0f); - - // Invalidate the current shader (since the renderstates set by the shader - // depend on the global fog settings as well as the actual shader settings) - ShaderClass::Invalidate(); - - // Set renderstates which are not affected by the shader - Set_DX8_Render_State(D3DRS_FOGSTART, *(DWORD *)(&start)); - Set_DX8_Render_State(D3DRS_FOGEND, *(DWORD *)(&end)); -} - - -WWINLINE void DX8Wrapper::Set_Ambient(const Vector3& color) -{ - Ambient_Color=color; - Set_DX8_Render_State(D3DRS_AMBIENT, DX8Wrapper::Convert_Color(color,0.0f)); -} - -// ---------------------------------------------------------------------------- -// -// Set vertex buffer to be used in the subsequent render calls. If there was -// a vertex buffer being used earlier, release the reference to it. Passing -// NULL just will release the vertex buffer. -// -// ---------------------------------------------------------------------------- - -WWINLINE void DX8Wrapper::Set_DX8_Material(const D3DMATERIAL8* mat) -{ - DX8_RECORD_MATERIAL_CHANGE(); - WWASSERT(mat); - SNAPSHOT_SAY(("DX8 - SetMaterial")); - DX8CALL(SetMaterial(mat)); -} - -WWINLINE void DX8Wrapper::Set_DX8_Light(int index, D3DLIGHT8* light) -{ - if (light) { - DX8_RECORD_LIGHT_CHANGE(); - DX8CALL(SetLight(index,light)); - DX8CALL(LightEnable(index,TRUE)); - CurrentDX8LightEnables[index]=true; - SNAPSHOT_SAY(("DX8 - SetLight %d",index)); - } - else if (CurrentDX8LightEnables[index]) { - DX8_RECORD_LIGHT_CHANGE(); - CurrentDX8LightEnables[index]=false; - DX8CALL(LightEnable(index,FALSE)); - SNAPSHOT_SAY(("DX8 - DisableLight %d",index)); - } -} - -WWINLINE void DX8Wrapper::Set_DX8_Render_State(D3DRENDERSTATETYPE state, unsigned value) -{ - // Can't monitor state changes because setShader call to GERD may change the states! - if (RenderStates[state]==value) return; - -#ifdef MESH_RENDER_SNAPSHOT_ENABLED - if (WW3D::Is_Snapshot_Activated()) { - StringClass value_name(0,true); - Get_DX8_Render_State_Value_Name(value_name,state,value); - SNAPSHOT_SAY(("DX8 - SetRenderState(state: %s, value: %s)", - Get_DX8_Render_State_Name(state), - value_name.str())); - } -#endif - - RenderStates[state]=value; - DX8CALL(SetRenderState( state, value )); - DX8_RECORD_RENDER_STATE_CHANGE(); -} - -WWINLINE void DX8Wrapper::Set_DX8_Clip_Plane(DWORD Index, CONST float* pPlane) -{ - DX8CALL(SetClipPlane( Index, pPlane )); -} - -WWINLINE void DX8Wrapper::Set_DX8_Texture_Stage_State(unsigned stage, D3DTEXTURESTAGESTATETYPE state, unsigned value) -{ - if (stage >= MAX_TEXTURE_STAGES) - { DX8CALL(SetTextureStageState( stage, state, value )); - return; - } - - // Can't monitor state changes because setShader call to GERD may change the states! - if (TextureStageStates[stage][(unsigned int)state]==value) return; -#ifdef MESH_RENDER_SNAPSHOT_ENABLED - if (WW3D::Is_Snapshot_Activated()) { - StringClass value_name(0,true); - Get_DX8_Texture_Stage_State_Value_Name(value_name,state,value); - SNAPSHOT_SAY(("DX8 - SetTextureStageState(stage: %d, state: %s, value: %s)", - stage, - Get_DX8_Texture_Stage_State_Name(state), - value_name.str())); - } -#endif - - TextureStageStates[stage][(unsigned int)state]=value; - DX8CALL(SetTextureStageState( stage, state, value )); - DX8_RECORD_TEXTURE_STAGE_STATE_CHANGE(); -} - -WWINLINE void DX8Wrapper::Set_DX8_Texture(unsigned int stage, IDirect3DBaseTexture8* texture) -{ - if (stage >= MAX_TEXTURE_STAGES) - { DX8CALL(SetTexture(stage, texture)); - return; - } - - if (Textures[stage]==texture) return; - - SNAPSHOT_SAY(("DX8 - SetTexture(%x) ",texture)); - - if (Textures[stage]) Textures[stage]->Release(); - Textures[stage] = texture; - if (Textures[stage]) Textures[stage]->AddRef(); - DX8CALL(SetTexture(stage, texture)); - DX8_RECORD_TEXTURE_CHANGE(); -} - -WWINLINE void DX8Wrapper::_Copy_DX8_Rects( - IDirect3DSurface8* pSourceSurface, - CONST RECT* pSourceRectsArray, - UINT cRects, - IDirect3DSurface8* pDestinationSurface, - CONST POINT* pDestPointsArray -) -{ - DX8CALL(CopyRects( - pSourceSurface, - pSourceRectsArray, - cRects, - pDestinationSurface, - pDestPointsArray)); -} - -WWINLINE Vector4 DX8Wrapper::Convert_Color(unsigned color) -{ - Vector4 col; - col[3]=((color&0xff000000)>>24)/255.0f; - col[0]=((color&0xff0000)>>16)/255.0f; - col[1]=((color&0xff00)>>8)/255.0f; - col[2]=((color&0xff)>>0)/255.0f; -// col=Vector4(1.0f,1.0f,1.0f,1.0f); - return col; -} - -#if 0 -WWINLINE unsigned int DX8Wrapper::Convert_Color(const Vector3& color, const float alpha) -{ - WWASSERT(color.X<=1.0f); - WWASSERT(color.Y<=1.0f); - WWASSERT(color.Z<=1.0f); - WWASSERT(alpha<=1.0f); - WWASSERT(color.X>=0.0f); - WWASSERT(color.Y>=0.0f); - WWASSERT(color.Z>=0.0f); - WWASSERT(alpha>=0.0f); - - return D3DCOLOR_COLORVALUE(color.X,color.Y,color.Z,alpha); -} -WWINLINE unsigned int DX8Wrapper::Convert_Color(const Vector4& color) -{ - WWASSERT(color.X<=1.0f); - WWASSERT(color.Y<=1.0f); - WWASSERT(color.Z<=1.0f); - WWASSERT(color.W<=1.0f); - WWASSERT(color.X>=0.0f); - WWASSERT(color.Y>=0.0f); - WWASSERT(color.Z>=0.0f); - WWASSERT(color.W>=0.0f); - - return D3DCOLOR_COLORVALUE(color.X,color.Y,color.Z,color.W); -} -#else - -// ---------------------------------------------------------------------------- -// -// Convert RGBA color from float vector to 32 bit integer -// Note: Color vector needs to be clamped to [0...1] range! -// -// ---------------------------------------------------------------------------- - -WWINLINE unsigned int DX8Wrapper::Convert_Color(const Vector3& color,float alpha) -{ -#if defined(_MSC_VER) && _MSC_VER < 1300 - const float scale = 255.0; - unsigned int col; - - // Multiply r, g, b and a components (0.0,...,1.0) by 255 and convert to integer. Or the integer values togerher - // such that 32 bit ingeger has AAAAAAAARRRRRRRRGGGGGGGGBBBBBBBB. - __asm - { - sub esp,20 // space for a, r, g and b float plus fpu rounding mode - - // Store the fpu rounding mode - - fwait - fstcw [esp+16] // store control word to stack - mov eax,[esp+16] // load it to eax - mov edi,eax // take copy - and eax,~(1024|2048) // mask out certain bits - or eax,(1024|2048) // or with precision control value "truncate" - sub edi,eax // did it change? - jz skip // .. if not, skip - mov [esp],eax // .. change control word - fldcw [esp] -skip: - - // Convert the color - - mov esi,dword ptr color - fld dword ptr[scale] - - fld dword ptr[esi] // r - fld dword ptr[esi+4] // g - fld dword ptr[esi+8] // b - fld dword ptr[alpha] // a - fld st(4) - fmul st(4),st - fmul st(3),st - fmul st(2),st - fmulp st(1),st - fistp dword ptr[esp+0] // a - fistp dword ptr[esp+4] // b - fistp dword ptr[esp+8] // g - fistp dword ptr[esp+12] // r - mov ecx,[esp] // a - mov eax,[esp+4] // b - mov edx,[esp+8] // g - mov ebx,[esp+12] // r - shl ecx,24 // a << 24 - shl ebx,16 // r << 16 - shl edx,8 // g << 8 - or eax,ecx // (a << 24) | b - or eax,ebx // (a << 24) | (r << 16) | b - or eax,edx // (a << 24) | (r << 16) | (g << 8) | b - - fstp st(0) - - // Restore fpu rounding mode - - cmp edi,0 // did we change the value? - je not_changed // nope... skip now... - fwait - fldcw [esp+16]; -not_changed: - add esp,20 - - mov col,eax - } - return col; -#else - return color.Convert_To_ARGB(alpha); -#endif // defined(_MSC_VER) && _MSC_VER < 1300 -} - -// ---------------------------------------------------------------------------- -// -// Clamp color vector to [0...1] range -// -// ---------------------------------------------------------------------------- - -WWINLINE void DX8Wrapper::Clamp_Color(Vector4& color) -{ -#if defined(_MSC_VER) && _MSC_VER < 1300 - if (CPUDetectClass::Has_CMOV_Instruction()) { - __asm - { - mov esi,dword ptr color - - mov edx,0x3f800000 - - mov edi,dword ptr[esi] - mov ebx,edi - sar edi,31 - not edi // mask is now zero if negative value - and edi,ebx - cmp edi,edx // if no less than 1.0 set to 1.0 - cmovnb edi,edx - mov dword ptr[esi],edi - - mov edi,dword ptr[esi+4] - mov ebx,edi - sar edi,31 - not edi // mask is now zero if negative value - and edi,ebx - cmp edi,edx // if no less than 1.0 set to 1.0 - cmovnb edi,edx - mov dword ptr[esi+4],edi - - mov edi,dword ptr[esi+8] - mov ebx,edi - sar edi,31 - not edi // mask is now zero if negative value - and edi,ebx - cmp edi,edx // if no less than 1.0 set to 1.0 - cmovnb edi,edx - mov dword ptr[esi+8],edi - - mov edi,dword ptr[esi+12] - mov ebx,edi - sar edi,31 - not edi // mask is now zero if negative value - and edi,ebx - cmp edi,edx // if no less than 1.0 set to 1.0 - cmovnb edi,edx - mov dword ptr[esi+12],edi - } - return; - } -#endif // defined(_MSC_VER) && _MSC_VER < 1300 - - for (int i=0;i<4;++i) { - float f=(color[i]<0.0f) ? 0.0f : color[i]; - color[i]=(f>1.0f) ? 1.0f : f; - } -} - -// ---------------------------------------------------------------------------- -// -// Convert RGBA color from float vector to 32 bit integer -// -// ---------------------------------------------------------------------------- - -WWINLINE unsigned int DX8Wrapper::Convert_Color(const Vector4& color) -{ - return Convert_Color(reinterpret_cast(color),color[3]); -} - -WWINLINE unsigned int DX8Wrapper::Convert_Color_Clamp(const Vector4& color) -{ - Vector4 clamped_color=color; - DX8Wrapper::Clamp_Color(clamped_color); - return Convert_Color(reinterpret_cast(clamped_color),clamped_color[3]); -} - -#endif - - -WWINLINE void DX8Wrapper::Set_Alpha (const float alpha, unsigned int &color) -{ - unsigned char *component = (unsigned char*) &color; - - component [3] = 255.0f * alpha; -} - -WWINLINE void DX8Wrapper::Get_Render_State(RenderStateStruct& state) -{ - state=render_state; -} - -WWINLINE void DX8Wrapper::Get_Shader(ShaderClass& shader) -{ - shader=render_state.shader; -} - -WWINLINE void DX8Wrapper::Set_Texture(unsigned stage,TextureBaseClass* texture) -{ - WWASSERT(stage<(unsigned int)CurrentCaps->Get_Max_Textures_Per_Pass()); - if (texture==render_state.Textures[stage]) return; - REF_PTR_SET(render_state.Textures[stage],texture); - render_state_changed|=(TEXTURE0_CHANGED<(material)); - render_state_changed|=MATERIAL_CHANGED; -} - -WWINLINE void DX8Wrapper::Set_Shader(const ShaderClass& shader) -{ - if (!ShaderClass::ShaderDirty && ((unsigned&)shader==(unsigned&)render_state.shader)) { - return; - } - render_state.shader=shader; - render_state_changed|=SHADER_CHANGED; -#ifdef MESH_RENDER_SNAPSHOT_ENABLED - StringClass str; -#endif - SNAPSHOT_SAY(("DX8Wrapper::Set_Shader(%s)",shader.Get_Description(str).str())); -} - - -WWINLINE void DX8Wrapper::Set_Transform(D3DTRANSFORMSTATETYPE transform,const Matrix4x4& m) -{ - switch ((int)transform) { - case D3DTS_WORLD: - render_state.world=m.Transpose(); - render_state_changed|=(unsigned)WORLD_CHANGED; - render_state_changed&=~(unsigned)WORLD_IDENTITY; - break; - case D3DTS_VIEW: - render_state.view=m.Transpose(); - render_state_changed|=(unsigned)VIEW_CHANGED; - render_state_changed&=~(unsigned)VIEW_IDENTITY; - break; - case D3DTS_PROJECTION: - { - Matrix4x4 ProjectionMatrix=m.Transpose(); - ZFar=0.0f; - ZNear=0.0f; - DX8CALL(SetTransform(D3DTS_PROJECTION,(D3DMATRIX*)&ProjectionMatrix)); - } - break; - default: - DX8_RECORD_MATRIX_CHANGE(); - Matrix4x4 m2=m.Transpose(); - DX8CALL(SetTransform(transform,(D3DMATRIX*)&m2)); - break; - } -} - -WWINLINE void DX8Wrapper::Set_Transform(D3DTRANSFORMSTATETYPE transform,const Matrix3D& m) -{ - Matrix4x4 m2(m); - switch ((int)transform) { - case D3DTS_WORLD: - render_state.world=m2.Transpose(); - render_state_changed|=(unsigned)WORLD_CHANGED; - render_state_changed&=~(unsigned)WORLD_IDENTITY; - break; - case D3DTS_VIEW: - render_state.view=m2.Transpose(); - render_state_changed|=(unsigned)VIEW_CHANGED; - render_state_changed&=~(unsigned)VIEW_IDENTITY; - break; - default: - DX8_RECORD_MATRIX_CHANGE(); - m2=m2.Transpose(); - DX8CALL(SetTransform(transform,(D3DMATRIX*)&m2)); - break; - } -} - -WWINLINE void DX8Wrapper::Set_World_Identity() -{ - if (render_state_changed&(unsigned)WORLD_IDENTITY) return; - render_state.world.Make_Identity(); - render_state_changed|=(unsigned)WORLD_CHANGED|(unsigned)WORLD_IDENTITY; -} - -WWINLINE void DX8Wrapper::Set_View_Identity() -{ - if (render_state_changed&(unsigned)VIEW_IDENTITY) return; - render_state.view.Make_Identity(); - render_state_changed|=(unsigned)VIEW_CHANGED|(unsigned)VIEW_IDENTITY; -} - -WWINLINE bool DX8Wrapper::Is_World_Identity() -{ - return !!(render_state_changed&(unsigned)WORLD_IDENTITY); -} - -WWINLINE bool DX8Wrapper::Is_View_Identity() -{ - return !!(render_state_changed&(unsigned)VIEW_IDENTITY); -} - -WWINLINE void DX8Wrapper::Get_Transform(D3DTRANSFORMSTATETYPE transform, Matrix4x4& m) -{ - D3DMATRIX mat; - - switch ((int)transform) { - case D3DTS_WORLD: - if (render_state_changed&WORLD_IDENTITY) m.Make_Identity(); - else m=render_state.world.Transpose(); - break; - case D3DTS_VIEW: - if (render_state_changed&VIEW_IDENTITY) m.Make_Identity(); - else m=render_state.view.Transpose(); - break; - default: - DX8CALL(GetTransform(transform,&mat)); - m=*(Matrix4x4*)&mat; - m=m.Transpose(); - break; - } -} - -WWINLINE const D3DLIGHT8& DX8Wrapper::Peek_Light(unsigned index) -{ - return render_state.Lights[index];; -} - -WWINLINE bool DX8Wrapper::Is_Light_Enabled(unsigned index) -{ - return render_state.LightEnable[index]; -} - - -WWINLINE void DX8Wrapper::Set_Render_State(const RenderStateStruct& state) -{ - int i; - - if (render_state.index_buffer) { - render_state.index_buffer->Release_Engine_Ref(); - } - - for (i = 0; i < MAX_VERTEX_STREAMS; ++i) - { - if (render_state.vertex_buffers[i]) - { - render_state.vertex_buffers[i]->Release_Engine_Ref(); - } - } - - render_state = state; - render_state_changed = 0xffffffff; - - if (render_state.index_buffer) { - render_state.index_buffer->Add_Engine_Ref(); - } - - for (i = 0; i < MAX_VERTEX_STREAMS; ++i) - { - if (render_state.vertex_buffers[i]) - { - render_state.vertex_buffers[i]->Add_Engine_Ref(); - } - } -} - -WWINLINE void DX8Wrapper::Release_Render_State() -{ - int i; - - if (render_state.index_buffer) { - render_state.index_buffer->Release_Engine_Ref(); - } - - for (i = 0; i < MAX_VERTEX_STREAMS; ++i) { - if (render_state.vertex_buffers[i]) { - render_state.vertex_buffers[i]->Release_Engine_Ref(); - } - } - - for (i = 0; i < MAX_VERTEX_STREAMS; ++i) { - REF_PTR_RELEASE(render_state.vertex_buffers[i]); - } - REF_PTR_RELEASE(render_state.index_buffer); - REF_PTR_RELEASE(render_state.material); - - - for (i = 0; i < MAX_TEXTURE_STAGES; ++i) - { - REF_PTR_RELEASE(render_state.Textures[i]); - } -} - - -WWINLINE RenderStateStruct::RenderStateStruct() - : - material(0), - index_buffer(0) -{ - unsigned i; - for (i = 0; i < MAX_VERTEX_STREAMS; ++i) vertex_buffers[i] = 0; - for (i = 0; i < MAX_TEXTURE_STAGES; ++i) Textures[i] = 0; - //lightsHash = (unsigned)this; -} - -WWINLINE RenderStateStruct::~RenderStateStruct() -{ - unsigned i; - REF_PTR_RELEASE(material); - for (i = 0; i < MAX_VERTEX_STREAMS; ++i) { - REF_PTR_RELEASE(vertex_buffers[i]); - } - REF_PTR_RELEASE(index_buffer); - - for (i = 0; i < MAX_TEXTURE_STAGES; ++i) - { - REF_PTR_RELEASE(Textures[i]); - } -} - - -WWINLINE RenderStateStruct& RenderStateStruct::operator= (const RenderStateStruct& src) -{ - unsigned i; - REF_PTR_SET(material, src.material); - for (i = 0; i < MAX_VERTEX_STREAMS; ++i) { - REF_PTR_SET(vertex_buffers[i], src.vertex_buffers[i]); - } - REF_PTR_SET(index_buffer, src.index_buffer); - - for (i = 0; i < MAX_TEXTURE_STAGES; ++i) - { - REF_PTR_SET(Textures[i], src.Textures[i]); - } - - LightEnable[0] = src.LightEnable[0]; - LightEnable[1] = src.LightEnable[1]; - LightEnable[2] = src.LightEnable[2]; - LightEnable[3] = src.LightEnable[3]; - if (LightEnable[0]) { - Lights[0] = src.Lights[0]; - if (LightEnable[1]) { - Lights[1] = src.Lights[1]; - if (LightEnable[2]) { - Lights[2] = src.Lights[2]; - if (LightEnable[3]) { - Lights[3] = src.Lights[3]; - } - } - } - - - //lightsHash = flimby((char*)(&Lights[0]), sizeof(D3DLIGHT8)-1 ); - - } - - shader = src.shader; - world = src.world; - view = src.view; - for (i = 0; i < MAX_VERTEX_STREAMS; ++i) { - vertex_buffer_types[i] = src.vertex_buffer_types[i]; - } - index_buffer_type = src.index_buffer_type; - vba_offset = src.vba_offset; - vba_count = src.vba_count; - iba_offset = src.iba_offset; - index_base_offset = src.index_base_offset; - - return *this; -} - - -#endif +#include "../../Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_header_common.h" diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h index 9f643d89b62..2c9291c9b6c 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h @@ -1,1514 +1 @@ -/* -** Command & Conquer Generals Zero Hour(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/dx8wrapper.h $* - * * - * Original Author:: Jani Penttinen * - * * - * Author : Kenny Mitchell * - * * - * $Modtime:: 08/05/02 2:40p $* - * * - * $Revision:: 92 $* - * * - * 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: * - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - -#if defined(_MSC_VER) -#pragma once -#endif - -#ifndef DX8_WRAPPER_H -#define DX8_WRAPPER_H - -#include "always.h" -#include "dllist.h" -#include "d3d8.h" -#include "matrix4.h" -#include "statistics.h" -#include "wwstring.h" -#include "lightenvironment.h" -#include "shader.h" -#include "vector4.h" -#include "cpudetect.h" -#include "dx8caps.h" - -#include "texture.h" -#include "dx8vertexbuffer.h" -#include "dx8indexbuffer.h" -#include "vertmaterial.h" - -/* -** Registry value names -*/ -#define VALUE_NAME_RENDER_DEVICE_NAME "RenderDeviceName" -#define VALUE_NAME_RENDER_DEVICE_WIDTH "RenderDeviceWidth" -#define VALUE_NAME_RENDER_DEVICE_HEIGHT "RenderDeviceHeight" -#define VALUE_NAME_RENDER_DEVICE_DEPTH "RenderDeviceDepth" -#define VALUE_NAME_RENDER_DEVICE_WINDOWED "RenderDeviceWindowed" -#define VALUE_NAME_RENDER_DEVICE_TEXTURE_DEPTH "RenderDeviceTextureDepth" - -const unsigned MAX_TEXTURE_STAGES=8; -const unsigned MAX_VERTEX_STREAMS=2; -const unsigned MAX_VERTEX_SHADER_CONSTANTS=96; -const unsigned MAX_PIXEL_SHADER_CONSTANTS=8; -const unsigned MAX_SHADOW_MAPS=1; - -#define prevVer -#define nextVer - - -enum { - BUFFER_TYPE_DX8, - BUFFER_TYPE_SORTING, - BUFFER_TYPE_DYNAMIC_DX8, - BUFFER_TYPE_DYNAMIC_SORTING, - BUFFER_TYPE_INVALID -}; - -class VertexMaterialClass; -class CameraClass; -class LightEnvironmentClass; -class RenderDeviceDescClass; -class VertexBufferClass; -class DynamicVBAccessClass; -class IndexBufferClass; -class DynamicIBAccessClass; -class TextureClass; -class ZTextureClass; -class LightClass; -class SurfaceClass; -class DX8Caps; - -#define DX8_RECORD_MATRIX_CHANGE() matrix_changes++ -#define DX8_RECORD_MATERIAL_CHANGE() material_changes++ -#define DX8_RECORD_VERTEX_BUFFER_CHANGE() vertex_buffer_changes++ -#define DX8_RECORD_INDEX_BUFFER_CHANGE() index_buffer_changes++ -#define DX8_RECORD_LIGHT_CHANGE() light_changes++ -#define DX8_RECORD_TEXTURE_CHANGE() texture_changes++ -#define DX8_RECORD_RENDER_STATE_CHANGE() render_state_changes++ -#define DX8_RECORD_TEXTURE_STAGE_STATE_CHANGE() texture_stage_state_changes++ -#define DX8_RECORD_DRAW_CALLS() draw_calls++ - -extern unsigned number_of_DX8_calls; -extern bool _DX8SingleThreaded; - -void DX8_Assert(); -void Log_DX8_ErrorCode(unsigned res); - -WWINLINE void DX8_ErrorCode(unsigned res) -{ - if (res==D3D_OK) return; - Log_DX8_ErrorCode(res); -} - -#ifdef WWDEBUG -#define DX8CALL_HRES(x,res) DX8_Assert(); res = DX8Wrapper::_Get_D3D_Device8()->x; DX8_ErrorCode(res); number_of_DX8_calls++; -#define DX8CALL(x) DX8_Assert(); DX8_ErrorCode(DX8Wrapper::_Get_D3D_Device8()->x); number_of_DX8_calls++; -#define DX8CALL_D3D(x) DX8_Assert(); DX8_ErrorCode(DX8Wrapper::_Get_D3D8()->x); number_of_DX8_calls++; -#define DX8_THREAD_ASSERT() if (_DX8SingleThreaded) { WWASSERT_PRINT(DX8Wrapper::_Get_Main_Thread_ID()==ThreadClass::_Get_Current_Thread_ID(),"DX8Wrapper::DX8 calls must be called from the main thread!"); } -#else -#define DX8CALL_HRES(x,res) res = DX8Wrapper::_Get_D3D_Device8()->x; number_of_DX8_calls++; -#define DX8CALL(x) DX8Wrapper::_Get_D3D_Device8()->x; number_of_DX8_calls++; -#define DX8CALL_D3D(x) DX8Wrapper::_Get_D3D8()->x; number_of_DX8_calls++; -#define DX8_THREAD_ASSERT() ; -#endif - - -#define no_EXTENDED_STATS -// EXTENDED_STATS collects additional timing statistics by turning off parts -// of the 3D drawing system (terrain, objects, etc.) -#ifdef EXTENDED_STATS -class DX8_Stats -{ -public: - bool m_showingStats; - bool m_disableTerrain; - bool m_disableWater; - bool m_disableObjects; - bool m_disableOverhead; - bool m_disableConsole; - int m_debugLinesToShow; - int m_sleepTime; -public: - DX8_Stats::DX8_Stats(void) { - m_disableConsole = m_showingStats = m_disableTerrain = m_disableWater = m_disableOverhead = m_disableObjects = false; - m_sleepTime = 0; - m_debugLinesToShow = -1; // -1 means show all expected lines of output - } -}; -#endif - - -// This virtual interface was added for the Generals RTS. -// It is called before resetting the dx8 device to ensure -// that all dx8 resources are released. Otherwise reset fails. jba. -class DX8_CleanupHook -{ -public: - virtual void ReleaseResources(void)=0; - virtual void ReAcquireResources(void)=0; -}; - - -struct RenderStateStruct -{ - ShaderClass shader; - VertexMaterialClass* material; - TextureBaseClass * Textures[MAX_TEXTURE_STAGES]; - D3DLIGHT8 Lights[4]; - bool LightEnable[4]; - //unsigned lightsHash; - Matrix4x4 world; - Matrix4x4 view; - unsigned vertex_buffer_types[MAX_VERTEX_STREAMS]; - unsigned index_buffer_type; - unsigned short vba_offset; - unsigned short vba_count; - unsigned short iba_offset; - VertexBufferClass* vertex_buffers[MAX_VERTEX_STREAMS]; - IndexBufferClass* index_buffer; - unsigned short index_base_offset; - - RenderStateStruct(); - ~RenderStateStruct(); - - RenderStateStruct& operator= (const RenderStateStruct& src); -}; - -/** -** DX8Wrapper -** -** DX8 interface wrapper class. This encapsulates the DX8 interface; adding redundant state -** detection, stat tracking, etc etc. In general, we will wrap all DX8 calls with at least -** an WWINLINE function so that we can add stat tracking, etc if needed. Direct access to the -** D3D device will require "friend" status and should be granted only in extreme circumstances :-) -*/ -class DX8Wrapper -{ - enum ChangedStates { - WORLD_CHANGED = 1<<0, - VIEW_CHANGED = 1<<1, - LIGHT0_CHANGED = 1<<2, - LIGHT1_CHANGED = 1<<3, - LIGHT2_CHANGED = 1<<4, - LIGHT3_CHANGED = 1<<5, - TEXTURE0_CHANGED= 1<<6, - TEXTURE1_CHANGED= 1<<7, - TEXTURE2_CHANGED= 1<<8, - TEXTURE3_CHANGED= 1<<9, - MATERIAL_CHANGED= 1<<14, - SHADER_CHANGED = 1<<15, - VERTEX_BUFFER_CHANGED = 1<<16, - INDEX_BUFFER_CHANGED = 1 << 17, - WORLD_IDENTITY= 1<<18, - VIEW_IDENTITY= 1<<19, - - TEXTURES_CHANGED= - TEXTURE0_CHANGED|TEXTURE1_CHANGED|TEXTURE2_CHANGED|TEXTURE3_CHANGED, - LIGHTS_CHANGED= - LIGHT0_CHANGED|LIGHT1_CHANGED|LIGHT2_CHANGED|LIGHT3_CHANGED, - }; - - static void Draw_Sorting_IB_VB( - unsigned primitive_type, - unsigned short start_index, - unsigned short polygon_count, - unsigned short min_vertex_index, - unsigned short vertex_count); - - static void Draw( - unsigned primitive_type, - unsigned short start_index, - unsigned short polygon_count, - unsigned short min_vertex_index=0, - unsigned short vertex_count=0); - -public: -#ifdef EXTENDED_STATS - static DX8_Stats stats; -#endif - - static bool Init(void * hwnd, bool lite = false); - static void Shutdown(void); - - static void SetCleanupHook(DX8_CleanupHook *pCleanupHook) {m_pCleanupHook = pCleanupHook;}; - /* - ** Some WW3D sub-systems need to be initialized after the device is created and shutdown - ** before the device is released. - */ - static void Do_Onetime_Device_Dependent_Inits(void); - static void Do_Onetime_Device_Dependent_Shutdowns(void); - - static bool Is_Device_Lost() { return IsDeviceLost; } - static bool Is_Initted(void) { return IsInitted; } - - static bool Has_Stencil (void); - static void Get_Format_Name(unsigned int format, StringClass *tex_format); - - /* - ** Rendering - */ - static void Begin_Scene(void); - static void End_Scene(bool flip_frame = true); - - // Flip until the primary buffer is visible. - static void Flip_To_Primary(void); - - static void Clear(bool clear_color, bool clear_z_stencil, const Vector3 &color, float dest_alpha=0.0f, float z=1.0f, unsigned int stencil=0); - - static void Set_Viewport(CONST D3DVIEWPORT8* pViewport); - - static void Set_Vertex_Buffer(const VertexBufferClass* vb, unsigned stream=0); - static void Set_Vertex_Buffer(const DynamicVBAccessClass& vba); - static void Set_Index_Buffer(const IndexBufferClass* ib,unsigned short index_base_offset); - static void Set_Index_Buffer(const DynamicIBAccessClass& iba,unsigned short index_base_offset); - static void Set_Index_Buffer_Index_Offset(unsigned offset); - - static void Get_Render_State(RenderStateStruct& state); - static void Set_Render_State(const RenderStateStruct& state); - static void Release_Render_State(); - - static void Set_DX8_Material(const D3DMATERIAL8* mat); - - static void Set_Gamma(float gamma,float bright,float contrast,bool calibrate=true,bool uselimit=true); - - // Set_ and Get_Transform() functions take the matrix in Westwood convention format. - - static void Set_DX8_ZBias(int zbias); - static void Set_Projection_Transform_With_Z_Bias(const Matrix4x4& matrix,float znear, float zfar); // pointer to 16 matrices - - static void Set_Transform(D3DTRANSFORMSTATETYPE transform,const Matrix4x4& m); - static void Set_Transform(D3DTRANSFORMSTATETYPE transform,const Matrix3D& m); - static void Get_Transform(D3DTRANSFORMSTATETYPE transform, Matrix4x4& m); - static void Set_World_Identity(); - static void Set_View_Identity(); - static bool Is_World_Identity(); - static bool Is_View_Identity(); - - // Note that *_DX8_Transform() functions take the matrix in DX8 format - transposed from Westwood convention. - - static void _Set_DX8_Transform(D3DTRANSFORMSTATETYPE transform,const Matrix4x4& m); - static void _Set_DX8_Transform(D3DTRANSFORMSTATETYPE transform,const Matrix3D& m); - static void _Get_DX8_Transform(D3DTRANSFORMSTATETYPE transform, Matrix4x4& m); - - static void Set_DX8_Light(int index,D3DLIGHT8* light); - static void Set_DX8_Render_State(D3DRENDERSTATETYPE state, unsigned value); - static void Set_DX8_Clip_Plane(DWORD Index, CONST float* pPlane); - static void Set_DX8_Texture_Stage_State(unsigned stage, D3DTEXTURESTAGESTATETYPE state, unsigned value); - static void Set_DX8_Texture(unsigned int stage, IDirect3DBaseTexture8* texture); - static void Set_Light_Environment(LightEnvironmentClass* light_env); - static LightEnvironmentClass* Get_Light_Environment() { return Light_Environment; } - static void Set_Fog(bool enable, const Vector3 &color, float start, float end); - - static WWINLINE const D3DLIGHT8& Peek_Light(unsigned index); - static WWINLINE bool Is_Light_Enabled(unsigned index); - - static bool Validate_Device(void); - - // Deferred - - static void Set_Shader(const ShaderClass& shader); - static void Get_Shader(ShaderClass& shader); - static void Set_Texture(unsigned stage,TextureBaseClass* texture); - static void Set_Material(const VertexMaterialClass* material); - static void Set_Light(unsigned index,const D3DLIGHT8* light); - static void Set_Light(unsigned index,const LightClass &light); - - static void Apply_Render_State_Changes(); // Apply deferred render state changes (will be called automatically by Draw...) - - static void Draw_Triangles( - unsigned buffer_type, - unsigned short start_index, - unsigned short polygon_count, - unsigned short min_vertex_index, - unsigned short vertex_count); - static void Draw_Triangles( - unsigned short start_index, - unsigned short polygon_count, - unsigned short min_vertex_index, - unsigned short vertex_count); - static void Draw_Strip( - unsigned short start_index, - unsigned short index_count, - unsigned short min_vertex_index, - unsigned short vertex_count); - - /* - ** 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, - unsigned int height, - WW3DFormat format, - MipCountType mip_level_count, - D3DPOOL pool=D3DPOOL_MANAGED, - bool rendertarget=false - ); - static IDirect3DTexture8 * _Create_DX8_Texture(const char *filename, MipCountType mip_level_count); - static IDirect3DTexture8 * _Create_DX8_Texture(IDirect3DSurface8 *surface, MipCountType mip_level_count); - - static IDirect3DSurface8 * _Create_DX8_Surface(unsigned int width, unsigned int height, WW3DFormat format); - static IDirect3DSurface8 * _Create_DX8_Surface(const char *filename); - static IDirect3DSurface8 * _Get_DX8_Front_Buffer(); - static SurfaceClass * _Get_DX8_Back_Buffer(unsigned int num=0); - - static void _Copy_DX8_Rects( - IDirect3DSurface8* pSourceSurface, - CONST RECT* pSourceRectsArray, - UINT cRects, - IDirect3DSurface8* pDestinationSurface, - CONST POINT* pDestPointsArray - ); - - static void _Update_Texture(TextureClass *system, TextureClass *video); - static void Flush_DX8_Resource_Manager(unsigned int bytes=0); - static unsigned int Get_Free_Texture_RAM(); - - static unsigned _Get_Main_Thread_ID() { return _MainThreadID; } - static const D3DADAPTER_IDENTIFIER8& Get_Current_Adapter_Identifier() { return CurrentAdapterIdentifier; } - - /* - ** Statistics - */ - static void Begin_Statistics(); - static void End_Statistics(); - static unsigned Get_Last_Frame_Matrix_Changes(); - static unsigned Get_Last_Frame_Material_Changes(); - static unsigned Get_Last_Frame_Vertex_Buffer_Changes(); - static unsigned Get_Last_Frame_Index_Buffer_Changes(); - static unsigned Get_Last_Frame_Light_Changes(); - static unsigned Get_Last_Frame_Texture_Changes(); - static unsigned Get_Last_Frame_Render_State_Changes(); - static unsigned Get_Last_Frame_Texture_Stage_State_Changes(); - static unsigned Get_Last_Frame_DX8_Calls(); - static unsigned Get_Last_Frame_Draw_Calls(); - - static unsigned long Get_FrameCount(void); - - // Needed by shader class - static bool Get_Fog_Enable() { return FogEnable; } - static D3DCOLOR Get_Fog_Color() { return FogColor; } - - // Utilities - static Vector4 Convert_Color(unsigned color); - static unsigned int Convert_Color(const Vector4& color); - static unsigned int Convert_Color(const Vector3& color, const float alpha); - static void Clamp_Color(Vector4& color); - static unsigned int Convert_Color_Clamp(const Vector4& color); - - static void Set_Alpha (const float alpha, unsigned int &color); - - static void _Enable_Triangle_Draw(bool enable) { _EnableTriangleDraw=enable; } - static bool _Is_Triangle_Draw_Enabled() { return _EnableTriangleDraw; } - - /* - ** Additional swap chain interface - ** - ** Use this interface to render to multiple windows (in windowed mode). - ** To render to an additional window, the sequence of calls should look - ** something like this: - ** - ** DX8Wrapper::Set_Render_Target (swap_chain_ptr); - ** - ** WW3D::Begin_Render (true, true, Vector3 (0, 0, 0)); - ** WW3D::Render (scene, camera, FALSE, FALSE); - ** WW3D::End_Render (); - ** - ** swap_chain_ptr->Present (NULL, NULL, NULL, NULL); - ** - ** DX8Wrapper::Set_Render_Target ((IDirect3DSurface8 *)NULL); - ** - */ - static IDirect3DSwapChain8 * Create_Additional_Swap_Chain (HWND render_window); - - /* - ** 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, 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 (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(); - - static void Set_Vertex_Shader(DWORD vertex_shader); - static void Set_Pixel_Shader(DWORD pixel_shader); - - static void Set_Vertex_Shader_Constant(int reg, const void* data, int count); - static void Set_Pixel_Shader_Constant(int reg, const void* data, int count); - - static DWORD Get_Vertex_Processing_Behavior() { return Vertex_Processing_Behavior; } - - // Needed by scene lighting class - static void Set_Ambient(const Vector3& color); - static const Vector3& Get_Ambient() { return Ambient_Color; } - // shader system updates KJM ^ - - - - - static IDirect3DDevice8* _Get_D3D_Device8() { return D3DDevice; } - static IDirect3D8* _Get_D3D8() { return D3DInterface; } - /// Returns the display format - added by TR for video playback - not part of W3D - static WW3DFormat getBackBufferFormat( void ); - static bool Reset_Device(bool reload_assets=true); - - static const DX8Caps* Get_Current_Caps() { WWASSERT(CurrentCaps); return CurrentCaps; } - - static bool Registry_Save_Render_Device( const char * sub_key ); - static bool Registry_Load_Render_Device( const char * sub_key, bool resize_window ); - - static const char* Get_DX8_Render_State_Name(D3DRENDERSTATETYPE state); - static const char* Get_DX8_Texture_Stage_State_Name(D3DTEXTURESTAGESTATETYPE state); - static unsigned Get_DX8_Render_State(D3DRENDERSTATETYPE state) { return RenderStates[state]; } - - // Names of the specific values of render states and texture stage states - static void Get_DX8_Texture_Stage_State_Value_Name(StringClass& name, D3DTEXTURESTAGESTATETYPE state, unsigned value); - static void Get_DX8_Render_State_Value_Name(StringClass& name, D3DRENDERSTATETYPE state, unsigned value); - - static const char* Get_DX8_Texture_Address_Name(unsigned value); - static const char* Get_DX8_Texture_Filter_Name(unsigned value); - static const char* Get_DX8_Texture_Arg_Name(unsigned value); - static const char* Get_DX8_Texture_Op_Name(unsigned value); - static const char* Get_DX8_Texture_Transform_Flag_Name(unsigned value); - static const char* Get_DX8_ZBuffer_Type_Name(unsigned value); - static const char* Get_DX8_Fill_Mode_Name(unsigned value); - static const char* Get_DX8_Shade_Mode_Name(unsigned value); - static const char* Get_DX8_Blend_Name(unsigned value); - static const char* Get_DX8_Cull_Mode_Name(unsigned value); - static const char* Get_DX8_Cmp_Func_Name(unsigned value); - static const char* Get_DX8_Fog_Mode_Name(unsigned value); - static const char* Get_DX8_Stencil_Op_Name(unsigned value); - static const char* Get_DX8_Material_Source_Name(unsigned value); - static const char* Get_DX8_Vertex_Blend_Flag_Name(unsigned value); - static const char* Get_DX8_Patch_Edge_Style_Name(unsigned value); - static const char* Get_DX8_Debug_Monitor_Token_Name(unsigned value); - static const char* Get_DX8_Blend_Op_Name(unsigned value); - - static void Invalidate_Cached_Render_States(void); - - static void Set_Draw_Polygon_Low_Bound_Limit(unsigned n) { DrawPolygonLowBoundLimit=n; } - -protected: - - static bool Create_Device(void); - static void Release_Device(void); - - static void Reset_Statistics(); - static void Enumerate_Devices(); - static void Set_Default_Global_Render_States(void); - - /* - ** Device Selection Code. - ** For backward compatibility, the public interface for these functions is in the ww3d. - ** header file. These functions are protected so that we aren't exposing two interfaces. - */ - static bool Set_Any_Render_Device(void); - static bool Set_Render_Device(const char * dev_name,int width=-1,int height=-1,int bits=-1,int windowed=-1,bool resize_window=false); - static bool Set_Render_Device(int dev=-1,int resx=-1,int resy=-1,int bits=-1,int windowed=-1,bool resize_window = false, bool reset_device = false, bool restore_assets=true); - static bool Set_Next_Render_Device(void); - static bool Toggle_Windowed(void); - - static int Get_Render_Device_Count(void); - static int Get_Render_Device(void); - static const RenderDeviceDescClass & Get_Render_Device_Desc(int deviceidx); - static const char * Get_Render_Device_Name(int device_index); - static bool Set_Device_Resolution(int width=-1,int height=-1,int bits=-1,int windowed=-1, bool resize_window=false); - static void Get_Device_Resolution(int & set_w,int & set_h,int & set_bits,bool & set_windowed); - static void Get_Render_Target_Resolution(int & set_w,int & set_h,int & set_bits,bool & set_windowed); - static int Get_Device_Resolution_Width(void) { return ResolutionWidth; } - static int Get_Device_Resolution_Height(void) { return ResolutionHeight; } - - static bool Registry_Save_Render_Device( const char *sub_key, int device, int width, int height, int depth, bool windowed, int texture_depth); - static bool Registry_Load_Render_Device( const char * sub_key, char *device, int device_len, int &width, int &height, int &depth, int &windowed, int &texture_depth); - static bool Is_Windowed(void) { return IsWindowed; } - - static void Set_Texture_Bitdepth(int depth) { WWASSERT(depth==16 || depth==32); TextureBitDepth = depth; } - static int Get_Texture_Bitdepth(void) { return TextureBitDepth; } - - static void Set_Swap_Interval(int swap); - static int Get_Swap_Interval(void); - static void Set_Polygon_Mode(int mode); - - /* - ** Internal functions - */ - static void Resize_And_Position_Window(); - static bool Find_Color_And_Z_Mode(int resx,int resy,int bitdepth,D3DFORMAT * set_colorbuffer,D3DFORMAT * set_backbuffer, D3DFORMAT * set_zmode); - static bool Find_Color_Mode(D3DFORMAT colorbuffer, int resx, int resy, UINT *mode); - static bool Find_Z_Mode(D3DFORMAT colorbuffer,D3DFORMAT backbuffer, D3DFORMAT *zmode); - static bool Test_Z_Mode(D3DFORMAT colorbuffer,D3DFORMAT backbuffer, D3DFORMAT zmode); - static void Compute_Caps(WW3DFormat display_format); - - /* - ** Protected Member Variables - */ - - static DX8_CleanupHook *m_pCleanupHook; - - static RenderStateStruct render_state; - static unsigned render_state_changed; - static Matrix4x4 DX8Transforms[D3DTS_WORLD+1]; - - static bool IsInitted; - static bool IsDeviceLost; - static void * Hwnd; - static unsigned _MainThreadID; - - static bool _EnableTriangleDraw; - - static int CurRenderDevice; - static int ResolutionWidth; - static int ResolutionHeight; - static int BitDepth; - static int TextureBitDepth; - static bool IsWindowed; - static D3DFORMAT DisplayFormat; - - static D3DMATRIX old_world; - static D3DMATRIX old_view; - static D3DMATRIX old_prj; - - // shader system updates KJM v - static DWORD Vertex_Shader; - static DWORD Pixel_Shader; - - static Vector4 Vertex_Shader_Constants[MAX_VERTEX_SHADER_CONSTANTS]; - static Vector4 Pixel_Shader_Constants[MAX_PIXEL_SHADER_CONSTANTS]; - - static LightEnvironmentClass* Light_Environment; - static RenderInfoClass* Render_Info; - - static DWORD Vertex_Processing_Behavior; - - static ZTextureClass* Shadow_Map[MAX_SHADOW_MAPS]; - - static Vector3 Ambient_Color; - // shader system updates KJM ^ - - static bool world_identity; - static unsigned RenderStates[256]; - static unsigned TextureStageStates[MAX_TEXTURE_STAGES][32]; - static IDirect3DBaseTexture8 * Textures[MAX_TEXTURE_STAGES]; - - // These fog settings are constant for all objects in a given scene, - // unlike the matching renderstates which vary based on shader settings. - static bool FogEnable; - static D3DCOLOR FogColor; - - static unsigned matrix_changes; - static unsigned material_changes; - static unsigned vertex_buffer_changes; - static unsigned index_buffer_changes; - static unsigned light_changes; - static unsigned texture_changes; - static unsigned render_state_changes; - static unsigned texture_stage_state_changes; - static unsigned draw_calls; - static bool CurrentDX8LightEnables[4]; - - static unsigned long FrameCount; - - static DX8Caps* CurrentCaps; - - static D3DADAPTER_IDENTIFIER8 CurrentAdapterIdentifier; - - static IDirect3D8 * D3DInterface; //d3d8; - static IDirect3DDevice8 * D3DDevice; //d3ddevice8; - - static IDirect3DSurface8 * CurrentRenderTarget; - static IDirect3DSurface8 * CurrentDepthBuffer; - static IDirect3DSurface8 * DefaultRenderTarget; - static IDirect3DSurface8 * DefaultDepthBuffer; - - static unsigned DrawPolygonLowBoundLimit; - - static bool IsRenderToTexture; - - static int ZBias; - static float ZNear; - static float ZFar; - static Matrix4x4 ProjectionMatrix; - - friend void DX8_Assert(); - friend class WW3D; - friend class DX8IndexBufferClass; - friend class DX8VertexBufferClass; -}; - -// shader system updates KJM v -WWINLINE void DX8Wrapper::Set_Vertex_Shader(DWORD vertex_shader) -{ -#if 0 //(gth) some code is bypassing this acessor function so we can't count on this variable... - // may be incorrect if shaders are created and destroyed dynamically - if (Vertex_Shader==vertex_shader) return; -#endif - - Vertex_Shader=vertex_shader; - DX8CALL(SetVertexShader(Vertex_Shader)); -} - -WWINLINE void DX8Wrapper::Set_Pixel_Shader(DWORD pixel_shader) -{ - // may be incorrect if shaders are created and destroyed dynamically - if (Pixel_Shader==pixel_shader) return; - - Pixel_Shader=pixel_shader; - DX8CALL(SetPixelShader(Pixel_Shader)); -} - -WWINLINE void DX8Wrapper::Set_Vertex_Shader_Constant(int reg, const void* data, int count) -{ - int memsize=sizeof(Vector4)*count; - - // may be incorrect if shaders are created and destroyed dynamically - if (memcmp(data, &Vertex_Shader_Constants[reg],memsize)==0) return; - - memcpy(&Vertex_Shader_Constants[reg],data,memsize); - DX8CALL(SetVertexShaderConstant(reg,data,count)); -} - -WWINLINE void DX8Wrapper::Set_Pixel_Shader_Constant(int reg, const void* data, int count) -{ - int memsize=sizeof(Vector4)*count; - - // may be incorrect if shaders are created and destroyed dynamically - if (memcmp(data, &Pixel_Shader_Constants[reg],memsize)==0) return; - - memcpy(&Pixel_Shader_Constants[reg],data,memsize); - DX8CALL(SetPixelShaderConstant(reg,data,count)); -} -// shader system updates KJM ^ - - -WWINLINE void DX8Wrapper::_Set_DX8_Transform(D3DTRANSFORMSTATETYPE transform,const Matrix4x4& m) -{ - WWASSERT(transform<=D3DTS_WORLD); -#if 0 // (gth) this optimization is breaking generals because they set the transform behind our backs. - if (m!=DX8Transforms[transform]) -#endif - { - DX8Transforms[transform]=m; - SNAPSHOT_SAY(("DX8 - SetTransform %d [%f,%f,%f,%f][%f,%f,%f,%f][%f,%f,%f,%f][%f,%f,%f,%f]",transform,m[0][0],m[0][1],m[0][2],m[0][3],m[1][0],m[1][1],m[1][2],m[1][3],m[2][0],m[2][1],m[2][2],m[2][3],m[3][0],m[3][1],m[3][2],m[3][3])); - DX8_RECORD_MATRIX_CHANGE(); - DX8CALL(SetTransform(transform,(D3DMATRIX*)&m)); - } -} - - -WWINLINE void DX8Wrapper::_Set_DX8_Transform(D3DTRANSFORMSTATETYPE transform,const Matrix3D& m) -{ - WWASSERT(transform<=D3DTS_WORLD); - Matrix4x4 mtx(m); -#if 0 // (gth) this optimization is breaking generals because they set the transform behind our backs. - if (mtx!=DX8Transforms[transform]) -#endif - { - DX8Transforms[transform]=mtx; - SNAPSHOT_SAY(("DX8 - SetTransform %d [%f,%f,%f,%f][%f,%f,%f,%f][%f,%f,%f,%f]",transform,m[0][0],m[0][1],m[0][2],m[0][3],m[1][0],m[1][1],m[1][2],m[1][3],m[2][0],m[2][1],m[2][2],m[2][3])); - DX8_RECORD_MATRIX_CHANGE(); - DX8CALL(SetTransform(transform,(D3DMATRIX*)&m)); - } -} - -WWINLINE void DX8Wrapper::_Get_DX8_Transform(D3DTRANSFORMSTATETYPE transform, Matrix4x4& m) -{ - DX8CALL(GetTransform(transform,(D3DMATRIX*)&m)); -} - -// ---------------------------------------------------------------------------- -// -// Set the index offset for the current index buffer -// -// ---------------------------------------------------------------------------- - -WWINLINE void DX8Wrapper::Set_Index_Buffer_Index_Offset(unsigned offset) -{ - if (render_state.index_base_offset==offset) return; - render_state.index_base_offset=offset; - render_state_changed|=INDEX_BUFFER_CHANGED; -} - -// ---------------------------------------------------------------------------- -// Set the fog settings. This function should be used, rather than setting the -// appropriate renderstates directly, because the shader sets some of the -// renderstates on a per-mesh / per-pass basis depending on global fog states -// (stored in the wrapper) as well as the shader settings. -// This function should be called rarely - once per scene would be appropriate. -// ---------------------------------------------------------------------------- - -WWINLINE void DX8Wrapper::Set_Fog(bool enable, const Vector3 &color, float start, float end) -{ - // Set global states - FogEnable = enable; - FogColor = Convert_Color(color,0.0f); - - // Invalidate the current shader (since the renderstates set by the shader - // depend on the global fog settings as well as the actual shader settings) - ShaderClass::Invalidate(); - - // Set renderstates which are not affected by the shader - Set_DX8_Render_State(D3DRS_FOGSTART, *(DWORD *)(&start)); - Set_DX8_Render_State(D3DRS_FOGEND, *(DWORD *)(&end)); -} - - -WWINLINE void DX8Wrapper::Set_Ambient(const Vector3& color) -{ - Ambient_Color=color; - Set_DX8_Render_State(D3DRS_AMBIENT, DX8Wrapper::Convert_Color(color,0.0f)); -} - -// ---------------------------------------------------------------------------- -// -// Set vertex buffer to be used in the subsequent render calls. If there was -// a vertex buffer being used earlier, release the reference to it. Passing -// NULL just will release the vertex buffer. -// -// ---------------------------------------------------------------------------- - -WWINLINE void DX8Wrapper::Set_DX8_Material(const D3DMATERIAL8* mat) -{ - DX8_RECORD_MATERIAL_CHANGE(); - WWASSERT(mat); - SNAPSHOT_SAY(("DX8 - SetMaterial")); - DX8CALL(SetMaterial(mat)); -} - -WWINLINE void DX8Wrapper::Set_DX8_Light(int index, D3DLIGHT8* light) -{ - if (light) { - DX8_RECORD_LIGHT_CHANGE(); - DX8CALL(SetLight(index,light)); - DX8CALL(LightEnable(index,TRUE)); - CurrentDX8LightEnables[index]=true; - SNAPSHOT_SAY(("DX8 - SetLight %d",index)); - } - else if (CurrentDX8LightEnables[index]) { - DX8_RECORD_LIGHT_CHANGE(); - CurrentDX8LightEnables[index]=false; - DX8CALL(LightEnable(index,FALSE)); - SNAPSHOT_SAY(("DX8 - DisableLight %d",index)); - } -} - -WWINLINE void DX8Wrapper::Set_DX8_Render_State(D3DRENDERSTATETYPE state, unsigned value) -{ - // Can't monitor state changes because setShader call to GERD may change the states! - if (RenderStates[state]==value) return; - -#ifdef MESH_RENDER_SNAPSHOT_ENABLED - if (WW3D::Is_Snapshot_Activated()) { - StringClass value_name(0,true); - Get_DX8_Render_State_Value_Name(value_name,state,value); - SNAPSHOT_SAY(("DX8 - SetRenderState(state: %s, value: %s)", - Get_DX8_Render_State_Name(state), - value_name.str())); - } -#endif - - RenderStates[state]=value; - DX8CALL(SetRenderState( state, value )); - DX8_RECORD_RENDER_STATE_CHANGE(); -} - -WWINLINE void DX8Wrapper::Set_DX8_Clip_Plane(DWORD Index, CONST float* pPlane) -{ - DX8CALL(SetClipPlane( Index, pPlane )); -} - -WWINLINE void DX8Wrapper::Set_DX8_Texture_Stage_State(unsigned stage, D3DTEXTURESTAGESTATETYPE state, unsigned value) -{ - if (stage >= MAX_TEXTURE_STAGES) - { DX8CALL(SetTextureStageState( stage, state, value )); - return; - } - - // Can't monitor state changes because setShader call to GERD may change the states! - if (TextureStageStates[stage][(unsigned int)state]==value) return; -#ifdef MESH_RENDER_SNAPSHOT_ENABLED - if (WW3D::Is_Snapshot_Activated()) { - StringClass value_name(0,true); - Get_DX8_Texture_Stage_State_Value_Name(value_name,state,value); - SNAPSHOT_SAY(("DX8 - SetTextureStageState(stage: %d, state: %s, value: %s)", - stage, - Get_DX8_Texture_Stage_State_Name(state), - value_name.str())); - } -#endif - - TextureStageStates[stage][(unsigned int)state]=value; - DX8CALL(SetTextureStageState( stage, state, value )); - DX8_RECORD_TEXTURE_STAGE_STATE_CHANGE(); -} - -WWINLINE void DX8Wrapper::Set_DX8_Texture(unsigned int stage, IDirect3DBaseTexture8* texture) -{ - if (stage >= MAX_TEXTURE_STAGES) - { DX8CALL(SetTexture(stage, texture)); - return; - } - - if (Textures[stage]==texture) return; - - SNAPSHOT_SAY(("DX8 - SetTexture(%x) ",texture)); - - if (Textures[stage]) Textures[stage]->Release(); - Textures[stage] = texture; - if (Textures[stage]) Textures[stage]->AddRef(); - DX8CALL(SetTexture(stage, texture)); - DX8_RECORD_TEXTURE_CHANGE(); -} - -WWINLINE void DX8Wrapper::_Copy_DX8_Rects( - IDirect3DSurface8* pSourceSurface, - CONST RECT* pSourceRectsArray, - UINT cRects, - IDirect3DSurface8* pDestinationSurface, - CONST POINT* pDestPointsArray -) -{ - DX8CALL(CopyRects( - pSourceSurface, - pSourceRectsArray, - cRects, - pDestinationSurface, - pDestPointsArray)); -} - -WWINLINE Vector4 DX8Wrapper::Convert_Color(unsigned color) -{ - Vector4 col; - col[3]=((color&0xff000000)>>24)/255.0f; - col[0]=((color&0xff0000)>>16)/255.0f; - col[1]=((color&0xff00)>>8)/255.0f; - col[2]=((color&0xff)>>0)/255.0f; -// col=Vector4(1.0f,1.0f,1.0f,1.0f); - return col; -} - -#if 0 -WWINLINE unsigned int DX8Wrapper::Convert_Color(const Vector3& color, const float alpha) -{ - WWASSERT(color.X<=1.0f); - WWASSERT(color.Y<=1.0f); - WWASSERT(color.Z<=1.0f); - WWASSERT(alpha<=1.0f); - WWASSERT(color.X>=0.0f); - WWASSERT(color.Y>=0.0f); - WWASSERT(color.Z>=0.0f); - WWASSERT(alpha>=0.0f); - - return D3DCOLOR_COLORVALUE(color.X,color.Y,color.Z,alpha); -} -WWINLINE unsigned int DX8Wrapper::Convert_Color(const Vector4& color) -{ - WWASSERT(color.X<=1.0f); - WWASSERT(color.Y<=1.0f); - WWASSERT(color.Z<=1.0f); - WWASSERT(color.W<=1.0f); - WWASSERT(color.X>=0.0f); - WWASSERT(color.Y>=0.0f); - WWASSERT(color.Z>=0.0f); - WWASSERT(color.W>=0.0f); - - return D3DCOLOR_COLORVALUE(color.X,color.Y,color.Z,color.W); -} -#else - -// ---------------------------------------------------------------------------- -// -// Convert RGBA color from float vector to 32 bit integer -// Note: Color vector needs to be clamped to [0...1] range! -// -// ---------------------------------------------------------------------------- - -WWINLINE unsigned int DX8Wrapper::Convert_Color(const Vector3& color,float alpha) -{ -#if defined(_MSC_VER) && _MSC_VER < 1300 - const float scale = 255.0; - unsigned int col; - - // Multiply r, g, b and a components (0.0,...,1.0) by 255 and convert to integer. Or the integer values togerher - // such that 32 bit ingeger has AAAAAAAARRRRRRRRGGGGGGGGBBBBBBBB. - __asm - { - sub esp,20 // space for a, r, g and b float plus fpu rounding mode - - // Store the fpu rounding mode - - fwait - fstcw [esp+16] // store control word to stack - mov eax,[esp+16] // load it to eax - mov edi,eax // take copy - and eax,~(1024|2048) // mask out certain bits - or eax,(1024|2048) // or with precision control value "truncate" - sub edi,eax // did it change? - jz skip // .. if not, skip - mov [esp],eax // .. change control word - fldcw [esp] -skip: - - // Convert the color - - mov esi,dword ptr color - fld dword ptr[scale] - - fld dword ptr[esi] // r - fld dword ptr[esi+4] // g - fld dword ptr[esi+8] // b - fld dword ptr[alpha] // a - fld st(4) - fmul st(4),st - fmul st(3),st - fmul st(2),st - fmulp st(1),st - fistp dword ptr[esp+0] // a - fistp dword ptr[esp+4] // b - fistp dword ptr[esp+8] // g - fistp dword ptr[esp+12] // r - mov ecx,[esp] // a - mov eax,[esp+4] // b - mov edx,[esp+8] // g - mov ebx,[esp+12] // r - shl ecx,24 // a << 24 - shl ebx,16 // r << 16 - shl edx,8 // g << 8 - or eax,ecx // (a << 24) | b - or eax,ebx // (a << 24) | (r << 16) | b - or eax,edx // (a << 24) | (r << 16) | (g << 8) | b - - fstp st(0) - - // Restore fpu rounding mode - - cmp edi,0 // did we change the value? - je not_changed // nope... skip now... - fwait - fldcw [esp+16]; -not_changed: - add esp,20 - - mov col,eax - } - return col; -#else - return color.Convert_To_ARGB(alpha); -#endif // defined(_MSC_VER) && _MSC_VER < 1300 -} - -// ---------------------------------------------------------------------------- -// -// Clamp color vector to [0...1] range -// -// ---------------------------------------------------------------------------- - -WWINLINE void DX8Wrapper::Clamp_Color(Vector4& color) -{ -#if defined(_MSC_VER) && _MSC_VER < 1300 - if (CPUDetectClass::Has_CMOV_Instruction()) { - __asm - { - mov esi,dword ptr color - - mov edx,0x3f800000 - - mov edi,dword ptr[esi] - mov ebx,edi - sar edi,31 - not edi // mask is now zero if negative value - and edi,ebx - cmp edi,edx // if no less than 1.0 set to 1.0 - cmovnb edi,edx - mov dword ptr[esi],edi - - mov edi,dword ptr[esi+4] - mov ebx,edi - sar edi,31 - not edi // mask is now zero if negative value - and edi,ebx - cmp edi,edx // if no less than 1.0 set to 1.0 - cmovnb edi,edx - mov dword ptr[esi+4],edi - - mov edi,dword ptr[esi+8] - mov ebx,edi - sar edi,31 - not edi // mask is now zero if negative value - and edi,ebx - cmp edi,edx // if no less than 1.0 set to 1.0 - cmovnb edi,edx - mov dword ptr[esi+8],edi - - mov edi,dword ptr[esi+12] - mov ebx,edi - sar edi,31 - not edi // mask is now zero if negative value - and edi,ebx - cmp edi,edx // if no less than 1.0 set to 1.0 - cmovnb edi,edx - mov dword ptr[esi+12],edi - } - return; - } -#endif // defined(_MSC_VER) && _MSC_VER < 1300 - - for (int i=0;i<4;++i) { - float f=(color[i]<0.0f) ? 0.0f : color[i]; - color[i]=(f>1.0f) ? 1.0f : f; - } -} - -// ---------------------------------------------------------------------------- -// -// Convert RGBA color from float vector to 32 bit integer -// -// ---------------------------------------------------------------------------- - -WWINLINE unsigned int DX8Wrapper::Convert_Color(const Vector4& color) -{ - return Convert_Color(reinterpret_cast(color),color[3]); -} - -WWINLINE unsigned int DX8Wrapper::Convert_Color_Clamp(const Vector4& color) -{ - Vector4 clamped_color=color; - DX8Wrapper::Clamp_Color(clamped_color); - return Convert_Color(reinterpret_cast(clamped_color),clamped_color[3]); -} - -#endif - - -WWINLINE void DX8Wrapper::Set_Alpha (const float alpha, unsigned int &color) -{ - unsigned char *component = (unsigned char*) &color; - - component [3] = 255.0f * alpha; -} - -WWINLINE void DX8Wrapper::Get_Render_State(RenderStateStruct& state) -{ - state=render_state; -} - -WWINLINE void DX8Wrapper::Get_Shader(ShaderClass& shader) -{ - shader=render_state.shader; -} - -WWINLINE void DX8Wrapper::Set_Texture(unsigned stage,TextureBaseClass* texture) -{ - WWASSERT(stage<(unsigned int)CurrentCaps->Get_Max_Textures_Per_Pass()); - if (texture==render_state.Textures[stage]) return; - REF_PTR_SET(render_state.Textures[stage],texture); - render_state_changed|=(TEXTURE0_CHANGED<Get_Name(),render_state.material->Get_Name())) { - material->Get_CRC()!=render_state.material->Get_CRC()) { - return; - } -*/ -// if (material==render_state.material) { -// return; -// } - REF_PTR_SET(render_state.material,const_cast(material)); - render_state_changed|=MATERIAL_CHANGED; - SNAPSHOT_SAY(("DX8Wrapper::Set_Material(%s)",material ? material->Get_Name() : "NULL")); -} - -WWINLINE void DX8Wrapper::Set_Shader(const ShaderClass& shader) -{ - if (!ShaderClass::ShaderDirty && ((unsigned&)shader==(unsigned&)render_state.shader)) { - return; - } - render_state.shader=shader; - render_state_changed|=SHADER_CHANGED; -#ifdef MESH_RENDER_SNAPSHOT_ENABLED - StringClass str; -#endif - SNAPSHOT_SAY(("DX8Wrapper::Set_Shader(%s)",shader.Get_Description(str).str())); -} - -WWINLINE void DX8Wrapper::Set_Projection_Transform_With_Z_Bias(const Matrix4x4& matrix, float znear, float zfar) -{ - ZFar=zfar; - ZNear=znear; - ProjectionMatrix=matrix.Transpose(); - - if (!Get_Current_Caps()->Support_ZBias() && ZNear!=ZFar) { - Matrix4x4 tmp=ProjectionMatrix; - float tmp_zbias=ZBias; - tmp_zbias*=(1.0f/16.0f); - tmp_zbias*=1.0f / (ZFar - ZNear); - tmp[2][2]-=tmp_zbias*tmp[3][2]; - DX8CALL(SetTransform(D3DTS_PROJECTION,(D3DMATRIX*)&tmp)); - } - else { - DX8CALL(SetTransform(D3DTS_PROJECTION,(D3DMATRIX*)&ProjectionMatrix)); - } -} - -WWINLINE void DX8Wrapper::Set_DX8_ZBias(int zbias) -{ - if (zbias==ZBias) return; - if (zbias>15) zbias=15; - if (zbias<0) zbias=0; - ZBias=zbias; - - if (!Get_Current_Caps()->Support_ZBias() && ZNear!=ZFar) { - Matrix4x4 tmp=ProjectionMatrix; - float tmp_zbias=ZBias; - tmp_zbias*=(1.0f/16.0f); - tmp_zbias*=1.0f / (ZFar - ZNear); - tmp[2][2]-=tmp_zbias*tmp[3][2]; - DX8CALL(SetTransform(D3DTS_PROJECTION,(D3DMATRIX*)&tmp)); - } - else { - Set_DX8_Render_State (D3DRS_ZBIAS, ZBias); - } -} - -WWINLINE void DX8Wrapper::Set_Transform(D3DTRANSFORMSTATETYPE transform,const Matrix4x4& m) -{ - switch ((int)transform) { - case D3DTS_WORLD: - render_state.world=m.Transpose(); - render_state_changed|=(unsigned)WORLD_CHANGED; - render_state_changed&=~(unsigned)WORLD_IDENTITY; - break; - case D3DTS_VIEW: - render_state.view=m.Transpose(); - render_state_changed|=(unsigned)VIEW_CHANGED; - render_state_changed&=~(unsigned)VIEW_IDENTITY; - break; - case D3DTS_PROJECTION: - { - Matrix4x4 ProjectionMatrix=m.Transpose(); - ZFar=0.0f; - ZNear=0.0f; - DX8CALL(SetTransform(D3DTS_PROJECTION,(D3DMATRIX*)&ProjectionMatrix)); - } - break; - default: - DX8_RECORD_MATRIX_CHANGE(); - Matrix4x4 m2=m.Transpose(); - DX8CALL(SetTransform(transform,(D3DMATRIX*)&m2)); - break; - } -} - -WWINLINE void DX8Wrapper::Set_Transform(D3DTRANSFORMSTATETYPE transform,const Matrix3D& m) -{ - Matrix4x4 m2(m); - switch ((int)transform) { - case D3DTS_WORLD: - render_state.world=m2.Transpose(); - render_state_changed|=(unsigned)WORLD_CHANGED; - render_state_changed&=~(unsigned)WORLD_IDENTITY; - break; - case D3DTS_VIEW: - render_state.view=m2.Transpose(); - render_state_changed|=(unsigned)VIEW_CHANGED; - render_state_changed&=~(unsigned)VIEW_IDENTITY; - break; - default: - DX8_RECORD_MATRIX_CHANGE(); - m2=m2.Transpose(); - DX8CALL(SetTransform(transform,(D3DMATRIX*)&m2)); - break; - } -} - -WWINLINE void DX8Wrapper::Set_World_Identity() -{ - if (render_state_changed&(unsigned)WORLD_IDENTITY) return; - render_state.world.Make_Identity(); - render_state_changed|=(unsigned)WORLD_CHANGED|(unsigned)WORLD_IDENTITY; -} - -WWINLINE void DX8Wrapper::Set_View_Identity() -{ - if (render_state_changed&(unsigned)VIEW_IDENTITY) return; - render_state.view.Make_Identity(); - render_state_changed|=(unsigned)VIEW_CHANGED|(unsigned)VIEW_IDENTITY; -} - -WWINLINE bool DX8Wrapper::Is_World_Identity() -{ - return !!(render_state_changed&(unsigned)WORLD_IDENTITY); -} - -WWINLINE bool DX8Wrapper::Is_View_Identity() -{ - return !!(render_state_changed&(unsigned)VIEW_IDENTITY); -} - -WWINLINE void DX8Wrapper::Get_Transform(D3DTRANSFORMSTATETYPE transform, Matrix4x4& m) -{ - D3DMATRIX mat; - - switch ((int)transform) { - case D3DTS_WORLD: - if (render_state_changed&WORLD_IDENTITY) m.Make_Identity(); - else m=render_state.world.Transpose(); - break; - case D3DTS_VIEW: - if (render_state_changed&VIEW_IDENTITY) m.Make_Identity(); - else m=render_state.view.Transpose(); - break; - default: - DX8CALL(GetTransform(transform,&mat)); - m=*(Matrix4x4*)&mat; - m=m.Transpose(); - break; - } -} - -WWINLINE const D3DLIGHT8& DX8Wrapper::Peek_Light(unsigned index) -{ - return render_state.Lights[index];; -} - -WWINLINE bool DX8Wrapper::Is_Light_Enabled(unsigned index) -{ - return render_state.LightEnable[index]; -} - - -WWINLINE void DX8Wrapper::Set_Render_State(const RenderStateStruct& state) -{ - int i; - - if (render_state.index_buffer) { - render_state.index_buffer->Release_Engine_Ref(); - } - - for (i=0;iRelease_Engine_Ref(); - } - } - - render_state=state; - render_state_changed=0xffffffff; - - if (render_state.index_buffer) { - render_state.index_buffer->Add_Engine_Ref(); - } - - for (i=0;iAdd_Engine_Ref(); - } - } -} - -WWINLINE void DX8Wrapper::Release_Render_State() -{ - int i; - - if (render_state.index_buffer) { - render_state.index_buffer->Release_Engine_Ref(); - } - - for (i=0;iRelease_Engine_Ref(); - } - } - - for (i=0;i Date: Fri, 1 Aug 2025 20:53:21 +0800 Subject: [PATCH 17/20] Move dx8wrapper to core --- .../Code => Core}/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp | 0 .../Code => Core}/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename {GeneralsMD/Code => Core}/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp (100%) rename {GeneralsMD/Code => Core}/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h (100%) diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/Core/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp similarity index 100% rename from GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp rename to Core/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h b/Core/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h similarity index 100% rename from GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h rename to Core/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h From fa23ec0361ed3b220fbd7e0a7e1f7401fb45a22c Mon Sep 17 00:00:00 2001 From: ryan-de-boer Date: Fri, 1 Aug 2025 20:46:36 +0800 Subject: [PATCH 18/20] Setup proper linking --- .../Common/Graphics/DX8/dx8wrapper_common.h | 4497 ---------------- .../Graphics/DX8/dx8wrapper_header_common.h | 1516 ------ .../Source/WWVegas/WW3D2/CMakeLists.txt | 4 +- .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 4500 +++++++++++++++++ .../Source/WWVegas/WW3D2/dx8wrapper.h | 1519 ++++++ .../Source/WWVegas/WW3D2/CMakeLists.txt | 4 +- .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 1 - .../Source/WWVegas/WW3D2/dx8wrapper.h | 1 - .../Source/WWVegas/WW3D2/CMakeLists.txt | 4 +- 9 files changed, 6025 insertions(+), 6021 deletions(-) delete mode 100644 Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h delete mode 100644 Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_header_common.h delete mode 100644 Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp delete mode 100644 Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h diff --git a/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h b/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h deleted file mode 100644 index 7d258b1bfbe..00000000000 --- a/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h +++ /dev/null @@ -1,4497 +0,0 @@ -/* -** Command & Conquer Generals Zero Hour(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/dx8wrapper.cpp $* - * * - * Original Author:: Jani Penttinen * - * * - * $Author:: Kenny Mitchell * - * * - * $Modtime:: 08/05/02 1:27p $* - * * - * $Revision:: 170 $* - * * - * 06/26/02 KM Matrix name change to avoid MAX conflicts * - * 06/27/02 KM Render to shadow buffer texture support * - * 06/27/02 KM Shader system updates * - * 08/05/02 KM Texture class redesign - *---------------------------------------------------------------------------------------------* - * Functions: * - * DX8Wrapper::_Update_Texture -- Copies a texture from system memory to video memory * - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - - //#define CREATE_DX8_MULTI_THREADED - //#define CREATE_DX8_FPU_PRESERVE -#define WW3D_DEVTYPE D3DDEVTYPE_HAL - -#if defined(_MSC_VER) && _MSC_VER < 1300 -#undef WINVER -#define WINVER 0x0500 // Required to access GetMonitorInfo in VC6. -#endif - -#include "dx8wrapper.h" -#include "dx8webbrowser.h" -#include "dx8fvf.h" -#include "dx8vertexbuffer.h" -#include "dx8indexbuffer.h" -#include "dx8renderer.h" -#include "ww3d.h" -#include "camera.h" -#include "wwstring.h" -#include "matrix4.h" -#include "vertmaterial.h" -#include "rddesc.h" -#include "lightenvironment.h" -#include "statistics.h" -#include "registry.h" -#include "boxrobj.h" -#include "pointgr.h" -#include "render2d.h" -#include "sortingrenderer.h" -#include "shattersystem.h" -#include "light.h" -#include "assetmgr.h" -#include "textureloader.h" -#include "missingtexture.h" -#include "thread.h" -#include -#include -#include "pot.h" -#include "wwprofile.h" -#include "ffactory.h" -#include "dx8caps.h" -#include "formconv.h" -#include "dx8texman.h" -#include "bound.h" -#include "dx8webbrowser.h" - -#include "shdlib.h" - -const int DEFAULT_RESOLUTION_WIDTH = 640; -const int DEFAULT_RESOLUTION_HEIGHT = 480; -const int DEFAULT_BIT_DEPTH = 32; -const int DEFAULT_TEXTURE_BIT_DEPTH = 16; - -bool DX8Wrapper_IsWindowed = true; - -// FPU_PRESERVE -int DX8Wrapper_PreserveFPU = 0; - -/*********************************************************************************** -** -** DX8Wrapper Static Variables -** -***********************************************************************************/ - -static HWND _Hwnd = NULL; -bool DX8Wrapper::IsInitted = false; -bool DX8Wrapper::_EnableTriangleDraw = true; - -int DX8Wrapper::CurRenderDevice = -1; -int DX8Wrapper::ResolutionWidth = DEFAULT_RESOLUTION_WIDTH; -int DX8Wrapper::ResolutionHeight = DEFAULT_RESOLUTION_HEIGHT; -int DX8Wrapper::BitDepth = DEFAULT_BIT_DEPTH; -int DX8Wrapper::TextureBitDepth = DEFAULT_TEXTURE_BIT_DEPTH; -bool DX8Wrapper::IsWindowed = false; -D3DFORMAT DX8Wrapper::DisplayFormat = D3DFMT_UNKNOWN; - -D3DMATRIX DX8Wrapper::old_world; -D3DMATRIX DX8Wrapper::old_view; -D3DMATRIX DX8Wrapper::old_prj; - -// shader system additions KJM v -DWORD DX8Wrapper::Vertex_Shader = 0; -DWORD DX8Wrapper::Pixel_Shader = 0; - -Vector4 DX8Wrapper::Vertex_Shader_Constants[MAX_VERTEX_SHADER_CONSTANTS]; -Vector4 DX8Wrapper::Pixel_Shader_Constants[MAX_PIXEL_SHADER_CONSTANTS]; - -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]; -IDirect3DBaseTexture8* DX8Wrapper::Textures[MAX_TEXTURE_STAGES]; -RenderStateStruct DX8Wrapper::render_state; -unsigned DX8Wrapper::render_state_changed; - -bool DX8Wrapper::FogEnable = false; -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; -unsigned DX8Wrapper::material_changes = 0; -unsigned DX8Wrapper::vertex_buffer_changes = 0; -unsigned DX8Wrapper::index_buffer_changes = 0; -unsigned DX8Wrapper::light_changes = 0; -unsigned DX8Wrapper::texture_changes = 0; -unsigned DX8Wrapper::render_state_changes = 0; -unsigned DX8Wrapper::texture_stage_state_changes = 0; -unsigned DX8Wrapper::draw_calls = 0; -unsigned DX8Wrapper::_MainThreadID = 0; -bool DX8Wrapper::CurrentDX8LightEnables[4]; -bool DX8Wrapper::IsDeviceLost; -int DX8Wrapper::ZBias; -float DX8Wrapper::ZNear; -float DX8Wrapper::ZFar; -Matrix4x4 DX8Wrapper::ProjectionMatrix; -Matrix4x4 DX8Wrapper::DX8Transforms[D3DTS_WORLD + 1]; - -DX8Caps* DX8Wrapper::CurrentCaps = 0; - -// Hack test... this disables rendering of batches of too few polygons. -unsigned DX8Wrapper::DrawPolygonLowBoundLimit = 0; - -D3DADAPTER_IDENTIFIER8 DX8Wrapper::CurrentAdapterIdentifier; - -unsigned long DX8Wrapper::FrameCount = 0; - -bool _DX8SingleThreaded = false; - -unsigned number_of_DX8_calls = 0; -static unsigned last_frame_matrix_changes = 0; -static unsigned last_frame_material_changes = 0; -static unsigned last_frame_vertex_buffer_changes = 0; -static unsigned last_frame_index_buffer_changes = 0; -static unsigned last_frame_light_changes = 0; -static unsigned last_frame_texture_changes = 0; -static unsigned last_frame_render_state_changes = 0; -static unsigned last_frame_texture_stage_state_changes = 0; -static unsigned last_frame_number_of_DX8_calls = 0; -static unsigned last_frame_draw_calls = 0; - -static D3DDISPLAYMODE DesktopMode; - -static D3DPRESENT_PARAMETERS _PresentParameters; -static DynamicVectorClass _RenderDeviceNameTable; -static DynamicVectorClass _RenderDeviceShortNameTable; -static DynamicVectorClass _RenderDeviceDescriptionTable; - - -typedef IDirect3D8* (WINAPI* Direct3DCreate8Type) (UINT SDKVersion); -Direct3DCreate8Type Direct3DCreate8Ptr = NULL; -HINSTANCE D3D8Lib = NULL; - -DX8_CleanupHook* DX8Wrapper::m_pCleanupHook = NULL; -#ifdef EXTENDED_STATS -DX8_Stats DX8Wrapper::stats; -#endif -/*********************************************************************************** -** -** DX8Wrapper Implementation -** -***********************************************************************************/ - -void Log_DX8_ErrorCode(unsigned res) -{ - char tmp[256] = ""; - - HRESULT new_res = D3DXGetErrorStringA( - res, - tmp, - sizeof(tmp)); - - if (new_res == D3D_OK) { - WWDEBUG_SAY((tmp)); - } - - WWASSERT(0); -} - -void Non_Fatal_Log_DX8_ErrorCode(unsigned res, const char* file, int line) -{ - char tmp[256] = ""; - - HRESULT new_res = D3DXGetErrorStringA( - res, - tmp, - sizeof(tmp)); - - if (new_res == D3D_OK) { - WWDEBUG_SAY(("DX8 Error: %s, File: %s, Line: %d", tmp, file, line)); - } -} - -// TheSuperHackers @info helmutbuhler 14/04/2025 -// Helper function that moves x and y such that the inner rect fits into the outer rect. -// If the inner rect already is in the outer rect, then this does nothing. -// If the inner rect is larger than the outer rect, then the inner rect will be aligned to the top left of the outer rect. -void MoveRectIntoOtherRect(const RECT& inner, const RECT& outer, int* x, int* y) -{ - int dx = 0; - if (inner.right > outer.right) - dx = outer.right - inner.right; - if (inner.left < outer.left) - dx = outer.left - inner.left; - - int dy = 0; - if (inner.bottom > outer.bottom) - dy = outer.bottom - inner.bottom; - if (inner.top < outer.top) - dy = outer.top - inner.top; - - *x += dx; - *y += dy; -} - -bool DX8Wrapper::Init(void* hwnd, bool lite) -{ - WWASSERT(!IsInitted); - - // zero memory - memset(Textures, 0, sizeof(IDirect3DBaseTexture8*) * MAX_TEXTURE_STAGES); - memset(RenderStates, 0, sizeof(unsigned) * 256); - memset(TextureStageStates, 0, sizeof(unsigned) * 32 * MAX_TEXTURE_STAGES); - 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! - */ - _Hwnd = (HWND)hwnd; - _MainThreadID = ThreadClass::_Get_Current_Thread_ID(); - WWDEBUG_SAY(("DX8Wrapper main thread: 0x%x", _MainThreadID)); - CurRenderDevice = -1; - ResolutionWidth = DEFAULT_RESOLUTION_WIDTH; - ResolutionHeight = DEFAULT_RESOLUTION_HEIGHT; - // Initialize Render2DClass Screen Resolution - Render2DClass::Set_Screen_Resolution(RectClass(0, 0, ResolutionWidth, ResolutionHeight)); - BitDepth = DEFAULT_BIT_DEPTH; - IsWindowed = false; - DX8Wrapper_IsWindowed = false; - - for (int light = 0; light < 4; ++light) CurrentDX8LightEnables[light] = false; - - ::ZeroMemory(&old_world, sizeof(D3DMATRIX)); - ::ZeroMemory(&old_view, sizeof(D3DMATRIX)); - ::ZeroMemory(&old_prj, sizeof(D3DMATRIX)); - - //old_vertex_shader; TODO - //old_sr_shader; - //current_shader; - - //world_identity; - //CurrentFogColor; - - D3DInterface = NULL; - D3DDevice = NULL; - - WWDEBUG_SAY(("Reset DX8Wrapper statistics")); - Reset_Statistics(); - - Invalidate_Cached_Render_States(); - - if (!lite) { - D3D8Lib = LoadLibrary("D3D8.DLL"); - - if (D3D8Lib == NULL) return false; // Return false at this point if init failed - - Direct3DCreate8Ptr = (Direct3DCreate8Type)GetProcAddress(D3D8Lib, "Direct3DCreate8"); - if (Direct3DCreate8Ptr == NULL) return false; - - /* - ** Create the D3D interface object - */ - WWDEBUG_SAY(("Create Direct3D8")); - D3DInterface = Direct3DCreate8Ptr(D3D_SDK_VERSION); // TODO: handle failure cases... - if (D3DInterface == NULL) { - return(false); - } - IsInitted = true; - - /* - ** Enumerate the available devices - */ - WWDEBUG_SAY(("Enumerate devices")); - Enumerate_Devices(); - WWDEBUG_SAY(("DX8Wrapper Init completed")); - } - - return(true); -} - -void DX8Wrapper::Shutdown(void) -{ - if (D3DDevice) { - - Set_Render_Target((IDirect3DSurface8*)NULL); - Release_Device(); - } - - if (D3DInterface) { - D3DInterface->Release(); - D3DInterface = NULL; - - } - - if (CurrentCaps) - { - int max = CurrentCaps->Get_Max_Textures_Per_Pass(); - for (int i = 0; i < max; i++) - { - if (Textures[i]) - { - Textures[i]->Release(); - Textures[i] = NULL; - } - } - } - - if (D3DInterface) { - UINT newRefCount = D3DInterface->Release(); - D3DInterface = NULL; - } - - if (D3D8Lib) { - FreeLibrary(D3D8Lib); - D3D8Lib = NULL; - } - - _RenderDeviceNameTable.Clear(); // note - Delete_All() resizes the vector, causing a reallocation. Clear is better. jba. - _RenderDeviceShortNameTable.Clear(); - _RenderDeviceDescriptionTable.Clear(); - - DX8Caps::Shutdown(); - IsInitted = false; // 010803 srj -} - -void DX8Wrapper::Do_Onetime_Device_Dependent_Inits(void) -{ - /* - ** Set Global render states (some of which depend on caps) - */ - Compute_Caps(D3DFormat_To_WW3DFormat(DisplayFormat)); - - /* - ** Initalize any other subsystems inside of WW3D - */ - MissingTexture::_Init(); - TextureFilterClass::_Init_Filters((TextureFilterClass::TextureFilterMode)WW3D::Get_Texture_Filter()); - TheDX8MeshRenderer.Init(); - SHD_INIT; - BoxRenderObjClass::Init(); - VertexMaterialClass::Init(); - PointGroupClass::_Init(); // This needs the VertexMaterialClass to be initted - ShatterSystem::Init(); - TextureLoader::Init(); - - Set_Default_Global_Render_States(); -} - -inline DWORD F2DW(float f) { return *((unsigned*)&f); } -void DX8Wrapper::Set_Default_Global_Render_States(void) -{ - DX8_THREAD_ASSERT(); - const D3DCAPS8& caps = Get_Current_Caps()->Get_DX8_Caps(); - - Set_DX8_Render_State(D3DRS_RANGEFOGENABLE, (caps.RasterCaps & D3DPRASTERCAPS_FOGRANGE) ? TRUE : FALSE); - Set_DX8_Render_State(D3DRS_FOGTABLEMODE, D3DFOG_NONE); - Set_DX8_Render_State(D3DRS_FOGVERTEXMODE, D3DFOG_LINEAR); - Set_DX8_Render_State(D3DRS_SPECULARMATERIALSOURCE, D3DMCS_MATERIAL); - Set_DX8_Render_State(D3DRS_COLORVERTEX, TRUE); - Set_DX8_Render_State(D3DRS_ZBIAS, 0); - Set_DX8_Texture_Stage_State(1, D3DTSS_BUMPENVLSCALE, F2DW(1.0f)); - Set_DX8_Texture_Stage_State(1, D3DTSS_BUMPENVLOFFSET, F2DW(0.0f)); - Set_DX8_Texture_Stage_State(0, D3DTSS_BUMPENVMAT00, F2DW(1.0f)); - Set_DX8_Texture_Stage_State(0, D3DTSS_BUMPENVMAT01, F2DW(0.0f)); - Set_DX8_Texture_Stage_State(0, D3DTSS_BUMPENVMAT10, F2DW(0.0f)); - Set_DX8_Texture_Stage_State(0, D3DTSS_BUMPENVMAT11, F2DW(1.0f)); - - // Set_DX8_Render_State(D3DRS_CULLMODE, D3DCULL_CW); - // Set dither mode here? -} - -//MW: I added this for 'Generals'. -bool DX8Wrapper::Validate_Device(void) -{ - DWORD numPasses = 0; - HRESULT hRes; - - hRes = _Get_D3D_Device8()->ValidateDevice(&numPasses); - - return (hRes == D3D_OK); -} - -void DX8Wrapper::Invalidate_Cached_Render_States(void) -{ - render_state_changed = 0; - - int a; - for (a = 0; a < sizeof(RenderStates) / sizeof(unsigned); ++a) { - RenderStates[a] = 0x12345678; - } - for (a = 0; a < MAX_TEXTURE_STAGES; ++a) - { - for (int b = 0; b < 32; b++) - { - TextureStageStates[a][b] = 0x12345678; - } - //Need to explicitly set texture to NULL, otherwise app will not be able to - //set it to null because of redundant state checker. MW - if (_Get_D3D_Device8()) - _Get_D3D_Device8()->SetTexture(a, NULL); - if (Textures[a] != NULL) { - Textures[a]->Release(); - } - Textures[a] = NULL; - } - - ShaderClass::Invalidate(); - - //Need to explicitly set render_state texture pointers to NULL. MW - Release_Render_State(); - - // (gth) clear the matrix shadows too - for (int i = 0; i < D3DTS_WORLD + 1; i++) { - DX8Transforms[i][0].Set(0, 0, 0, 0); - DX8Transforms[i][1].Set(0, 0, 0, 0); - DX8Transforms[i][2].Set(0, 0, 0, 0); - DX8Transforms[i][3].Set(0, 0, 0, 0); - } - -} - -void DX8Wrapper::Do_Onetime_Device_Dependent_Shutdowns(void) -{ - /* - ** Shutdown ww3d systems - */ - int i; - for (i = 0; i < MAX_VERTEX_STREAMS; ++i) { - if (render_state.vertex_buffers[i]) render_state.vertex_buffers[i]->Release_Engine_Ref(); - REF_PTR_RELEASE(render_state.vertex_buffers[i]); - } - if (render_state.index_buffer) render_state.index_buffer->Release_Engine_Ref(); - REF_PTR_RELEASE(render_state.index_buffer); - REF_PTR_RELEASE(render_state.material); - for (i = 0; i < CurrentCaps->Get_Max_Textures_Per_Pass(); ++i) REF_PTR_RELEASE(render_state.Textures[i]); - - - TextureLoader::Deinit(); - SortingRendererClass::Deinit(); - DynamicVBAccessClass::_Deinit(); - DynamicIBAccessClass::_Deinit(); - ShatterSystem::Shutdown(); - PointGroupClass::_Shutdown(); - VertexMaterialClass::Shutdown(); - BoxRenderObjClass::Shutdown(); - SHD_SHUTDOWN; - TheDX8MeshRenderer.Shutdown(); - MissingTexture::_Deinit(); - - if (CurrentCaps) { - delete CurrentCaps; - CurrentCaps = NULL; - } - -} - -bool DX8Wrapper::Create_Device(void) -{ - WWASSERT(D3DDevice == NULL); // for now, once you've created a device, you're stuck with it! - - D3DCAPS8 caps; - if - ( - FAILED - ( - D3DInterface->GetDeviceCaps - ( - CurRenderDevice, - WW3D_DEVTYPE, - &caps - ) - ) - ) - { - return false; - } - - ::ZeroMemory(&CurrentAdapterIdentifier, sizeof(D3DADAPTER_IDENTIFIER8)); - - if - ( - FAILED - ( - D3DInterface->GetAdapterIdentifier - ( - CurRenderDevice, - D3DENUM_NO_WHQL_LEVEL, - &CurrentAdapterIdentifier - ) - ) - ) - { - return false; - } - -#ifndef _XBOX - - Vertex_Processing_Behavior = (caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) ? - D3DCREATE_MIXED_VERTEXPROCESSING : D3DCREATE_SOFTWARE_VERTEXPROCESSING; - - // enable this when all 'get' dx calls are removed KJM - /*if (caps.DevCaps&D3DDEVCAPS_PUREDEVICE) - { - Vertex_Processing_Behavior|=D3DCREATE_PUREDEVICE; - }*/ - -#else // XBOX - Vertex_Processing_Behavior = D3DCREATE_PUREDEVICE; -#endif // XBOX - -#ifdef CREATE_DX8_MULTI_THREADED - Vertex_Processing_Behavior |= D3DCREATE_MULTITHREADED; - _DX8SingleThreaded = false; -#else - _DX8SingleThreaded = true; -#endif - - if (DX8Wrapper_PreserveFPU) - Vertex_Processing_Behavior |= D3DCREATE_FPU_PRESERVE; - -#ifdef CREATE_DX8_FPU_PRESERVE - Vertex_Processing_Behavior |= D3DCREATE_FPU_PRESERVE; -#endif - - HRESULT hr = D3DInterface->CreateDevice - ( - CurRenderDevice, - WW3D_DEVTYPE, - _Hwnd, - Vertex_Processing_Behavior, - &_PresentParameters, - &D3DDevice - ); - - if (FAILED(hr)) - { - // The device selection may fail because the device lied that it supports 32 bit zbuffer with 16 bit - // display. This happens at least on Voodoo2. - - if ((_PresentParameters.BackBufferFormat == D3DFMT_R5G6B5 || - _PresentParameters.BackBufferFormat == D3DFMT_X1R5G5B5 || - _PresentParameters.BackBufferFormat == D3DFMT_A1R5G5B5) && - (_PresentParameters.AutoDepthStencilFormat == D3DFMT_D32 || - _PresentParameters.AutoDepthStencilFormat == D3DFMT_D24S8 || - _PresentParameters.AutoDepthStencilFormat == D3DFMT_D24X8)) - { - _PresentParameters.AutoDepthStencilFormat = D3DFMT_D16; - hr = D3DInterface->CreateDevice - ( - CurRenderDevice, - WW3D_DEVTYPE, - _Hwnd, - Vertex_Processing_Behavior, - &_PresentParameters, - &D3DDevice - ); - - if (FAILED(hr)) - { - return false; - } - } - else - { - return false; - } - } - - /* - ** Initialize all subsystems - */ - Do_Onetime_Device_Dependent_Inits(); - return true; -} - -bool DX8Wrapper::Reset_Device(bool reload_assets) -{ - WWDEBUG_SAY(("Resetting device.")); - DX8_THREAD_ASSERT(); - if ((IsInitted) && (D3DDevice != NULL)) { - // Release all non-MANAGED stuff - WW3D::_Invalidate_Textures(); - - for (unsigned i = 0; i < MAX_VERTEX_STREAMS; ++i) - { - Set_Vertex_Buffer(NULL, i); - } - Set_Index_Buffer(NULL, 0); - if (m_pCleanupHook) { - m_pCleanupHook->ReleaseResources(); - } - DynamicVBAccessClass::_Deinit(); - DynamicIBAccessClass::_Deinit(); - DX8TextureManagerClass::Release_Textures(); - SHD_SHUTDOWN_SHADERS; - - // Reset frame count to reflect the flipping chain being reset by Reset() - FrameCount = 0; - - memset(Vertex_Shader_Constants, 0, sizeof(Vector4) * MAX_VERTEX_SHADER_CONSTANTS); - memset(Pixel_Shader_Constants, 0, sizeof(Vector4) * MAX_PIXEL_SHADER_CONSTANTS); - - HRESULT hr = _Get_D3D_Device8()->TestCooperativeLevel(); - if (hr != D3DERR_DEVICELOST) - { - DX8CALL_HRES(Reset(&_PresentParameters), hr) - if (hr != D3D_OK) - return false; //reset failed. - } - else - return false; //device is lost and can't be reset. - - if (reload_assets) - { - DX8TextureManagerClass::Recreate_Textures(); - if (m_pCleanupHook) { - m_pCleanupHook->ReAcquireResources(); - } - } - Invalidate_Cached_Render_States(); - Set_Default_Global_Render_States(); - SHD_INIT_SHADERS; - WWDEBUG_SAY(("Device reset completed")); - return true; - } - WWDEBUG_SAY(("Device reset failed")); - return false; -} - -void DX8Wrapper::Release_Device(void) -{ - if (D3DDevice) { - - for (int a = 0; a < MAX_TEXTURE_STAGES; ++a) - { //release references to any textures that were used in last rendering call - DX8CALL(SetTexture(a, NULL)); - } - - DX8CALL(SetStreamSource(0, NULL, 0)); //release reference count on last rendered vertex buffer - DX8CALL(SetIndices(NULL, 0)); //release reference count on last rendered index buffer - - - /* - ** Release the current vertex and index buffers - */ - for (unsigned i = 0; i < MAX_VERTEX_STREAMS; ++i) - { - if (render_state.vertex_buffers[i]) render_state.vertex_buffers[i]->Release_Engine_Ref(); - REF_PTR_RELEASE(render_state.vertex_buffers[i]); - } - if (render_state.index_buffer) render_state.index_buffer->Release_Engine_Ref(); - REF_PTR_RELEASE(render_state.index_buffer); - - /* - ** Shutdown all subsystems - */ - Do_Onetime_Device_Dependent_Shutdowns(); - - /* - ** Release the device - */ - - D3DDevice->Release(); - D3DDevice = NULL; - } -} - -void DX8Wrapper::Enumerate_Devices() -{ - DX8_Assert(); - - int adapter_count = D3DInterface->GetAdapterCount(); - for (int adapter_index = 0; adapter_index < adapter_count; adapter_index++) { - - D3DADAPTER_IDENTIFIER8 id; - ::ZeroMemory(&id, sizeof(D3DADAPTER_IDENTIFIER8)); - HRESULT res = D3DInterface->GetAdapterIdentifier(adapter_index, D3DENUM_NO_WHQL_LEVEL, &id); - - if (res == D3D_OK) { - - /* - ** Set up the render device description - ** TODO: Fill in more fields of the render device description? (need some lookup tables) - */ - RenderDeviceDescClass desc; - desc.set_device_name(id.Description); - desc.set_driver_name(id.Driver); - - char buf[64]; - sprintf(buf, "%d.%d.%d.%d", //"%04x.%04x.%04x.%04x", - HIWORD(id.DriverVersion.HighPart), - LOWORD(id.DriverVersion.HighPart), - HIWORD(id.DriverVersion.LowPart), - LOWORD(id.DriverVersion.LowPart)); - - desc.set_driver_version(buf); - - D3DInterface->GetDeviceCaps(adapter_index, WW3D_DEVTYPE, &desc.Caps); - D3DInterface->GetAdapterIdentifier(adapter_index, D3DENUM_NO_WHQL_LEVEL, &desc.AdapterIdentifier); - - DX8Caps dx8caps(D3DInterface, desc.Caps, WW3D_FORMAT_UNKNOWN, desc.AdapterIdentifier); - - /* - ** Enumerate the resolutions - */ - desc.reset_resolution_list(); - int mode_count = D3DInterface->GetAdapterModeCount(adapter_index); - for (int mode_index = 0; mode_index < mode_count; mode_index++) { - D3DDISPLAYMODE d3dmode; - ::ZeroMemory(&d3dmode, sizeof(D3DDISPLAYMODE)); - HRESULT res = D3DInterface->EnumAdapterModes(adapter_index, mode_index, &d3dmode); - - if (res == D3D_OK) { - int bits = 0; - switch (d3dmode.Format) - { - case D3DFMT_R8G8B8: - case D3DFMT_A8R8G8B8: - case D3DFMT_X8R8G8B8: bits = 32; break; - - case D3DFMT_R5G6B5: - case D3DFMT_X1R5G5B5: bits = 16; break; - } - - // Some cards fail in certain modes, DX8Caps keeps list of those. - if (!dx8caps.Is_Valid_Display_Format(d3dmode.Width, d3dmode.Height, D3DFormat_To_WW3DFormat(d3dmode.Format))) { - bits = 0; - } - - /* - ** If we recognize the format, add it to the list - ** TODO: should we handle more formats? will any cards report more than 24 or 16 bit? - */ - if (bits != 0) { - desc.add_resolution(d3dmode.Width, d3dmode.Height, bits); - } - } - } - - // IML: If the device has one or more valid resolutions add it to the device list. - // NOTE: Testing has shown that there are drivers with zero resolutions. - if (desc.Enumerate_Resolutions().Count() > 0) { - - /* - ** Set up the device name - */ - StringClass device_name(id.Description, true); - _RenderDeviceNameTable.Add(device_name); - _RenderDeviceShortNameTable.Add(device_name); // for now, just add the same name to the "pretty name table" - - /* - ** Add the render device to our table - */ - _RenderDeviceDescriptionTable.Add(desc); - } - } - } -} - - -bool DX8Wrapper::Set_Any_Render_Device(void) -{ - // Then fullscreen - int dev_number = 0; - for (; dev_number < _RenderDeviceNameTable.Count(); dev_number++) { - if (Set_Render_Device(dev_number, -1, -1, -1, 0, false)) { - return true; - } - } - - // Try windowed first - for (dev_number = 0; dev_number < _RenderDeviceNameTable.Count(); dev_number++) { - if (Set_Render_Device(dev_number, -1, -1, -1, 1, false)) { - return true; - } - } - - return false; -} - -bool DX8Wrapper::Set_Render_Device -( - const char* dev_name, - int width, - int height, - int bits, - int windowed, - bool resize_window -) -{ - for (int dev_number = 0; dev_number < _RenderDeviceNameTable.Count(); dev_number++) { - if (strcmp(dev_name, _RenderDeviceNameTable[dev_number]) == 0) { - return Set_Render_Device(dev_number, width, height, bits, windowed, resize_window); - } - - if (strcmp(dev_name, _RenderDeviceShortNameTable[dev_number]) == 0) { - return Set_Render_Device(dev_number, width, height, bits, windowed, resize_window); - } - } - return false; -} - -void DX8Wrapper::Get_Format_Name(unsigned int format, StringClass* tex_format) -{ - *tex_format = "Unknown"; - switch (format) { - case D3DFMT_A8R8G8B8: *tex_format = "D3DFMT_A8R8G8B8"; break; - case D3DFMT_R8G8B8: *tex_format = "D3DFMT_R8G8B8"; break; - case D3DFMT_A4R4G4B4: *tex_format = "D3DFMT_A4R4G4B4"; break; - case D3DFMT_A1R5G5B5: *tex_format = "D3DFMT_A1R5G5B5"; break; - case D3DFMT_R5G6B5: *tex_format = "D3DFMT_R5G6B5"; break; - case D3DFMT_L8: *tex_format = "D3DFMT_L8"; break; - case D3DFMT_A8: *tex_format = "D3DFMT_A8"; break; - case D3DFMT_P8: *tex_format = "D3DFMT_P8"; break; - case D3DFMT_X8R8G8B8: *tex_format = "D3DFMT_X8R8G8B8"; break; - case D3DFMT_X1R5G5B5: *tex_format = "D3DFMT_X1R5G5B5"; break; - case D3DFMT_R3G3B2: *tex_format = "D3DFMT_R3G3B2"; break; - case D3DFMT_A8R3G3B2: *tex_format = "D3DFMT_A8R3G3B2"; break; - case D3DFMT_X4R4G4B4: *tex_format = "D3DFMT_X4R4G4B4"; break; - case D3DFMT_A8P8: *tex_format = "D3DFMT_A8P8"; break; - case D3DFMT_A8L8: *tex_format = "D3DFMT_A8L8"; break; - case D3DFMT_A4L4: *tex_format = "D3DFMT_A4L4"; break; - case D3DFMT_V8U8: *tex_format = "D3DFMT_V8U8"; break; - case D3DFMT_L6V5U5: *tex_format = "D3DFMT_L6V5U5"; break; - case D3DFMT_X8L8V8U8: *tex_format = "D3DFMT_X8L8V8U8"; break; - case D3DFMT_Q8W8V8U8: *tex_format = "D3DFMT_Q8W8V8U8"; break; - case D3DFMT_V16U16: *tex_format = "D3DFMT_V16U16"; break; - case D3DFMT_W11V11U10: *tex_format = "D3DFMT_W11V11U10"; break; - case D3DFMT_UYVY: *tex_format = "D3DFMT_UYVY"; break; - case D3DFMT_YUY2: *tex_format = "D3DFMT_YUY2"; break; - case D3DFMT_DXT1: *tex_format = "D3DFMT_DXT1"; break; - case D3DFMT_DXT2: *tex_format = "D3DFMT_DXT2"; break; - case D3DFMT_DXT3: *tex_format = "D3DFMT_DXT3"; break; - case D3DFMT_DXT4: *tex_format = "D3DFMT_DXT4"; break; - case D3DFMT_DXT5: *tex_format = "D3DFMT_DXT5"; break; - case D3DFMT_D16_LOCKABLE: *tex_format = "D3DFMT_D16_LOCKABLE"; break; - case D3DFMT_D32: *tex_format = "D3DFMT_D32"; break; - case D3DFMT_D15S1: *tex_format = "D3DFMT_D15S1"; break; - case D3DFMT_D24S8: *tex_format = "D3DFMT_D24S8"; break; - case D3DFMT_D16: *tex_format = "D3DFMT_D16"; break; - case D3DFMT_D24X8: *tex_format = "D3DFMT_D24X8"; break; - case D3DFMT_D24X4S4: *tex_format = "D3DFMT_D24X4S4"; break; - default: break; - } -} - -void DX8Wrapper::Resize_And_Position_Window() -{ - // Get the current dimensions of the 'render area' of the window - RECT rect = { 0 }; - ::GetClientRect(_Hwnd, &rect); - - // Is the window the correct size for this resolution? - if ((rect.right - rect.left) != ResolutionWidth || - (rect.bottom - rect.top) != ResolutionHeight) { - - // Calculate what the main window's bounding rectangle should be to - // accommodate this resolution - rect.left = 0; - rect.top = 0; - rect.right = ResolutionWidth; - rect.bottom = ResolutionHeight; - DWORD dwstyle = ::GetWindowLong(_Hwnd, GWL_STYLE); - AdjustWindowRect(&rect, dwstyle, FALSE); - int width = rect.right - rect.left; - int height = rect.bottom - rect.top; - - // Resize the window to fit this resolution - if (!IsWindowed) - { - ::SetWindowPos(_Hwnd, HWND_TOPMOST, 0, 0, width, height, SWP_NOSIZE | SWP_NOMOVE); - - DEBUG_LOG(("Window resized to w:%d h:%d", width, height)); - } - else - { - // TheSuperHackers @feature helmutbuhler 14/04/2025 - // Center the window in the workarea of the monitor it is on. - MONITORINFO mi = { sizeof(MONITORINFO) }; - GetMonitorInfo(MonitorFromWindow(_Hwnd, MONITOR_DEFAULTTOPRIMARY), &mi); - int left = (mi.rcWork.left + mi.rcWork.right - width) / 2; - int top = (mi.rcWork.top + mi.rcWork.bottom - height) / 2; - - // TheSuperHackers @feature helmutbuhler 14/04/2025 - // Move the window to try fit it into the monitor area, if one of its dimensions is larger than the work area. - // Otherwise align the window to the top left edges, if it is even larger than the monitor area. - RECT rectClient; - rectClient.left = left - rect.left; - rectClient.top = top - rect.top; - rectClient.right = rectClient.left + ResolutionWidth; - rectClient.bottom = rectClient.top + ResolutionHeight; - MoveRectIntoOtherRect(rectClient, mi.rcMonitor, &left, &top); - - ::SetWindowPos(_Hwnd, NULL, left, top, width, height, SWP_NOZORDER); - - DEBUG_LOG(("Window positioned to x:%d y:%d, resized to w:%d h:%d", left, top, width, height)); - } - } -} - - - -bool DX8Wrapper::Set_Render_Device(int dev, int width, int height, int bits, int windowed, - bool resize_window, bool reset_device, bool restore_assets) -{ - WWASSERT(IsInitted); - WWASSERT(dev >= -1); - WWASSERT(dev < _RenderDeviceNameTable.Count()); - - /* - ** If user has never selected a render device, start out with device 0 - */ - if ((CurRenderDevice == -1) && (dev == -1)) { - CurRenderDevice = 0; - } - else if (dev != -1) { - CurRenderDevice = dev; - } - - /* - ** If user doesn't want to change res, set the res variables to match the - ** current resolution - */ - if (width != -1) ResolutionWidth = width; - if (height != -1) ResolutionHeight = height; - - // Initialize Render2DClass Screen Resolution - Render2DClass::Set_Screen_Resolution(RectClass(0, 0, ResolutionWidth, ResolutionHeight)); - - if (bits != -1) BitDepth = bits; - if (windowed != -1) IsWindowed = (windowed != 0); - DX8Wrapper_IsWindowed = IsWindowed; - - WWDEBUG_SAY(("Attempting Set_Render_Device: name: %s (%s:%s), width: %d, height: %d, windowed: %d", - _RenderDeviceNameTable[CurRenderDevice].str(), _RenderDeviceDescriptionTable[CurRenderDevice].Get_Driver_Name(), - _RenderDeviceDescriptionTable[CurRenderDevice].Get_Driver_Version(), ResolutionWidth, ResolutionHeight, (IsWindowed ? 1 : 0))); - -#ifdef _WINDOWS - // PWG 4/13/2000 - changed so that if you say to resize the window it resizes - // regardless of whether its windowed or not as OpenGL resizes its self around - // the caption and edges of the window type you provide, so its important to - // push the client area to be the size you really want. - // if ( resize_window && windowed ) { - if (resize_window) { - Resize_And_Position_Window(); - } -#endif - //must be either resetting existing device or creating a new one. - WWASSERT(reset_device || D3DDevice == NULL); - - /* - ** Initialize values for D3DPRESENT_PARAMETERS members. - */ - ::ZeroMemory(&_PresentParameters, sizeof(D3DPRESENT_PARAMETERS)); - - _PresentParameters.BackBufferWidth = ResolutionWidth; - _PresentParameters.BackBufferHeight = ResolutionHeight; - _PresentParameters.BackBufferCount = IsWindowed ? 1 : 2; - - _PresentParameters.MultiSampleType = D3DMULTISAMPLE_NONE; - //I changed this to discard all the time (even when full-screen) since that the most efficient. 07-16-03 MW: - _PresentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;//IsWindowed ? D3DSWAPEFFECT_DISCARD : D3DSWAPEFFECT_FLIP; // Shouldn't this be D3DSWAPEFFECT_FLIP? - _PresentParameters.hDeviceWindow = _Hwnd; - _PresentParameters.Windowed = IsWindowed; - - _PresentParameters.EnableAutoDepthStencil = TRUE; // Driver will attempt to match Z-buffer depth - _PresentParameters.Flags = 0; // We're not going to lock the backbuffer - - _PresentParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; - _PresentParameters.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT; - - /* - ** Set up the buffer formats. Several issues here: - ** - if in windowed mode, the backbuffer must use the current display format. - ** - the depth buffer must use - */ - if (IsWindowed) { - - D3DDISPLAYMODE desktop_mode; - ::ZeroMemory(&desktop_mode, sizeof(D3DDISPLAYMODE)); - D3DInterface->GetAdapterDisplayMode(CurRenderDevice, &desktop_mode); - - DisplayFormat = _PresentParameters.BackBufferFormat = desktop_mode.Format; - - // In windowed mode, define the bitdepth from desktop mode (as it can't be changed) - switch (_PresentParameters.BackBufferFormat) { - case D3DFMT_X8R8G8B8: - case D3DFMT_A8R8G8B8: - case D3DFMT_R8G8B8: BitDepth = 32; break; - case D3DFMT_A4R4G4B4: - case D3DFMT_A1R5G5B5: - case D3DFMT_R5G6B5: BitDepth = 16; break; - case D3DFMT_L8: - case D3DFMT_A8: - case D3DFMT_P8: BitDepth = 8; break; - default: - // Unknown backbuffer format probably means the device can't do windowed - return false; - } - - if (BitDepth == 32 && D3DInterface->CheckDeviceType(0, D3DDEVTYPE_HAL, desktop_mode.Format, D3DFMT_A8R8G8B8, TRUE) == D3D_OK) - { //promote 32-bit modes to include destination alpha - _PresentParameters.BackBufferFormat = D3DFMT_A8R8G8B8; - } - - /* - ** Find a appropriate Z buffer - */ - if (!Find_Z_Mode(DisplayFormat, _PresentParameters.BackBufferFormat, &_PresentParameters.AutoDepthStencilFormat)) - { - // If opening 32 bit mode failed, try 16 bit, even if the desktop happens to be 32 bit - if (BitDepth == 32) { - BitDepth = 16; - _PresentParameters.BackBufferFormat = D3DFMT_R5G6B5; - if (!Find_Z_Mode(_PresentParameters.BackBufferFormat, _PresentParameters.BackBufferFormat, &_PresentParameters.AutoDepthStencilFormat)) { - _PresentParameters.AutoDepthStencilFormat = D3DFMT_UNKNOWN; - } - } - else { - _PresentParameters.AutoDepthStencilFormat = D3DFMT_UNKNOWN; - } - } - - } - else { - - /* - ** Try to find a mode that matches the user's desired bit-depth. - */ - Find_Color_And_Z_Mode(ResolutionWidth, ResolutionHeight, BitDepth, &DisplayFormat, - &_PresentParameters.BackBufferFormat, &_PresentParameters.AutoDepthStencilFormat); - } - - /* - ** Time to actually create the device. - */ - if (_PresentParameters.AutoDepthStencilFormat == D3DFMT_UNKNOWN) { - if (BitDepth == 32) { - _PresentParameters.AutoDepthStencilFormat = D3DFMT_D32; - } - else { - _PresentParameters.AutoDepthStencilFormat = D3DFMT_D16; - } - } - - StringClass displayFormat; - StringClass backbufferFormat; - - Get_Format_Name(DisplayFormat, &displayFormat); - Get_Format_Name(_PresentParameters.BackBufferFormat, &backbufferFormat); - - WWDEBUG_SAY(("Using Display/BackBuffer Formats: %s/%s", displayFormat.str(), backbufferFormat.str())); - - bool ret; - - if (reset_device) - { - WWDEBUG_SAY(("DX8Wrapper::Set_Render_Device is resetting the device.")); - ret = Reset_Device(restore_assets); //reset device without restoring data - we're likely switching out of the app. - } - else - ret = Create_Device(); - - WWDEBUG_SAY(("Reset/Create_Device done, reset_device=%d, restore_assets=%d", reset_device, restore_assets)); - - return ret; -} - -bool DX8Wrapper::Set_Next_Render_Device(void) -{ - int new_dev = (CurRenderDevice + 1) % _RenderDeviceNameTable.Count(); - return Set_Render_Device(new_dev); -} - -bool DX8Wrapper::Toggle_Windowed(void) -{ -#ifdef WW3D_DX8 - // State OK? - assert(IsInitted); - if (IsInitted) { - - // Get information about the current render device's resolutions - const RenderDeviceDescClass& render_device = Get_Render_Device_Desc(); - const DynamicVectorClass& resolutions = render_device.Enumerate_Resolutions(); - - // Loop through all the resolutions supported by the current device. - // If we aren't currently running under one of these resolutions, - // then we should probably to the closest resolution before - // toggling the windowed state. - int curr_res = -1; - for (int res = 0; - (res < resolutions.Count()) && (curr_res == -1); - res++) { - - // Is this the resolution we are looking for? - if ((resolutions[res].Width == ResolutionWidth) && - (resolutions[res].Height == ResolutionHeight) && - (resolutions[res].BitDepth == BitDepth)) { - curr_res = res; - } - } - - if (curr_res == -1) { - - // We don't match any of the standard resolutions, - // so set the first resolution and toggle the windowed state. - return Set_Device_Resolution(resolutions[0].Width, - resolutions[0].Height, - resolutions[0].BitDepth, - !IsWindowed, true); - } - else { - - // Toggle the windowed state - return Set_Device_Resolution(-1, -1, -1, !IsWindowed, true); - } - } -#endif //WW3D_DX8 - - return false; -} - -void DX8Wrapper::Set_Swap_Interval(int swap) -{ - switch (swap) { - case 0: _PresentParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; break; - case 1: _PresentParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_ONE; break; - case 2: _PresentParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_TWO; break; - case 3: _PresentParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_THREE; break; - default: _PresentParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_ONE; break; - } - - WWDEBUG_SAY(("DX8Wrapper::Set_Swap_Interval is resetting the device.")); - Reset_Device(); -} - -int DX8Wrapper::Get_Swap_Interval(void) -{ - return _PresentParameters.FullScreen_PresentationInterval; -} - -bool DX8Wrapper::Has_Stencil(void) -{ - bool has_stencil = (_PresentParameters.AutoDepthStencilFormat == D3DFMT_D24S8 || - _PresentParameters.AutoDepthStencilFormat == D3DFMT_D24X4S4); - return has_stencil; -} - -int DX8Wrapper::Get_Render_Device_Count(void) -{ - return _RenderDeviceNameTable.Count(); - -} -int DX8Wrapper::Get_Render_Device(void) -{ - assert(IsInitted); - return CurRenderDevice; -} - -const RenderDeviceDescClass& DX8Wrapper::Get_Render_Device_Desc(int deviceidx) -{ - WWASSERT(IsInitted); - - if ((deviceidx == -1) && (CurRenderDevice == -1)) { - CurRenderDevice = 0; - } - - // if the device index is -1 then we want the current device - if (deviceidx == -1) { - WWASSERT(CurRenderDevice >= 0); - WWASSERT(CurRenderDevice < _RenderDeviceNameTable.Count()); - return _RenderDeviceDescriptionTable[CurRenderDevice]; - } - - // We can only ask for multiple device information if the devices - // have been detected. - WWASSERT(deviceidx >= 0); - WWASSERT(deviceidx < _RenderDeviceNameTable.Count()); - return _RenderDeviceDescriptionTable[deviceidx]; -} - -const char* DX8Wrapper::Get_Render_Device_Name(int device_index) -{ - device_index = device_index % _RenderDeviceShortNameTable.Count(); - return _RenderDeviceShortNameTable[device_index]; -} - -bool DX8Wrapper::Set_Device_Resolution(int width, int height, int bits, int windowed, bool resize_window) -{ - if (D3DDevice != NULL) { - - if (width != -1) { - _PresentParameters.BackBufferWidth = ResolutionWidth = width; - } - if (height != -1) { - _PresentParameters.BackBufferHeight = ResolutionHeight = height; - } - if (resize_window) - { - Resize_And_Position_Window(); - } -#pragma message("TODO: support changing windowed status and changing the bit depth") - WWDEBUG_SAY(("DX8Wrapper::Set_Device_Resolution is resetting the device.")); - return Reset_Device(); - } - else { - return false; - } -} - -void DX8Wrapper::Get_Device_Resolution(int& set_w, int& set_h, int& set_bits, bool& set_windowed) -{ - WWASSERT(IsInitted); - - set_w = ResolutionWidth; - set_h = ResolutionHeight; - set_bits = BitDepth; - set_windowed = IsWindowed; - - return; -} - -void DX8Wrapper::Get_Render_Target_Resolution(int& set_w, int& set_h, int& set_bits, bool& set_windowed) -{ - WWASSERT(IsInitted); - - if (CurrentRenderTarget != NULL) { - D3DSURFACE_DESC info; - CurrentRenderTarget->GetDesc(&info); - - set_w = info.Width; - set_h = info.Height; - set_bits = BitDepth; // should we get the actual bit depth of the target? - set_windowed = IsWindowed; // this doesn't really make sense for render targets (shouldn't matter)... - - } - else { - Get_Device_Resolution(set_w, set_h, set_bits, set_windowed); - } - - return; -} - -bool DX8Wrapper::Registry_Save_Render_Device(const char* sub_key) -{ - int width, height, depth; - bool windowed; - Get_Device_Resolution(width, height, depth, windowed); - return Registry_Save_Render_Device(sub_key, CurRenderDevice, ResolutionWidth, ResolutionHeight, BitDepth, IsWindowed, TextureBitDepth); -} - -bool DX8Wrapper::Registry_Save_Render_Device(const char* sub_key, int device, int width, int height, int depth, bool windowed, int texture_depth) -{ - RegistryClass* registry = W3DNEW RegistryClass(sub_key); - WWASSERT(registry); - - if (!registry->Is_Valid()) { - delete registry; - WWDEBUG_SAY(("Error getting Registry")); - return false; - } - - registry->Set_String(VALUE_NAME_RENDER_DEVICE_NAME, - _RenderDeviceShortNameTable[device]); - registry->Set_Int(VALUE_NAME_RENDER_DEVICE_WIDTH, width); - registry->Set_Int(VALUE_NAME_RENDER_DEVICE_HEIGHT, height); - registry->Set_Int(VALUE_NAME_RENDER_DEVICE_DEPTH, depth); - registry->Set_Int(VALUE_NAME_RENDER_DEVICE_WINDOWED, windowed); - registry->Set_Int(VALUE_NAME_RENDER_DEVICE_TEXTURE_DEPTH, texture_depth); - - delete registry; - return true; -} - -bool DX8Wrapper::Registry_Load_Render_Device(const char* sub_key, bool resize_window) -{ - char name[200]; - int width, height, depth, windowed; - - if (Registry_Load_Render_Device(sub_key, - name, - sizeof(name), - width, - height, - depth, - windowed, - TextureBitDepth) && - (*name != 0)) - { - WWDEBUG_SAY(("Device %s (%d X %d) %d bit windowed:%d", name, width, height, depth, windowed)); - - if (TextureBitDepth == 16 || TextureBitDepth == 32) { - // WWDEBUG_SAY(( "Texture depth %d", TextureBitDepth)); - } - else { - WWDEBUG_SAY(("Invalid texture depth %d, switching to 16 bits", TextureBitDepth)); - TextureBitDepth = 16; - } - - - // _RenderDeviceDescriptionTable. - - - if (Set_Render_Device(name, width, height, depth, windowed, resize_window) != true) { - if (depth == 16) depth = 32; - else depth = 16; - if (Set_Render_Device(name, width, height, depth, windowed, resize_window) == true) { - return true; - } - if (depth == 16) depth = 32; - else depth = 16; - // we'll test resolutions down, so if start is 640, increase to begin with... - if (width == 640) { - width = 1024; - height = 768; - } - for (;;) { - if (width > 2048) { - width = 2048; - height = 1536; - } - else if (width > 1920) { - width = 1920; - height = 1440; - } - else if (width > 1600) { - width = 1600; - height = 1200; - } - else if (width > 1280) { - width = 1280; - height = 1024; - } - else if (width > 1024) { - width = 1024; - height = 768; - } - else if (width > 800) { - width = 800; - height = 600; - } - else if (width != 640) { - width = 640; - height = 480; - } - else { - return Set_Any_Render_Device(); - } - for (int i = 0; i < 2; ++i) { - if (Set_Render_Device(name, width, height, depth, windowed, resize_window) == true) { - return true; - } - if (depth == 16) depth = 32; - else depth = 16; - } - } - } - - return true; - } - - WWDEBUG_SAY(("Error getting Registry")); - - return Set_Any_Render_Device(); -} - -bool DX8Wrapper::Registry_Load_Render_Device(const char* sub_key, char* device, int device_len, int& width, int& height, int& depth, int& windowed, int& texture_depth) -{ - RegistryClass registry(sub_key); - - if (registry.Is_Valid()) { - registry.Get_String(VALUE_NAME_RENDER_DEVICE_NAME, - device, device_len); - - width = registry.Get_Int(VALUE_NAME_RENDER_DEVICE_WIDTH, -1); - height = registry.Get_Int(VALUE_NAME_RENDER_DEVICE_HEIGHT, -1); - depth = registry.Get_Int(VALUE_NAME_RENDER_DEVICE_DEPTH, -1); - windowed = registry.Get_Int(VALUE_NAME_RENDER_DEVICE_WINDOWED, -1); - texture_depth = registry.Get_Int(VALUE_NAME_RENDER_DEVICE_TEXTURE_DEPTH, -1); - return true; - } - *device = 0; - width = -1; - height = -1; - depth = -1; - windowed = -1; - texture_depth = -1; - return false; -} - - -bool DX8Wrapper::Find_Color_And_Z_Mode(int resx, int resy, int bitdepth, D3DFORMAT* set_colorbuffer, D3DFORMAT* set_backbuffer, D3DFORMAT* set_zmode) -{ - static D3DFORMAT _formats16[] = - { - D3DFMT_R5G6B5, - D3DFMT_X1R5G5B5, - D3DFMT_A1R5G5B5 - }; - - static D3DFORMAT _formats32[] = - { - D3DFMT_A8R8G8B8, - D3DFMT_X8R8G8B8, - D3DFMT_R8G8B8, - }; - - /* - ** Select the table that we're going to use to search for a valid backbuffer format - */ - D3DFORMAT* format_table = NULL; - int format_count = 0; - - if (BitDepth == 16) { - format_table = _formats16; - format_count = sizeof(_formats16) / sizeof(D3DFORMAT); - } - else { - format_table = _formats32; - format_count = sizeof(_formats32) / sizeof(D3DFORMAT); - } - - /* - ** now search for a valid format - */ - bool found = false; - unsigned int mode = 0; - - int format_index = 0; - for (; format_index < format_count; format_index++) { - found |= Find_Color_Mode(format_table[format_index], resx, resy, &mode); - if (found) break; - } - - if (!found) { - return false; - } - else { - *set_backbuffer = *set_colorbuffer = format_table[format_index]; - } - - if (bitdepth == 32 && *set_colorbuffer == D3DFMT_X8R8G8B8 && D3DInterface->CheckDeviceType(0, D3DDEVTYPE_HAL, *set_colorbuffer, D3DFMT_A8R8G8B8, TRUE) == D3D_OK) - { //promote 32-bit modes to include destination alpha when supported - *set_backbuffer = D3DFMT_A8R8G8B8; - } - - /* - ** We found a backbuffer format, now find a zbuffer format - */ - return Find_Z_Mode(*set_colorbuffer, *set_backbuffer, set_zmode); -}; - - -// find the resolution mode with at least resx,resy with the highest supported -// refresh rate -bool DX8Wrapper::Find_Color_Mode(D3DFORMAT colorbuffer, int resx, int resy, UINT* mode) -{ - UINT i, j, modemax; - UINT rx, ry; - D3DDISPLAYMODE dmode; - ::ZeroMemory(&dmode, sizeof(D3DDISPLAYMODE)); - - rx = (unsigned int)resx; - ry = (unsigned int)resy; - - bool found = false; - - modemax = D3DInterface->GetAdapterModeCount(D3DADAPTER_DEFAULT); - - i = 0; - - while (i < modemax && !found) - { - D3DInterface->EnumAdapterModes(D3DADAPTER_DEFAULT, i, &dmode); - if (dmode.Width == rx && dmode.Height == ry && dmode.Format == colorbuffer) { - WWDEBUG_SAY(("Found valid color mode. Width = %d Height = %d Format = %d", dmode.Width, dmode.Height, dmode.Format)); - found = true; - } - i++; - } - - i--; // this is the first valid mode - - // no match - if (!found) { - WWDEBUG_SAY(("Failed to find a valid color mode")); - return false; - } - - // go to the highest refresh rate in this mode - bool stillok = true; - - j = i; - while (j < modemax && stillok) - { - D3DInterface->EnumAdapterModes(D3DADAPTER_DEFAULT, j, &dmode); - if (dmode.Width == rx && dmode.Height == ry && dmode.Format == colorbuffer) - stillok = true; else stillok = false; - j++; - } - - if (stillok == false) *mode = j - 2; - else *mode = i; - - return true; -} - -// Helper function to find a Z buffer mode for the colorbuffer -// Will look for greatest Z precision -bool DX8Wrapper::Find_Z_Mode(D3DFORMAT colorbuffer, D3DFORMAT backbuffer, D3DFORMAT* zmode) -{ - //MW: Swapped the next 2 tests so that Stencil modes get tested first. - if (Test_Z_Mode(colorbuffer, backbuffer, D3DFMT_D24S8)) - { - *zmode = D3DFMT_D24S8; - WWDEBUG_SAY(("Found zbuffer mode D3DFMT_D24S8")); - return true; - } - - if (Test_Z_Mode(colorbuffer, backbuffer, D3DFMT_D32)) - { - *zmode = D3DFMT_D32; - WWDEBUG_SAY(("Found zbuffer mode D3DFMT_D32")); - return true; - } - - if (Test_Z_Mode(colorbuffer, backbuffer, D3DFMT_D24X8)) - { - *zmode = D3DFMT_D24X8; - WWDEBUG_SAY(("Found zbuffer mode D3DFMT_D24X8")); - return true; - } - - if (Test_Z_Mode(colorbuffer, backbuffer, D3DFMT_D24X4S4)) - { - *zmode = D3DFMT_D24X4S4; - WWDEBUG_SAY(("Found zbuffer mode D3DFMT_D24X4S4")); - return true; - } - - if (Test_Z_Mode(colorbuffer, backbuffer, D3DFMT_D16)) - { - *zmode = D3DFMT_D16; - WWDEBUG_SAY(("Found zbuffer mode D3DFMT_D16")); - return true; - } - - if (Test_Z_Mode(colorbuffer, backbuffer, D3DFMT_D15S1)) - { - *zmode = D3DFMT_D15S1; - WWDEBUG_SAY(("Found zbuffer mode D3DFMT_D15S1")); - return true; - } - - // can't find a match - WWDEBUG_SAY(("Failed to find a valid zbuffer mode")); - return false; -} - -bool DX8Wrapper::Test_Z_Mode(D3DFORMAT colorbuffer, D3DFORMAT backbuffer, D3DFORMAT zmode) -{ - // See if we have this mode first - if (FAILED(D3DInterface->CheckDeviceFormat(D3DADAPTER_DEFAULT, WW3D_DEVTYPE, - colorbuffer, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, zmode))) - { - WWDEBUG_SAY(("CheckDeviceFormat failed. Colorbuffer format = %d Zbufferformat = %d", colorbuffer, zmode)); - return false; - } - - // Then see if it matches the color buffer - if (FAILED(D3DInterface->CheckDepthStencilMatch(D3DADAPTER_DEFAULT, WW3D_DEVTYPE, - colorbuffer, backbuffer, zmode))) - { - WWDEBUG_SAY(("CheckDepthStencilMatch failed. Colorbuffer format = %d Backbuffer format = %d Zbufferformat = %d", colorbuffer, backbuffer, zmode)); - return false; - } - return true; -} - - -void DX8Wrapper::Reset_Statistics() -{ - matrix_changes = 0; - material_changes = 0; - vertex_buffer_changes = 0; - index_buffer_changes = 0; - light_changes = 0; - texture_changes = 0; - render_state_changes = 0; - texture_stage_state_changes = 0; - draw_calls = 0; - - number_of_DX8_calls = 0; - last_frame_matrix_changes = 0; - last_frame_material_changes = 0; - last_frame_vertex_buffer_changes = 0; - last_frame_index_buffer_changes = 0; - last_frame_light_changes = 0; - last_frame_texture_changes = 0; - last_frame_render_state_changes = 0; - last_frame_texture_stage_state_changes = 0; - last_frame_number_of_DX8_calls = 0; - last_frame_draw_calls = 0; -} - -void DX8Wrapper::Begin_Statistics() -{ - matrix_changes = 0; - material_changes = 0; - vertex_buffer_changes = 0; - index_buffer_changes = 0; - light_changes = 0; - texture_changes = 0; - render_state_changes = 0; - texture_stage_state_changes = 0; - number_of_DX8_calls = 0; - draw_calls = 0; -} - -void DX8Wrapper::End_Statistics() -{ - last_frame_matrix_changes = matrix_changes; - last_frame_material_changes = material_changes; - last_frame_vertex_buffer_changes = vertex_buffer_changes; - last_frame_index_buffer_changes = index_buffer_changes; - last_frame_light_changes = light_changes; - last_frame_texture_changes = texture_changes; - last_frame_render_state_changes = render_state_changes; - last_frame_texture_stage_state_changes = texture_stage_state_changes; - last_frame_number_of_DX8_calls = number_of_DX8_calls; - last_frame_draw_calls = draw_calls; -} - -unsigned DX8Wrapper::Get_Last_Frame_Matrix_Changes() { return last_frame_matrix_changes; } -unsigned DX8Wrapper::Get_Last_Frame_Material_Changes() { return last_frame_material_changes; } -unsigned DX8Wrapper::Get_Last_Frame_Vertex_Buffer_Changes() { return last_frame_vertex_buffer_changes; } -unsigned DX8Wrapper::Get_Last_Frame_Index_Buffer_Changes() { return last_frame_index_buffer_changes; } -unsigned DX8Wrapper::Get_Last_Frame_Light_Changes() { return last_frame_light_changes; } -unsigned DX8Wrapper::Get_Last_Frame_Texture_Changes() { return last_frame_texture_changes; } -unsigned DX8Wrapper::Get_Last_Frame_Render_State_Changes() { return last_frame_render_state_changes; } -unsigned DX8Wrapper::Get_Last_Frame_Texture_Stage_State_Changes() { return last_frame_texture_stage_state_changes; } -unsigned DX8Wrapper::Get_Last_Frame_DX8_Calls() { return last_frame_number_of_DX8_calls; } -unsigned DX8Wrapper::Get_Last_Frame_Draw_Calls() { return last_frame_draw_calls; } -unsigned long DX8Wrapper::Get_FrameCount(void) { return FrameCount; } - -void DX8_Assert() -{ - WWASSERT(DX8Wrapper::_Get_D3D8()); - DX8_THREAD_ASSERT(); -} - -void DX8Wrapper::Begin_Scene(void) -{ - DX8_THREAD_ASSERT(); - -#if ENABLE_EMBEDDED_BROWSER - DX8WebBrowser::Update(); -#endif - - DX8CALL(BeginScene()); - - DX8WebBrowser::Update(); -} - -void DX8Wrapper::End_Scene(bool flip_frames) -{ - DX8_THREAD_ASSERT(); - DX8CALL(EndScene()); - - DX8WebBrowser::Render(0); - - if (flip_frames) { - DX8_Assert(); - HRESULT hr; - { - WWPROFILE("DX8Device::Present()"); - hr = _Get_D3D_Device8()->Present(NULL, NULL, NULL, NULL); - } - - number_of_DX8_calls++; - - if (SUCCEEDED(hr)) { -#ifdef EXTENDED_STATS - if (stats.m_sleepTime) { - ::Sleep(stats.m_sleepTime); - } -#endif - IsDeviceLost = false; - FrameCount++; - } - else { - IsDeviceLost = true; - } - - // If the device was lost we need to check for cooperative level and possibly reset the device - if (hr == D3DERR_DEVICELOST) { - hr = _Get_D3D_Device8()->TestCooperativeLevel(); - if (hr == D3DERR_DEVICENOTRESET) { - WWDEBUG_SAY(("DX8Wrapper::End_Scene is resetting the device.")); - Reset_Device(); - } - else { - // Sleep it not active - ThreadClass::Sleep_Ms(200); - } - } - else { - DX8_ErrorCode(hr); - } - } - - // Each frame, release all of the buffers and textures. - Set_Vertex_Buffer(NULL); - Set_Index_Buffer(NULL, 0); - for (int i = 0; i < CurrentCaps->Get_Max_Textures_Per_Pass(); ++i) Set_Texture(i, NULL); - Set_Material(NULL); -} - - -void DX8Wrapper::Flip_To_Primary(void) -{ - // If we are fullscreen and the current frame is odd then we need - // to force a page flip to ensure that the first buffer in the flipping - // chain is the one visible. - if (!IsWindowed) { - DX8_Assert(); - - int numBuffers = (_PresentParameters.BackBufferCount + 1); - int visibleBuffer = (FrameCount % numBuffers); - int flipCount = ((numBuffers - visibleBuffer) % numBuffers); - int resetAttempts = 0; - - while ((flipCount > 0) && (resetAttempts < 3)) { - HRESULT hr = _Get_D3D_Device8()->TestCooperativeLevel(); - - if (FAILED(hr)) { - WWDEBUG_SAY(("TestCooperativeLevel Failed!")); - - if (D3DERR_DEVICELOST == hr) { - IsDeviceLost = true; - WWDEBUG_SAY(("DEVICELOST: Cannot flip to primary.")); - return; - } - IsDeviceLost = false; - - if (D3DERR_DEVICENOTRESET == hr) { - WWDEBUG_SAY(("DEVICENOTRESET")); - Reset_Device(); - resetAttempts++; - } - } - else { - WWDEBUG_SAY(("Flipping: %ld", FrameCount)); - hr = _Get_D3D_Device8()->Present(NULL, NULL, NULL, NULL); - - if (SUCCEEDED(hr)) { - IsDeviceLost = false; - FrameCount++; - WWDEBUG_SAY(("Flip to primary succeeded %ld", FrameCount)); - } - else { - IsDeviceLost = true; - } - } - - --flipCount; - } - } -} - - - -//********************************************************************************************** -//! Clear current render device -/*! KM -/* 5/17/02 KM Fixed support for render to texture with depth/stencil buffers -*/ -void DX8Wrapper::Clear(bool clear_color, bool clear_z_stencil, const Vector3& color, float dest_alpha, float z, unsigned int stencil) -{ - DX8_THREAD_ASSERT(); - - // If we try to clear a stencil buffer which is not there, the entire call will fail - // KJM fixed this to get format from back buffer (incase render to texture is used) - /*bool has_stencil = ( _PresentParameters.AutoDepthStencilFormat == D3DFMT_D15S1 || - _PresentParameters.AutoDepthStencilFormat == D3DFMT_D24S8 || - _PresentParameters.AutoDepthStencilFormat == D3DFMT_D24X4S4);*/ - bool has_stencil = false; - IDirect3DSurface8* depthbuffer; - - _Get_D3D_Device8()->GetDepthStencilSurface(&depthbuffer); - number_of_DX8_calls++; - - if (depthbuffer) - { - D3DSURFACE_DESC desc; - depthbuffer->GetDesc(&desc); - has_stencil = - ( - desc.Format == D3DFMT_D15S1 || - desc.Format == D3DFMT_D24S8 || - desc.Format == D3DFMT_D24X4S4 - ); - - // release ref - depthbuffer->Release(); - } - - DWORD flags = 0; - if (clear_color) flags |= D3DCLEAR_TARGET; - if (clear_z_stencil) flags |= D3DCLEAR_ZBUFFER; - if (clear_z_stencil && has_stencil) flags |= D3DCLEAR_STENCIL; - if (flags) - { - DX8CALL(Clear(0, NULL, flags, Convert_Color(color, dest_alpha), z, stencil)); - } -} - -void DX8Wrapper::Set_Viewport(CONST D3DVIEWPORT8* pViewport) -{ - DX8_THREAD_ASSERT(); - DX8CALL(SetViewport(pViewport)); -} - -// ---------------------------------------------------------------------------- -// -// Set vertex buffer. A reference to previous vertex buffer is released and -// this one is assigned the current vertex buffer. The DX8 vertex buffer will -// actually be set in Apply() which is called by Draw_Indexed_Triangles(). -// -// ---------------------------------------------------------------------------- - -void DX8Wrapper::Set_Vertex_Buffer(const VertexBufferClass* vb, unsigned stream) -{ - render_state.vba_offset = 0; - render_state.vba_count = 0; - if (render_state.vertex_buffers[stream]) { - render_state.vertex_buffers[stream]->Release_Engine_Ref(); - } - REF_PTR_SET(render_state.vertex_buffers[stream], const_cast(vb)); - if (vb) { - vb->Add_Engine_Ref(); - render_state.vertex_buffer_types[stream] = vb->Type(); - } - else { - render_state.vertex_buffer_types[stream] = BUFFER_TYPE_INVALID; - } - render_state_changed |= VERTEX_BUFFER_CHANGED; -} - -// ---------------------------------------------------------------------------- -// -// Set index buffer. A reference to previous index buffer is released and -// this one is assigned the current index buffer. The DX8 index buffer will -// actually be set in Apply() which is called by Draw_Indexed_Triangles(). -// -// ---------------------------------------------------------------------------- - -void DX8Wrapper::Set_Index_Buffer(const IndexBufferClass* ib, unsigned short index_base_offset) -{ - render_state.iba_offset = 0; - if (render_state.index_buffer) { - render_state.index_buffer->Release_Engine_Ref(); - } - REF_PTR_SET(render_state.index_buffer, const_cast(ib)); - render_state.index_base_offset = index_base_offset; - if (ib) { - ib->Add_Engine_Ref(); - render_state.index_buffer_type = ib->Type(); - } - else { - render_state.index_buffer_type = BUFFER_TYPE_INVALID; - } - render_state_changed |= INDEX_BUFFER_CHANGED; -} - -// ---------------------------------------------------------------------------- -// -// Set vertex buffer using dynamic access object. -// -// ---------------------------------------------------------------------------- - -void DX8Wrapper::Set_Vertex_Buffer(const DynamicVBAccessClass& vba_) -{ - // Release all streams (only one stream allowed in the legacy pipeline) - for (int i = 1; i < MAX_VERTEX_STREAMS; ++i) { - DX8Wrapper::Set_Vertex_Buffer(NULL, i); - } - - if (render_state.vertex_buffers[0]) render_state.vertex_buffers[0]->Release_Engine_Ref(); - DynamicVBAccessClass& vba = const_cast(vba_); - render_state.vertex_buffer_types[0] = vba.Get_Type(); - render_state.vba_offset = vba.VertexBufferOffset; - render_state.vba_count = vba.Get_Vertex_Count(); - REF_PTR_SET(render_state.vertex_buffers[0], vba.VertexBuffer); - render_state.vertex_buffers[0]->Add_Engine_Ref(); - render_state_changed |= VERTEX_BUFFER_CHANGED; - render_state_changed |= INDEX_BUFFER_CHANGED; // vba_offset changes so index buffer needs to be reset as well. -} - -// ---------------------------------------------------------------------------- -// -// Set index buffer using dynamic access object. -// -// ---------------------------------------------------------------------------- - -void DX8Wrapper::Set_Index_Buffer(const DynamicIBAccessClass& iba_, unsigned short index_base_offset) -{ - if (render_state.index_buffer) render_state.index_buffer->Release_Engine_Ref(); - - DynamicIBAccessClass& iba = const_cast(iba_); - render_state.index_base_offset = index_base_offset; - render_state.index_buffer_type = iba.Get_Type(); - render_state.iba_offset = iba.IndexBufferOffset; - REF_PTR_SET(render_state.index_buffer, iba.IndexBuffer); - render_state.index_buffer->Add_Engine_Ref(); - render_state_changed |= INDEX_BUFFER_CHANGED; -} - -// ---------------------------------------------------------------------------- -// -// Private function for the special case of rendering polygons from sorting -// index and vertex buffers. -// -// ---------------------------------------------------------------------------- - -void DX8Wrapper::Draw_Sorting_IB_VB( - unsigned primitive_type, - unsigned short start_index, - unsigned short polygon_count, - unsigned short min_vertex_index, - unsigned short vertex_count) -{ - WWASSERT(render_state.vertex_buffer_types[0] == BUFFER_TYPE_SORTING || render_state.vertex_buffer_types[0] == BUFFER_TYPE_DYNAMIC_SORTING); - WWASSERT(render_state.index_buffer_type == BUFFER_TYPE_SORTING || render_state.index_buffer_type == BUFFER_TYPE_DYNAMIC_SORTING); - - // Fill dynamic vertex buffer with sorting vertex buffer vertices - DynamicVBAccessClass dyn_vb_access(BUFFER_TYPE_DYNAMIC_DX8, dynamic_fvf_type, vertex_count); - { - DynamicVBAccessClass::WriteLockClass lock(&dyn_vb_access); - VertexFormatXYZNDUV2* src = static_cast(render_state.vertex_buffers[0])->VertexBuffer; - VertexFormatXYZNDUV2* dest = lock.Get_Formatted_Vertex_Array(); - src += render_state.vba_offset + render_state.index_base_offset + min_vertex_index; - unsigned size = dyn_vb_access.FVF_Info().Get_FVF_Size() * vertex_count / sizeof(unsigned); - unsigned* dest_u = (unsigned*)dest; - unsigned* src_u = (unsigned*)src; - - for (unsigned i = 0; i < size; ++i) { - *dest_u++ = *src_u++; - } - } - - DX8CALL(SetStreamSource( - 0, - static_cast(dyn_vb_access.VertexBuffer)->Get_DX8_Vertex_Buffer(), - dyn_vb_access.FVF_Info().Get_FVF_Size())); - // If using FVF format VB, set the FVF as vertex shader (may not be needed here KM) - unsigned fvf = dyn_vb_access.FVF_Info().Get_FVF(); - if (fvf != 0) { - DX8CALL(SetVertexShader(fvf)); - } - DX8_RECORD_VERTEX_BUFFER_CHANGE(); - - unsigned index_count = 0; - switch (primitive_type) { - case D3DPT_TRIANGLELIST: index_count = polygon_count * 3; break; - case D3DPT_TRIANGLESTRIP: index_count = polygon_count + 2; break; - case D3DPT_TRIANGLEFAN: index_count = polygon_count + 2; break; - default: WWASSERT(0); break; // Unsupported primitive type - } - - // Fill dynamic index buffer with sorting index buffer vertices - DynamicIBAccessClass dyn_ib_access(BUFFER_TYPE_DYNAMIC_DX8, index_count); - { - DynamicIBAccessClass::WriteLockClass lock(&dyn_ib_access); - unsigned short* dest = lock.Get_Index_Array(); - unsigned short* src = NULL; - src = static_cast(render_state.index_buffer)->index_buffer; - src += render_state.iba_offset + start_index; - - for (unsigned short i = 0; i < index_count; ++i) { - unsigned short index = *src++; - index -= min_vertex_index; - WWASSERT(index < vertex_count); - *dest++ = index; - } - } - - DX8CALL(SetIndices( - static_cast(dyn_ib_access.IndexBuffer)->Get_DX8_Index_Buffer(), - dyn_vb_access.VertexBufferOffset)); - DX8_RECORD_INDEX_BUFFER_CHANGE(); - - DX8_RECORD_DRAW_CALLS(); - DX8CALL(DrawIndexedPrimitive( - D3DPT_TRIANGLELIST, - 0, // start vertex - vertex_count, - dyn_ib_access.IndexBufferOffset, - polygon_count)); - - DX8_RECORD_RENDER(polygon_count, vertex_count, render_state.shader); -} - -// ---------------------------------------------------------------------------- -// -// -// -// ---------------------------------------------------------------------------- - -void DX8Wrapper::Draw( - unsigned primitive_type, - unsigned short start_index, - unsigned short polygon_count, - unsigned short min_vertex_index, - unsigned short vertex_count) -{ - if (DrawPolygonLowBoundLimit && DrawPolygonLowBoundLimit >= polygon_count) return; - - DX8_THREAD_ASSERT(); - SNAPSHOT_SAY(("DX8 - draw")); - - Apply_Render_State_Changes(); - - // Debug feature to disable triangle drawing... - if (!_Is_Triangle_Draw_Enabled()) return; - -#ifdef MESH_RENDER_SNAPSHOT_ENABLED - if (WW3D::Is_Snapshot_Activated()) { - unsigned long passes = 0; - SNAPSHOT_SAY(("ValidateDevice:")); - HRESULT res = D3DDevice->ValidateDevice(&passes); - switch (res) { - case D3D_OK: - SNAPSHOT_SAY(("OK")); - break; - - case D3DERR_CONFLICTINGTEXTUREFILTER: - SNAPSHOT_SAY(("D3DERR_CONFLICTINGTEXTUREFILTER")); - break; - case D3DERR_CONFLICTINGTEXTUREPALETTE: - SNAPSHOT_SAY(("D3DERR_CONFLICTINGTEXTUREPALETTE")); - break; - case D3DERR_DEVICELOST: - SNAPSHOT_SAY(("D3DERR_DEVICELOST")); - break; - case D3DERR_TOOMANYOPERATIONS: - SNAPSHOT_SAY(("D3DERR_TOOMANYOPERATIONS")); - break; - case D3DERR_UNSUPPORTEDALPHAARG: - SNAPSHOT_SAY(("D3DERR_UNSUPPORTEDALPHAARG")); - break; - case D3DERR_UNSUPPORTEDALPHAOPERATION: - SNAPSHOT_SAY(("D3DERR_UNSUPPORTEDALPHAOPERATION")); - break; - case D3DERR_UNSUPPORTEDCOLORARG: - SNAPSHOT_SAY(("D3DERR_UNSUPPORTEDCOLORARG")); - break; - case D3DERR_UNSUPPORTEDCOLOROPERATION: - SNAPSHOT_SAY(("D3DERR_UNSUPPORTEDCOLOROPERATION")); - break; - case D3DERR_UNSUPPORTEDFACTORVALUE: - SNAPSHOT_SAY(("D3DERR_UNSUPPORTEDFACTORVALUE")); - break; - case D3DERR_UNSUPPORTEDTEXTUREFILTER: - SNAPSHOT_SAY(("D3DERR_UNSUPPORTEDTEXTUREFILTER")); - break; - case D3DERR_WRONGTEXTUREFORMAT: - SNAPSHOT_SAY(("D3DERR_WRONGTEXTUREFORMAT")); - break; - default: - SNAPSHOT_SAY(("UNKNOWN Error")); - break; - } - } -#endif // MESH_RENDER_SHAPSHOT_ENABLED - - - SNAPSHOT_SAY(("DX8 - draw %d polygons (%d vertices)", polygon_count, vertex_count)); - - if (vertex_count < 3) { - min_vertex_index = 0; - switch (render_state.vertex_buffer_types[0]) { - case BUFFER_TYPE_DX8: - case BUFFER_TYPE_SORTING: - vertex_count = render_state.vertex_buffers[0]->Get_Vertex_Count() - render_state.index_base_offset - render_state.vba_offset - min_vertex_index; - break; - case BUFFER_TYPE_DYNAMIC_DX8: - case BUFFER_TYPE_DYNAMIC_SORTING: - vertex_count = render_state.vba_count; - break; - } - } - - switch (render_state.vertex_buffer_types[0]) { - case BUFFER_TYPE_DX8: - case BUFFER_TYPE_DYNAMIC_DX8: - switch (render_state.index_buffer_type) { - case BUFFER_TYPE_DX8: - case BUFFER_TYPE_DYNAMIC_DX8: - { - /* if ((start_index+render_state.iba_offset+polygon_count*3) > render_state.index_buffer->Get_Index_Count()) - { WWASSERT_PRINT(0,"OVERFLOWING INDEX BUFFER"); - ///@todo: MUST FIND OUT WHY THIS HAPPENS WITH LOTS OF PARTICLES ON BIG FIGHT! -MW - break; - }*/ - DX8_RECORD_RENDER(polygon_count, vertex_count, render_state.shader); - DX8_RECORD_DRAW_CALLS(); - DX8CALL(DrawIndexedPrimitive( - (D3DPRIMITIVETYPE)primitive_type, - min_vertex_index, - vertex_count, - start_index + render_state.iba_offset, - polygon_count)); - } - break; - case BUFFER_TYPE_SORTING: - case BUFFER_TYPE_DYNAMIC_SORTING: - WWASSERT_PRINT(0, "VB and IB must of same type (sorting or dx8)"); - break; - case BUFFER_TYPE_INVALID: - WWASSERT(0); - break; - } - break; - case BUFFER_TYPE_SORTING: - case BUFFER_TYPE_DYNAMIC_SORTING: - switch (render_state.index_buffer_type) { - case BUFFER_TYPE_DX8: - case BUFFER_TYPE_DYNAMIC_DX8: - WWASSERT_PRINT(0, "VB and IB must of same type (sorting or dx8)"); - break; - case BUFFER_TYPE_SORTING: - case BUFFER_TYPE_DYNAMIC_SORTING: - Draw_Sorting_IB_VB(primitive_type, start_index, polygon_count, min_vertex_index, vertex_count); - break; - case BUFFER_TYPE_INVALID: - WWASSERT(0); - break; - } - break; - case BUFFER_TYPE_INVALID: - WWASSERT(0); - break; - } -} - -// ---------------------------------------------------------------------------- -// -// -// -// ---------------------------------------------------------------------------- - -void DX8Wrapper::Draw_Triangles( - unsigned buffer_type, - unsigned short start_index, - unsigned short polygon_count, - unsigned short min_vertex_index, - unsigned short vertex_count) -{ - if (buffer_type == BUFFER_TYPE_SORTING || buffer_type == BUFFER_TYPE_DYNAMIC_SORTING) { - SortingRendererClass::Insert_Triangles(start_index, polygon_count, min_vertex_index, vertex_count); - } - else { - Draw(D3DPT_TRIANGLELIST, start_index, polygon_count, min_vertex_index, vertex_count); - } -} - -// ---------------------------------------------------------------------------- -// -// -// -// ---------------------------------------------------------------------------- - -void DX8Wrapper::Draw_Triangles( - unsigned short start_index, - unsigned short polygon_count, - unsigned short min_vertex_index, - unsigned short vertex_count) -{ - Draw(D3DPT_TRIANGLELIST, start_index, polygon_count, min_vertex_index, vertex_count); -} - -// ---------------------------------------------------------------------------- -// -// -// -// ---------------------------------------------------------------------------- - -void DX8Wrapper::Draw_Strip( - unsigned short start_index, - unsigned short polygon_count, - unsigned short min_vertex_index, - unsigned short vertex_count) -{ - Draw(D3DPT_TRIANGLESTRIP, start_index, polygon_count, min_vertex_index, vertex_count); -} - - - -// ---------------------------------------------------------------------------- -// -// -// -// ---------------------------------------------------------------------------- - -void DX8Wrapper::Apply_Render_State_Changes() -{ - SNAPSHOT_SAY(("DX8Wrapper::Apply_Render_State_Changes()")); - - if (!render_state_changed) return; - if (render_state_changed & SHADER_CHANGED) { - SNAPSHOT_SAY(("DX8 - apply shader")); - render_state.shader.Apply(); - } - - unsigned mask = TEXTURE0_CHANGED; - int i = 0; - for (; i < CurrentCaps->Get_Max_Textures_Per_Pass(); ++i, mask <<= 1) - { - if (render_state_changed & mask) - { - SNAPSHOT_SAY(("DX8 - apply texture %d (%s)", i, render_state.Textures[i] ? render_state.Textures[i]->Get_Full_Path().str() : "NULL")); - - if (render_state.Textures[i]) - { - render_state.Textures[i]->Apply(i); - } - else - { - TextureBaseClass::Apply_Null(i); - } - } - } - - if (render_state_changed & MATERIAL_CHANGED) - { - SNAPSHOT_SAY(("DX8 - apply material")); - VertexMaterialClass* material = const_cast(render_state.material); - if (material) - { - material->Apply(); - } - else VertexMaterialClass::Apply_Null(); - } - - if (render_state_changed & LIGHTS_CHANGED) - { - unsigned mask = LIGHT0_CHANGED; - for (unsigned index = 0; index < 4; ++index, mask <<= 1) { - if (render_state_changed & mask) { - SNAPSHOT_SAY(("DX8 - apply light %d", index)); - if (render_state.LightEnable[index]) { -#ifdef MESH_RENDER_SNAPSHOT_ENABLED - if (WW3D::Is_Snapshot_Activated()) { - D3DLIGHT8* light = &(render_state.Lights[index]); - static const char* _light_types[] = { "Unknown", "Point","Spot", "Directional" }; - WWASSERT((light->Type >= 0) && (light->Type <= 3)); - - SNAPSHOT_SAY((" type = %s amb = %4.2f,%4.2f,%4.2f diff = %4.2f,%4.2f,%4.2f spec = %4.2f, %4.2f, %4.2f", - _light_types[light->Type], - light->Ambient.r, light->Ambient.g, light->Ambient.b, - light->Diffuse.r, light->Diffuse.g, light->Diffuse.b, - light->Specular.r, light->Specular.g, light->Specular.b)); - SNAPSHOT_SAY((" pos = %f, %f, %f dir = %f, %f, %f", - light->Position.x, light->Position.y, light->Position.z, - light->Direction.x, light->Direction.y, light->Direction.z)); - } -#endif - - Set_DX8_Light(index, &render_state.Lights[index]); - } - else { - Set_DX8_Light(index, NULL); - SNAPSHOT_SAY((" clearing light to NULL")); - } - } - } - } - - if (render_state_changed & WORLD_CHANGED) { - SNAPSHOT_SAY(("DX8 - apply world matrix")); - _Set_DX8_Transform(D3DTS_WORLD, render_state.world); - } - if (render_state_changed & VIEW_CHANGED) { - SNAPSHOT_SAY(("DX8 - apply view matrix")); - _Set_DX8_Transform(D3DTS_VIEW, render_state.view); - } - if (render_state_changed & VERTEX_BUFFER_CHANGED) { - SNAPSHOT_SAY(("DX8 - apply vb change")); - for (i = 0; i < MAX_VERTEX_STREAMS; ++i) { - if (render_state.vertex_buffers[i]) { - switch (render_state.vertex_buffer_types[i]) {//->Type()) { - case BUFFER_TYPE_DX8: - case BUFFER_TYPE_DYNAMIC_DX8: - DX8CALL(SetStreamSource( - i, - static_cast(render_state.vertex_buffers[i])->Get_DX8_Vertex_Buffer(), - render_state.vertex_buffers[i]->FVF_Info().Get_FVF_Size())); - DX8_RECORD_VERTEX_BUFFER_CHANGE(); - { - // If the VB format is FVF, set the FVF as a vertex shader - unsigned fvf = render_state.vertex_buffers[i]->FVF_Info().Get_FVF(); - if (fvf != 0) { - Set_Vertex_Shader(fvf); - } - } - break; - case BUFFER_TYPE_SORTING: - case BUFFER_TYPE_DYNAMIC_SORTING: - break; - default: - WWASSERT(0); - } - } - else { - DX8CALL(SetStreamSource(i, NULL, 0)); - DX8_RECORD_VERTEX_BUFFER_CHANGE(); - } - } - } - if (render_state_changed & INDEX_BUFFER_CHANGED) { - SNAPSHOT_SAY(("DX8 - apply ib change")); - if (render_state.index_buffer) { - switch (render_state.index_buffer_type) {//->Type()) { - case BUFFER_TYPE_DX8: - case BUFFER_TYPE_DYNAMIC_DX8: - DX8CALL(SetIndices( - static_cast(render_state.index_buffer)->Get_DX8_Index_Buffer(), - render_state.index_base_offset + render_state.vba_offset)); - DX8_RECORD_INDEX_BUFFER_CHANGE(); - break; - case BUFFER_TYPE_SORTING: - case BUFFER_TYPE_DYNAMIC_SORTING: - break; - default: - WWASSERT(0); - } - } - else { - DX8CALL(SetIndices( - NULL, - 0)); - DX8_RECORD_INDEX_BUFFER_CHANGE(); - } - } - - render_state_changed &= ((unsigned)WORLD_IDENTITY | (unsigned)VIEW_IDENTITY); - - SNAPSHOT_SAY(("DX8Wrapper::Apply_Render_State_Changes() - finished")); -} - -IDirect3DTexture8* DX8Wrapper::_Create_DX8_Texture -( - unsigned int width, - unsigned int height, - WW3DFormat format, - MipCountType mip_level_count, - D3DPOOL pool, - bool rendertarget -) -{ - DX8_THREAD_ASSERT(); - DX8_Assert(); - IDirect3DTexture8* 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 = D3DXCreateTexture( - DX8Wrapper::_Get_D3D_Device8(), - width, - height, - 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 = D3DXCreateTexture( - DX8Wrapper::_Get_D3D_Device8(), - width, - height, - 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 = D3DXCreateTexture( - DX8Wrapper::_Get_D3D_Device8(), - width, - height, - 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 = D3DXCreateTexture( - DX8Wrapper::_Get_D3D_Device8(), - width, - height, - 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; -} - -IDirect3DTexture8* DX8Wrapper::_Create_DX8_Texture -( - const char* filename, - MipCountType mip_level_count -) -{ - DX8_THREAD_ASSERT(); - DX8_Assert(); - IDirect3DTexture8* texture = NULL; - - // NOTE: If the original image format is not supported as a texture format, it will - // automatically be converted to an appropriate format. - // NOTE: It is possible to get the size and format of the original image file from this - // function as well, so if we later want to second-guess D3DX's format conversion decisions - // we can do so after this function is called.. - unsigned result = D3DXCreateTextureFromFileExA( - _Get_D3D_Device8(), - filename, - D3DX_DEFAULT, - D3DX_DEFAULT, - mip_level_count,//create_mipmaps ? 0 : 1, - 0, - D3DFMT_UNKNOWN, - D3DPOOL_MANAGED, - D3DX_FILTER_BOX, - D3DX_FILTER_BOX, - 0, - NULL, - NULL, - &texture); - - if (result != D3D_OK) { - return MissingTexture::_Get_Missing_Texture(); - } - - // Make sure texture wasn't paletted! - D3DSURFACE_DESC desc; - texture->GetLevelDesc(0, &desc); - if (desc.Format == D3DFMT_P8) { - texture->Release(); - return MissingTexture::_Get_Missing_Texture(); - } - return texture; -} - -IDirect3DTexture8* DX8Wrapper::_Create_DX8_Texture -( - IDirect3DSurface8* surface, - MipCountType mip_level_count -) -{ - DX8_THREAD_ASSERT(); - DX8_Assert(); - IDirect3DTexture8* texture = NULL; - - D3DSURFACE_DESC surface_desc; - ::ZeroMemory(&surface_desc, sizeof(D3DSURFACE_DESC)); - surface->GetDesc(&surface_desc); - - // This function will create a texture with a different (but similar) format if the surface is - // not in a supported texture format. - WW3DFormat format = D3DFormat_To_WW3DFormat(surface_desc.Format); - texture = _Create_DX8_Texture(surface_desc.Width, surface_desc.Height, format, mip_level_count); - - // Copy the surface to the texture - IDirect3DSurface8* tex_surface = NULL; - texture->GetSurfaceLevel(0, &tex_surface); - DX8_ErrorCode(D3DXLoadSurfaceFromSurface(tex_surface, NULL, NULL, surface, NULL, NULL, D3DX_FILTER_BOX, 0)); - tex_surface->Release(); - - // Create mipmaps if needed - if (mip_level_count != MIP_LEVELS_1) - { - DX8_ErrorCode(D3DXFilterTexture(texture, NULL, 0, D3DX_FILTER_BOX)); - } - - return 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(); - DX8_Assert(); - - IDirect3DSurface8* surface = NULL; - - // Paletted surfaces not supported! - WWASSERT(format != D3DFMT_P8); - - DX8CALL(CreateImageSurface(width, height, WW3DFormat_To_D3DFormat(format), &surface)); - - return surface; -} - -IDirect3DSurface8* DX8Wrapper::_Create_DX8_Surface(const char* filename_) -{ - DX8_THREAD_ASSERT(); - DX8_Assert(); - - // Note: Since there is no "D3DXCreateSurfaceFromFile" and no "GetSurfaceInfoFromFile" (the - // latter is supposed to be added to D3DX in a future version), we create a texture from the - // file (w/o mipmaps), check that its surface is equal to the original file data (which it - // will not be if the file is not in a texture-supported format or size). If so, copy its - // surface (we might be able to just get its surface and add a ref to it but I'm not sure so - // I'm not going to risk it) and release the texture. If not, create a surface according to - // the file data and use D3DXLoadSurfaceFromFile. This is a horrible hack, but it saves us - // having to write file loaders. Will fix this when D3DX provides us with the right functions. - // Create a surface the size of the file image data - IDirect3DSurface8* surface = NULL; - - { - - file_auto_ptr myfile(_TheFileFactory, filename_); - // If file not found, create a surface with missing texture in it - - if (!myfile->Is_Available()) { - // If file not found, try the dds format - // else create a surface with missing texture in it - char compressed_name[200]; - strncpy(compressed_name, filename_, ARRAY_SIZE(compressed_name)); - compressed_name[ARRAY_SIZE(compressed_name) - 1] = '\0'; - char* ext = strstr(compressed_name, "."); - if (ext && (strlen(ext) == 4) && - ((ext[1] == 't') || (ext[1] == 'T')) && - ((ext[2] == 'g') || (ext[2] == 'G')) && - ((ext[3] == 'a') || (ext[3] == 'A'))) { - ext[1] = 'd'; - ext[2] = 'd'; - ext[3] = 's'; - } - file_auto_ptr myfile2(_TheFileFactory, compressed_name); - if (!myfile2->Is_Available()) - return MissingTexture::_Create_Missing_Surface(); - } - } - - StringClass filename_string(filename_, true); - surface = TextureLoader::Load_Surface_Immediate( - filename_string, - WW3D_FORMAT_UNKNOWN, - true); - return surface; -} - - -/*********************************************************************************************** - * DX8Wrapper::_Update_Texture -- Copies a texture from system memory to video memory * - * * - * * - * * - * * - * INPUT: * - * * - * OUTPUT: * - * * - * WARNINGS: * - * * - * HISTORY: * - * 4/26/2001 hy : Created. * - *=============================================================================================*/ -void DX8Wrapper::_Update_Texture(TextureClass* system, TextureClass* video) -{ - WWASSERT(system); - WWASSERT(video); - WWASSERT(system->Get_Pool() == TextureClass::POOL_SYSTEMMEM); - WWASSERT(video->Get_Pool() == TextureClass::POOL_DEFAULT); - DX8CALL(UpdateTexture(system->Peek_D3D_Base_Texture(), video->Peek_D3D_Base_Texture())); -} - -void DX8Wrapper::Compute_Caps(WW3DFormat display_format) -{ - DX8_THREAD_ASSERT(); - DX8_Assert(); - delete CurrentCaps; - CurrentCaps = new DX8Caps(_Get_D3D8(), D3DDevice, display_format, Get_Current_Adapter_Identifier()); -} - - -void DX8Wrapper::Set_Light(unsigned index, const D3DLIGHT8* light) -{ - if (light) { - render_state.Lights[index] = *light; - render_state.LightEnable[index] = true; - } - else { - render_state.LightEnable[index] = false; - } - render_state_changed |= (LIGHT0_CHANGED << index); -} - -void DX8Wrapper::Set_Light(unsigned index, const LightClass& light) -{ - D3DLIGHT8 dlight; - Vector3 temp; - memset(&dlight, 0, sizeof(D3DLIGHT8)); - - switch (light.Get_Type()) - { - case LightClass::POINT: - { - dlight.Type = D3DLIGHT_POINT; - } - break; - case LightClass::DIRECTIONAL: - { - dlight.Type = D3DLIGHT_DIRECTIONAL; - } - break; - case LightClass::SPOT: - { - dlight.Type = D3DLIGHT_SPOT; - } - break; - } - - light.Get_Diffuse(&temp); - temp *= light.Get_Intensity(); - dlight.Diffuse.r = temp.X; - dlight.Diffuse.g = temp.Y; - dlight.Diffuse.b = temp.Z; - dlight.Diffuse.a = 1.0f; - - light.Get_Specular(&temp); - temp *= light.Get_Intensity(); - dlight.Specular.r = temp.X; - dlight.Specular.g = temp.Y; - dlight.Specular.b = temp.Z; - dlight.Specular.a = 1.0f; - - light.Get_Ambient(&temp); - temp *= light.Get_Intensity(); - dlight.Ambient.r = temp.X; - dlight.Ambient.g = temp.Y; - dlight.Ambient.b = temp.Z; - dlight.Ambient.a = 1.0f; - - temp = light.Get_Position(); - dlight.Position = *(D3DVECTOR*)&temp; - - light.Get_Spot_Direction(temp); - dlight.Direction = *(D3DVECTOR*)&temp; - - dlight.Range = light.Get_Attenuation_Range(); - dlight.Falloff = light.Get_Spot_Exponent(); - dlight.Theta = light.Get_Spot_Angle(); - dlight.Phi = light.Get_Spot_Angle(); - - // Inverse linear light 1/(1+D) - double a, b; - light.Get_Far_Attenuation_Range(a, b); - dlight.Attenuation0 = 1.0f; - if (fabs(a - b) < 1e-5) - // if the attenuation range is too small assume uniform with cutoff - dlight.Attenuation1 = 0.0f; - else - // this will cause the light to drop to half intensity at the first far attenuation - dlight.Attenuation1 = (float)1.0 / a; - dlight.Attenuation2 = 0.0f; - - Set_Light(index, &dlight); -} - -//********************************************************************************************** -//! Set the light environment. This is a lighting model which used up to four -//! directional lights to produce the lighting. -/*! 5/27/02 KJM Added shader light environment support -*/ -void DX8Wrapper::Set_Light_Environment(LightEnvironmentClass* light_env) -{ - // Shader light environment support * -// if (Light_Environment && light_env && (*Light_Environment)==(*light_env)) return; - - Light_Environment = light_env; - - if (light_env) - { - int light_count = light_env->Get_Light_Count(); - unsigned int color = Convert_Color(light_env->Get_Equivalent_Ambient(), 0.0f); - if (RenderStates[D3DRS_AMBIENT] != color) - { - Set_DX8_Render_State(D3DRS_AMBIENT, color); - //buggy Radeon 9700 driver doesn't apply new ambient unless the material also changes. -#if 1 - render_state_changed |= MATERIAL_CHANGED; -#endif - } - - D3DLIGHT8 light; - int l = 0; - for (; l < light_count; ++l) { - - ::ZeroMemory(&light, sizeof(D3DLIGHT8)); - - light.Type = D3DLIGHT_DIRECTIONAL; - (Vector3&)light.Diffuse = light_env->Get_Light_Diffuse(l); - Vector3 dir = -light_env->Get_Light_Direction(l); - light.Direction = (const D3DVECTOR&)(dir); - - // (gth) TODO: put specular into LightEnvironment? Much work to be done on lights :-)' - if (l == 0) { - light.Specular.r = light.Specular.g = light.Specular.b = 1.0f; - } - - if (light_env->isPointLight(l)) { - light.Type = D3DLIGHT_POINT; - (Vector3&)light.Diffuse = light_env->getPointDiffuse(l); - (Vector3&)light.Ambient = light_env->getPointAmbient(l); - light.Position = (const D3DVECTOR&)light_env->getPointCenter(l); - light.Range = light_env->getPointOrad(l); - - // Inverse linear light 1/(1+D) - double a, b; - b = light_env->getPointOrad(l); - a = light_env->getPointIrad(l); - - //(gth) CNC3 Generals code for the attenuation factors is causing the lights to over-brighten - //I'm changing the Attenuation0 parameter to 1.0 to avoid this problem. -#if 0 - light.Attenuation0 = 0.01f; -#else - light.Attenuation0 = 1.0f; -#endif - if (fabs(a - b) < 1e-5) - // if the attenuation range is too small assume uniform with cutoff - light.Attenuation1 = 0.0f; - else - // this will cause the light to drop to half intensity at the first far attenuation - light.Attenuation1 = (float)0.1 / a; - - light.Attenuation2 = 8.0f / (b * b); - } - - Set_Light(l, &light); - } - - for (; l < 4; ++l) { - Set_Light(l, NULL); - } - } - /* else { - for (int l=0;l<4;++l) { - Set_Light(l,NULL); - } - } - */ -} - - -IDirect3DSurface8* DX8Wrapper::_Get_DX8_Front_Buffer() -{ - DX8_THREAD_ASSERT(); - D3DDISPLAYMODE mode; - - DX8CALL(GetDisplayMode(&mode)); - - IDirect3DSurface8* fb = NULL; - - DX8CALL(CreateImageSurface(mode.Width, mode.Height, D3DFMT_A8R8G8B8, &fb)); - - DX8CALL(GetFrontBuffer(fb)); - return fb; -} - -SurfaceClass* DX8Wrapper::_Get_DX8_Back_Buffer(unsigned int num) -{ - DX8_THREAD_ASSERT(); - - IDirect3DSurface8* bb; - SurfaceClass* surf = NULL; - DX8CALL(GetBackBuffer(num, D3DBACKBUFFER_TYPE_MONO, &bb)); - if (bb) - { - surf = NEW_REF(SurfaceClass, (bb)); - bb->Release(); - } - - return surf; -} - -TextureClass* -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 - // - const D3DCAPS8& dx8caps = Get_Current_Caps()->Get_DX8_Caps(); - float poweroftwosize = width; - if (height > 0 && height < width) { - poweroftwosize = height; - } - poweroftwosize = ::Find_POT(poweroftwosize); - - if (poweroftwosize > dx8caps.MaxTextureWidth) { - poweroftwosize = dx8caps.MaxTextureWidth; - } - if (poweroftwosize > dx8caps.MaxTextureHeight) { - poweroftwosize = dx8caps.MaxTextureHeight; - } - - width = height = poweroftwosize; - - // - // Attempt to create the render target - // - 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++; - - // 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 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)) - { - WWDEBUG_SAY(("DX8Wrapper - Render target with depth format is not supported")); - return; - } - - // 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) - { - poweroftwosize = height; - } - poweroftwosize = ::Find_POT(poweroftwosize); - - if (poweroftwosize > dx8caps.MaxTextureWidth) - { - poweroftwosize = dx8caps.MaxTextureWidth; - } - - if (poweroftwosize > dx8caps.MaxTextureHeight) - { - poweroftwosize = dx8caps.MaxTextureHeight; - } - - width = height = poweroftwosize; - - // Attempt to create the render target - 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); - } - - *target = tex; - - // attempt to create the depth stencil buffer - *depth_buffer = NEW_REF - ( - ZTextureClass, - ( - width, - height, - zformat, - MIP_LEVELS_1, - TextureClass::POOL_DEFAULT - ) - ); -} - -/*! - * Set render target - * KM Added optional custom z target - */ -void DX8Wrapper::Set_Render_Target_With_Z -( - TextureClass* texture, - ZTextureClass* ztexture -) -{ - 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 -DX8Wrapper::Set_Render_Target(IDirect3DSwapChain8* swap_chain) -{ - DX8_THREAD_ASSERT(); - WWASSERT(swap_chain != NULL); - - // - // Get the back buffer for the swap chain - // - LPDIRECT3DSURFACE8 render_target = NULL; - swap_chain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &render_target); - - // - // Set this back buffer as the render targer - // - Set_Render_Target(render_target, true); - - // - // Release our hold on the back buffer - // - if (render_target != NULL) { - render_target->Release(); - render_target = NULL; - } - - IsRenderToTexture = false; - - return; -} - -void -DX8Wrapper::Set_Render_Target(IDirect3DSurface8* render_target, bool use_default_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; - WWASSERT(CurrentRenderTarget != NULL); - if (CurrentRenderTarget != NULL) - { - CurrentRenderTarget->AddRef(); - - // - // Switch render targets - // - 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; -// } - - 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 -} - - -IDirect3DSwapChain8* -DX8Wrapper::Create_Additional_Swap_Chain(HWND render_window) -{ - DX8_Assert(); - - // - // Configure the presentation parameters for a windowed render target - // - D3DPRESENT_PARAMETERS params = { 0 }; - params.BackBufferFormat = _PresentParameters.BackBufferFormat; - params.BackBufferCount = 1; - params.MultiSampleType = D3DMULTISAMPLE_NONE; - params.SwapEffect = D3DSWAPEFFECT_COPY_VSYNC; - params.hDeviceWindow = render_window; - params.Windowed = TRUE; - params.EnableAutoDepthStencil = TRUE; - params.AutoDepthStencilFormat = _PresentParameters.AutoDepthStencilFormat; - params.Flags = 0; - params.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT; - params.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; - - // - // Create the swap chain - // - IDirect3DSwapChain8* swap_chain = NULL; - DX8CALL(CreateAdditionalSwapChain(¶ms, &swap_chain)); - return swap_chain; -} - -void DX8Wrapper::Flush_DX8_Resource_Manager(unsigned int bytes) -{ - DX8_Assert(); - DX8CALL(ResourceManagerDiscardBytes(bytes)); -} - -unsigned int DX8Wrapper::Get_Free_Texture_RAM() -{ - DX8_Assert(); - number_of_DX8_calls++; - return DX8Wrapper::_Get_D3D_Device8()->GetAvailableTextureMem(); -} - -// Converts a linear gamma ramp to one that is controlled by: -// Gamma - controls the curvature of the middle of the curve -// Bright - controls the minimum value of the curve -// Contrast - controls the difference between the maximum and the minimum of the curve -void DX8Wrapper::Set_Gamma(float gamma, float bright, float contrast, bool calibrate, bool uselimit) -{ - gamma = Bound(gamma, 0.6f, 6.0f); - bright = Bound(bright, -0.5f, 0.5f); - contrast = Bound(contrast, 0.5f, 2.0f); - float oo_gamma = 1.0f / gamma; - - DX8_Assert(); - number_of_DX8_calls++; - - DWORD flag = (calibrate ? D3DSGR_CALIBRATE : D3DSGR_NO_CALIBRATION); - - D3DGAMMARAMP ramp; - float limit; - - // IML: I'm not really sure what the intent of the 'limit' variable is. It does not produce useful results for my purposes. - if (uselimit) { - limit = (contrast - 1) / 2 * contrast; - } - else { - limit = 0.0f; - } - - // HY - arrived at this equation after much trial and error. - for (int i = 0; i < 256; i++) { - float in, out; - in = i / 256.0f; - float x = in - limit; - x = Bound(x, 0.0f, 1.0f); - x = powf(x, oo_gamma); - out = contrast * x + bright; - out = Bound(out, 0.0f, 1.0f); - ramp.red[i] = (WORD)(out * 65535); - ramp.green[i] = (WORD)(out * 65535); - ramp.blue[i] = (WORD)(out * 65535); - } - - if (Get_Current_Caps()->Support_Gamma()) { - DX8Wrapper::_Get_D3D_Device8()->SetGammaRamp(flag, &ramp); - } - else { - HWND hwnd = GetDesktopWindow(); - HDC hdc = GetDC(hwnd); - if (hdc) - { - SetDeviceGammaRamp(hdc, &ramp); - ReleaseDC(hwnd, hdc); - } - } -} - -//********************************************************************************************** -//! Resets render device to default state -/*! -*/ -void DX8Wrapper::Apply_Default_State() -{ - SNAPSHOT_SAY(("DX8Wrapper::Apply_Default_State()")); - - // only set states used in game - Set_DX8_Render_State(D3DRS_ZENABLE, TRUE); - // Set_DX8_Render_State(D3DRS_FILLMODE, D3DFILL_SOLID); - Set_DX8_Render_State(D3DRS_SHADEMODE, D3DSHADE_GOURAUD); - //Set_DX8_Render_State(D3DRS_LINEPATTERN, 0); - Set_DX8_Render_State(D3DRS_ZWRITEENABLE, TRUE); - Set_DX8_Render_State(D3DRS_ALPHATESTENABLE, FALSE); - //Set_DX8_Render_State(D3DRS_LASTPIXEL, FALSE); - Set_DX8_Render_State(D3DRS_SRCBLEND, D3DBLEND_ONE); - Set_DX8_Render_State(D3DRS_DESTBLEND, D3DBLEND_ZERO); - Set_DX8_Render_State(D3DRS_CULLMODE, D3DCULL_CW); - Set_DX8_Render_State(D3DRS_ZFUNC, D3DCMP_LESSEQUAL); - Set_DX8_Render_State(D3DRS_ALPHAREF, 0); - Set_DX8_Render_State(D3DRS_ALPHAFUNC, D3DCMP_LESSEQUAL); - Set_DX8_Render_State(D3DRS_DITHERENABLE, FALSE); - Set_DX8_Render_State(D3DRS_ALPHABLENDENABLE, FALSE); - Set_DX8_Render_State(D3DRS_FOGENABLE, FALSE); - Set_DX8_Render_State(D3DRS_SPECULARENABLE, FALSE); - // Set_DX8_Render_State(D3DRS_ZVISIBLE, FALSE); - // Set_DX8_Render_State(D3DRS_FOGCOLOR, 0); - // Set_DX8_Render_State(D3DRS_FOGTABLEMODE, D3DFOG_NONE); - // Set_DX8_Render_State(D3DRS_FOGSTART, 0); - - // Set_DX8_Render_State(D3DRS_FOGEND, WWMath::Float_As_Int(1.0f)); - // Set_DX8_Render_State(D3DRS_FOGDENSITY, WWMath::Float_As_Int(1.0f)); - - //Set_DX8_Render_State(D3DRS_EDGEANTIALIAS, FALSE); - Set_DX8_Render_State(D3DRS_ZBIAS, 0); - // Set_DX8_Render_State(D3DRS_RANGEFOGENABLE, FALSE); - Set_DX8_Render_State(D3DRS_STENCILENABLE, FALSE); - Set_DX8_Render_State(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP); - Set_DX8_Render_State(D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP); - Set_DX8_Render_State(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP); - Set_DX8_Render_State(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); - Set_DX8_Render_State(D3DRS_STENCILREF, 0); - Set_DX8_Render_State(D3DRS_STENCILMASK, 0xffffffff); - Set_DX8_Render_State(D3DRS_STENCILWRITEMASK, 0xffffffff); - Set_DX8_Render_State(D3DRS_TEXTUREFACTOR, 0); - /* Set_DX8_Render_State(D3DRS_WRAP0, D3DWRAP_U| D3DWRAP_V); - Set_DX8_Render_State(D3DRS_WRAP1, D3DWRAP_U| D3DWRAP_V); - Set_DX8_Render_State(D3DRS_WRAP2, D3DWRAP_U| D3DWRAP_V); - Set_DX8_Render_State(D3DRS_WRAP3, D3DWRAP_U| D3DWRAP_V); - Set_DX8_Render_State(D3DRS_WRAP4, D3DWRAP_U| D3DWRAP_V); - Set_DX8_Render_State(D3DRS_WRAP5, D3DWRAP_U| D3DWRAP_V); - Set_DX8_Render_State(D3DRS_WRAP6, D3DWRAP_U| D3DWRAP_V); - Set_DX8_Render_State(D3DRS_WRAP7, D3DWRAP_U| D3DWRAP_V);*/ - Set_DX8_Render_State(D3DRS_CLIPPING, TRUE); - Set_DX8_Render_State(D3DRS_LIGHTING, FALSE); - //Set_DX8_Render_State(D3DRS_AMBIENT, 0); -// Set_DX8_Render_State(D3DRS_FOGVERTEXMODE, D3DFOG_NONE); - Set_DX8_Render_State(D3DRS_COLORVERTEX, TRUE); - /* Set_DX8_Render_State(D3DRS_LOCALVIEWER, TRUE); - Set_DX8_Render_State(D3DRS_NORMALIZENORMALS, FALSE); - Set_DX8_Render_State(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1); - Set_DX8_Render_State(D3DRS_SPECULARMATERIALSOURCE, D3DMCS_COLOR2); - Set_DX8_Render_State(D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_MATERIAL); - Set_DX8_Render_State(D3DRS_EMISSIVEMATERIALSOURCE, D3DMCS_MATERIAL); - Set_DX8_Render_State(D3DRS_VERTEXBLEND, D3DVBF_DISABLE);*/ - //Set_DX8_Render_State(D3DRS_CLIPPLANEENABLE, 0); - Set_DX8_Render_State(D3DRS_SOFTWAREVERTEXPROCESSING, FALSE); - //Set_DX8_Render_State(D3DRS_POINTSIZE, 0x3f800000); - //Set_DX8_Render_State(D3DRS_POINTSIZE_MIN, 0); - //Set_DX8_Render_State(D3DRS_POINTSPRITEENABLE, FALSE); - //Set_DX8_Render_State(D3DRS_POINTSCALEENABLE, FALSE); - //Set_DX8_Render_State(D3DRS_POINTSCALE_A, 0); - //Set_DX8_Render_State(D3DRS_POINTSCALE_B, 0); - //Set_DX8_Render_State(D3DRS_POINTSCALE_C, 0); - //Set_DX8_Render_State(D3DRS_MULTISAMPLEANTIALIAS, TRUE); - //Set_DX8_Render_State(D3DRS_MULTISAMPLEMASK, 0xffffffff); - //Set_DX8_Render_State(D3DRS_PATCHEDGESTYLE, D3DPATCHEDGE_DISCRETE); - //Set_DX8_Render_State(D3DRS_PATCHSEGMENTS, 0x3f800000); - //Set_DX8_Render_State(D3DRS_DEBUGMONITORTOKEN, D3DDMT_ENABLE); - //Set_DX8_Render_State(D3DRS_POINTSIZE_MAX, Float_At_Int(64.0f)); - //Set_DX8_Render_State(D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE); - Set_DX8_Render_State(D3DRS_COLORWRITEENABLE, 0x0000000f); - //Set_DX8_Render_State(D3DRS_TWEENFACTOR, 0); - Set_DX8_Render_State(D3DRS_BLENDOP, D3DBLENDOP_ADD); - //Set_DX8_Render_State(D3DRS_POSITIONORDER, D3DORDER_CUBIC); - //Set_DX8_Render_State(D3DRS_NORMALORDER, D3DORDER_LINEAR); - - // disable TSS stages - int i; - for (i = 0; i < CurrentCaps->Get_Max_Textures_Per_Pass(); i++) - { - Set_DX8_Texture_Stage_State(i, D3DTSS_COLOROP, D3DTOP_DISABLE); - Set_DX8_Texture_Stage_State(i, D3DTSS_COLORARG1, D3DTA_TEXTURE); - Set_DX8_Texture_Stage_State(i, D3DTSS_COLORARG2, D3DTA_DIFFUSE); - - Set_DX8_Texture_Stage_State(i, D3DTSS_ALPHAOP, D3DTOP_DISABLE); - Set_DX8_Texture_Stage_State(i, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); - Set_DX8_Texture_Stage_State(i, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); - - /*Set_DX8_Texture_Stage_State(i, D3DTSS_BUMPENVMAT00, 0); - Set_DX8_Texture_Stage_State(i, D3DTSS_BUMPENVMAT01, 0); - Set_DX8_Texture_Stage_State(i, D3DTSS_BUMPENVMAT10, 0); - Set_DX8_Texture_Stage_State(i, D3DTSS_BUMPENVMAT11, 0); - Set_DX8_Texture_Stage_State(i, D3DTSS_BUMPENVLSCALE, 0); - Set_DX8_Texture_Stage_State(i, D3DTSS_BUMPENVLOFFSET, 0);*/ - - Set_DX8_Texture_Stage_State(i, D3DTSS_TEXCOORDINDEX, i); - - - Set_DX8_Texture_Stage_State(i, D3DTSS_ADDRESSU, D3DTADDRESS_WRAP); - Set_DX8_Texture_Stage_State(i, D3DTSS_ADDRESSV, D3DTADDRESS_WRAP); - Set_DX8_Texture_Stage_State(i, D3DTSS_BORDERCOLOR, 0); - // Set_DX8_Texture_Stage_State(i, D3DTSS_MAGFILTER, D3DTEXF_LINEAR); - // Set_DX8_Texture_Stage_State(i, D3DTSS_MINFILTER, D3DTEXF_LINEAR); - // Set_DX8_Texture_Stage_State(i, D3DTSS_MIPFILTER, D3DTEXF_LINEAR); - // Set_DX8_Texture_Stage_State(i, D3DTSS_MIPMAPLODBIAS, 0); - // Set_DX8_Texture_Stage_State(i, D3DTSS_MAXMIPLEVEL, 0); - // Set_DX8_Texture_Stage_State(i, D3DTSS_MAXANISOTROPY, 1); - //Set_DX8_Texture_Stage_State(i, D3DTSS_ADDRESSW, D3DTADDRESS_WRAP); - //Set_DX8_Texture_Stage_State(i, D3DTSS_COLORARG0, D3DTA_CURRENT); - //Set_DX8_Texture_Stage_State(i, D3DTSS_ALPHAARG0, D3DTA_CURRENT); - //Set_DX8_Texture_Stage_State(i, D3DTSS_RESULTARG, D3DTA_CURRENT); - - Set_DX8_Texture_Stage_State(i, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE); - Set_Texture(i, NULL); - } - - // DX8Wrapper::Set_Material(NULL); - VertexMaterialClass::Apply_Null(); - - for (unsigned index = 0; index < 4; ++index) { - SNAPSHOT_SAY(("Clearing light %d to NULL", index)); - Set_DX8_Light(index, NULL); - } - - // set up simple default TSS - Vector4 vconst[MAX_VERTEX_SHADER_CONSTANTS]; - memset(vconst, 0, sizeof(Vector4) * MAX_VERTEX_SHADER_CONSTANTS); - Set_Vertex_Shader_Constant(0, vconst, MAX_VERTEX_SHADER_CONSTANTS); - - Vector4 pconst[MAX_PIXEL_SHADER_CONSTANTS]; - memset(pconst, 0, sizeof(Vector4) * MAX_PIXEL_SHADER_CONSTANTS); - Set_Pixel_Shader_Constant(0, pconst, MAX_PIXEL_SHADER_CONSTANTS); - - Set_Vertex_Shader(DX8_FVF_XYZNDUV2); - Set_Pixel_Shader(0); - - ShaderClass::Invalidate(); -} - -const char* DX8Wrapper::Get_DX8_Render_State_Name(D3DRENDERSTATETYPE state) -{ - switch (state) { - case D3DRS_ZENABLE: return "D3DRS_ZENABLE"; - case D3DRS_FILLMODE: return "D3DRS_FILLMODE"; - case D3DRS_SHADEMODE: return "D3DRS_SHADEMODE"; - case D3DRS_LINEPATTERN: return "D3DRS_LINEPATTERN"; - case D3DRS_ZWRITEENABLE: return "D3DRS_ZWRITEENABLE"; - case D3DRS_ALPHATESTENABLE: return "D3DRS_ALPHATESTENABLE"; - case D3DRS_LASTPIXEL: return "D3DRS_LASTPIXEL"; - case D3DRS_SRCBLEND: return "D3DRS_SRCBLEND"; - case D3DRS_DESTBLEND: return "D3DRS_DESTBLEND"; - case D3DRS_CULLMODE: return "D3DRS_CULLMODE"; - case D3DRS_ZFUNC: return "D3DRS_ZFUNC"; - case D3DRS_ALPHAREF: return "D3DRS_ALPHAREF"; - case D3DRS_ALPHAFUNC: return "D3DRS_ALPHAFUNC"; - case D3DRS_DITHERENABLE: return "D3DRS_DITHERENABLE"; - case D3DRS_ALPHABLENDENABLE: return "D3DRS_ALPHABLENDENABLE"; - case D3DRS_FOGENABLE: return "D3DRS_FOGENABLE"; - case D3DRS_SPECULARENABLE: return "D3DRS_SPECULARENABLE"; - case D3DRS_ZVISIBLE: return "D3DRS_ZVISIBLE"; - case D3DRS_FOGCOLOR: return "D3DRS_FOGCOLOR"; - case D3DRS_FOGTABLEMODE: return "D3DRS_FOGTABLEMODE"; - case D3DRS_FOGSTART: return "D3DRS_FOGSTART"; - case D3DRS_FOGEND: return "D3DRS_FOGEND"; - case D3DRS_FOGDENSITY: return "D3DRS_FOGDENSITY"; - case D3DRS_EDGEANTIALIAS: return "D3DRS_EDGEANTIALIAS"; - case D3DRS_ZBIAS: return "D3DRS_ZBIAS"; - case D3DRS_RANGEFOGENABLE: return "D3DRS_RANGEFOGENABLE"; - case D3DRS_STENCILENABLE: return "D3DRS_STENCILENABLE"; - case D3DRS_STENCILFAIL: return "D3DRS_STENCILFAIL"; - case D3DRS_STENCILZFAIL: return "D3DRS_STENCILZFAIL"; - case D3DRS_STENCILPASS: return "D3DRS_STENCILPASS"; - case D3DRS_STENCILFUNC: return "D3DRS_STENCILFUNC"; - case D3DRS_STENCILREF: return "D3DRS_STENCILREF"; - case D3DRS_STENCILMASK: return "D3DRS_STENCILMASK"; - case D3DRS_STENCILWRITEMASK: return "D3DRS_STENCILWRITEMASK"; - case D3DRS_TEXTUREFACTOR: return "D3DRS_TEXTUREFACTOR"; - case D3DRS_WRAP0: return "D3DRS_WRAP0"; - case D3DRS_WRAP1: return "D3DRS_WRAP1"; - case D3DRS_WRAP2: return "D3DRS_WRAP2"; - case D3DRS_WRAP3: return "D3DRS_WRAP3"; - case D3DRS_WRAP4: return "D3DRS_WRAP4"; - case D3DRS_WRAP5: return "D3DRS_WRAP5"; - case D3DRS_WRAP6: return "D3DRS_WRAP6"; - case D3DRS_WRAP7: return "D3DRS_WRAP7"; - case D3DRS_CLIPPING: return "D3DRS_CLIPPING"; - case D3DRS_LIGHTING: return "D3DRS_LIGHTING"; - case D3DRS_AMBIENT: return "D3DRS_AMBIENT"; - case D3DRS_FOGVERTEXMODE: return "D3DRS_FOGVERTEXMODE"; - case D3DRS_COLORVERTEX: return "D3DRS_COLORVERTEX"; - case D3DRS_LOCALVIEWER: return "D3DRS_LOCALVIEWER"; - case D3DRS_NORMALIZENORMALS: return "D3DRS_NORMALIZENORMALS"; - case D3DRS_DIFFUSEMATERIALSOURCE: return "D3DRS_DIFFUSEMATERIALSOURCE"; - case D3DRS_SPECULARMATERIALSOURCE: return "D3DRS_SPECULARMATERIALSOURCE"; - case D3DRS_AMBIENTMATERIALSOURCE: return "D3DRS_AMBIENTMATERIALSOURCE"; - case D3DRS_EMISSIVEMATERIALSOURCE: return "D3DRS_EMISSIVEMATERIALSOURCE"; - case D3DRS_VERTEXBLEND: return "D3DRS_VERTEXBLEND"; - case D3DRS_CLIPPLANEENABLE: return "D3DRS_CLIPPLANEENABLE"; - case D3DRS_SOFTWAREVERTEXPROCESSING: return "D3DRS_SOFTWAREVERTEXPROCESSING"; - case D3DRS_POINTSIZE: return "D3DRS_POINTSIZE"; - case D3DRS_POINTSIZE_MIN: return "D3DRS_POINTSIZE_MIN"; - case D3DRS_POINTSPRITEENABLE: return "D3DRS_POINTSPRITEENABLE"; - case D3DRS_POINTSCALEENABLE: return "D3DRS_POINTSCALEENABLE"; - case D3DRS_POINTSCALE_A: return "D3DRS_POINTSCALE_A"; - case D3DRS_POINTSCALE_B: return "D3DRS_POINTSCALE_B"; - case D3DRS_POINTSCALE_C: return "D3DRS_POINTSCALE_C"; - case D3DRS_MULTISAMPLEANTIALIAS: return "D3DRS_MULTISAMPLEANTIALIAS"; - case D3DRS_MULTISAMPLEMASK: return "D3DRS_MULTISAMPLEMASK"; - case D3DRS_PATCHEDGESTYLE: return "D3DRS_PATCHEDGESTYLE"; - case D3DRS_PATCHSEGMENTS: return "D3DRS_PATCHSEGMENTS"; - case D3DRS_DEBUGMONITORTOKEN: return "D3DRS_DEBUGMONITORTOKEN"; - case D3DRS_POINTSIZE_MAX: return "D3DRS_POINTSIZE_MAX"; - case D3DRS_INDEXEDVERTEXBLENDENABLE: return "D3DRS_INDEXEDVERTEXBLENDENABLE"; - case D3DRS_COLORWRITEENABLE: return "D3DRS_COLORWRITEENABLE"; - case D3DRS_TWEENFACTOR: return "D3DRS_TWEENFACTOR"; - case D3DRS_BLENDOP: return "D3DRS_BLENDOP"; - // case D3DRS_POSITIONORDER : return "D3DRS_POSITIONORDER"; - // case D3DRS_NORMALORDER : return "D3DRS_NORMALORDER"; - default: return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Texture_Stage_State_Name(D3DTEXTURESTAGESTATETYPE state) -{ - switch (state) { - case D3DTSS_COLOROP: return "D3DTSS_COLOROP"; - case D3DTSS_COLORARG1: return "D3DTSS_COLORARG1"; - case D3DTSS_COLORARG2: return "D3DTSS_COLORARG2"; - case D3DTSS_ALPHAOP: return "D3DTSS_ALPHAOP"; - case D3DTSS_ALPHAARG1: return "D3DTSS_ALPHAARG1"; - case D3DTSS_ALPHAARG2: return "D3DTSS_ALPHAARG2"; - case D3DTSS_BUMPENVMAT00: return "D3DTSS_BUMPENVMAT00"; - case D3DTSS_BUMPENVMAT01: return "D3DTSS_BUMPENVMAT01"; - case D3DTSS_BUMPENVMAT10: return "D3DTSS_BUMPENVMAT10"; - case D3DTSS_BUMPENVMAT11: return "D3DTSS_BUMPENVMAT11"; - case D3DTSS_TEXCOORDINDEX: return "D3DTSS_TEXCOORDINDEX"; - case D3DTSS_ADDRESSU: return "D3DTSS_ADDRESSU"; - case D3DTSS_ADDRESSV: return "D3DTSS_ADDRESSV"; - case D3DTSS_BORDERCOLOR: return "D3DTSS_BORDERCOLOR"; - case D3DTSS_MAGFILTER: return "D3DTSS_MAGFILTER"; - case D3DTSS_MINFILTER: return "D3DTSS_MINFILTER"; - case D3DTSS_MIPFILTER: return "D3DTSS_MIPFILTER"; - case D3DTSS_MIPMAPLODBIAS: return "D3DTSS_MIPMAPLODBIAS"; - case D3DTSS_MAXMIPLEVEL: return "D3DTSS_MAXMIPLEVEL"; - case D3DTSS_MAXANISOTROPY: return "D3DTSS_MAXANISOTROPY"; - case D3DTSS_BUMPENVLSCALE: return "D3DTSS_BUMPENVLSCALE"; - case D3DTSS_BUMPENVLOFFSET: return "D3DTSS_BUMPENVLOFFSET"; - case D3DTSS_TEXTURETRANSFORMFLAGS: return "D3DTSS_TEXTURETRANSFORMFLAGS"; - case D3DTSS_ADDRESSW: return "D3DTSS_ADDRESSW"; - case D3DTSS_COLORARG0: return "D3DTSS_COLORARG0"; - case D3DTSS_ALPHAARG0: return "D3DTSS_ALPHAARG0"; - case D3DTSS_RESULTARG: return "D3DTSS_RESULTARG"; - default: return "UNKNOWN"; - } -} - -void DX8Wrapper::Get_DX8_Render_State_Value_Name(StringClass& name, D3DRENDERSTATETYPE state, unsigned value) -{ - switch (state) { - case D3DRS_ZENABLE: - name = Get_DX8_ZBuffer_Type_Name(value); - break; - - case D3DRS_FILLMODE: - name = Get_DX8_Fill_Mode_Name(value); - break; - - case D3DRS_SHADEMODE: - name = Get_DX8_Shade_Mode_Name(value); - break; - - case D3DRS_LINEPATTERN: - case D3DRS_FOGCOLOR: - case D3DRS_ALPHAREF: - case D3DRS_STENCILMASK: - case D3DRS_STENCILWRITEMASK: - case D3DRS_TEXTUREFACTOR: - case D3DRS_AMBIENT: - case D3DRS_CLIPPLANEENABLE: - case D3DRS_MULTISAMPLEMASK: - name.Format("0x%x", value); - break; - - case D3DRS_ZWRITEENABLE: - case D3DRS_ALPHATESTENABLE: - case D3DRS_LASTPIXEL: - case D3DRS_DITHERENABLE: - case D3DRS_ALPHABLENDENABLE: - case D3DRS_FOGENABLE: - case D3DRS_SPECULARENABLE: - case D3DRS_STENCILENABLE: - case D3DRS_RANGEFOGENABLE: - case D3DRS_EDGEANTIALIAS: - case D3DRS_CLIPPING: - case D3DRS_LIGHTING: - case D3DRS_COLORVERTEX: - case D3DRS_LOCALVIEWER: - case D3DRS_NORMALIZENORMALS: - case D3DRS_SOFTWAREVERTEXPROCESSING: - case D3DRS_POINTSPRITEENABLE: - case D3DRS_POINTSCALEENABLE: - case D3DRS_MULTISAMPLEANTIALIAS: - case D3DRS_INDEXEDVERTEXBLENDENABLE: - name = value ? "TRUE" : "FALSE"; - break; - - case D3DRS_SRCBLEND: - case D3DRS_DESTBLEND: - name = Get_DX8_Blend_Name(value); - break; - - case D3DRS_CULLMODE: - name = Get_DX8_Cull_Mode_Name(value); - break; - - case D3DRS_ZFUNC: - case D3DRS_ALPHAFUNC: - case D3DRS_STENCILFUNC: - name = Get_DX8_Cmp_Func_Name(value); - break; - - case D3DRS_ZVISIBLE: - name = "NOTSUPPORTED"; - break; - - case D3DRS_FOGTABLEMODE: - case D3DRS_FOGVERTEXMODE: - name = Get_DX8_Fog_Mode_Name(value); - break; - - case D3DRS_FOGSTART: - case D3DRS_FOGEND: - case D3DRS_FOGDENSITY: - case D3DRS_POINTSIZE: - case D3DRS_POINTSIZE_MIN: - case D3DRS_POINTSCALE_A: - case D3DRS_POINTSCALE_B: - case D3DRS_POINTSCALE_C: - case D3DRS_PATCHSEGMENTS: - case D3DRS_POINTSIZE_MAX: - case D3DRS_TWEENFACTOR: - name.Format("%f", *(float*)&value); - break; - - case D3DRS_ZBIAS: - case D3DRS_STENCILREF: - name.Format("%d", value); - break; - - case D3DRS_STENCILFAIL: - case D3DRS_STENCILZFAIL: - case D3DRS_STENCILPASS: - name = Get_DX8_Stencil_Op_Name(value); - break; - - case D3DRS_WRAP0: - case D3DRS_WRAP1: - case D3DRS_WRAP2: - case D3DRS_WRAP3: - case D3DRS_WRAP4: - case D3DRS_WRAP5: - case D3DRS_WRAP6: - case D3DRS_WRAP7: - name = "0"; - if (value & D3DWRAP_U) name += "|D3DWRAP_U"; - if (value & D3DWRAP_V) name += "|D3DWRAP_V"; - if (value & D3DWRAP_W) name += "|D3DWRAP_W"; - break; - - case D3DRS_DIFFUSEMATERIALSOURCE: - case D3DRS_SPECULARMATERIALSOURCE: - case D3DRS_AMBIENTMATERIALSOURCE: - case D3DRS_EMISSIVEMATERIALSOURCE: - name = Get_DX8_Material_Source_Name(value); - break; - - case D3DRS_VERTEXBLEND: - name = Get_DX8_Vertex_Blend_Flag_Name(value); - break; - - case D3DRS_PATCHEDGESTYLE: - name = Get_DX8_Patch_Edge_Style_Name(value); - break; - - case D3DRS_DEBUGMONITORTOKEN: - name = Get_DX8_Debug_Monitor_Token_Name(value); - break; - - case D3DRS_COLORWRITEENABLE: - name = "0"; - if (value & D3DCOLORWRITEENABLE_RED) name += "|D3DCOLORWRITEENABLE_RED"; - if (value & D3DCOLORWRITEENABLE_GREEN) name += "|D3DCOLORWRITEENABLE_GREEN"; - if (value & D3DCOLORWRITEENABLE_BLUE) name += "|D3DCOLORWRITEENABLE_BLUE"; - if (value & D3DCOLORWRITEENABLE_ALPHA) name += "|D3DCOLORWRITEENABLE_ALPHA"; - break; - case D3DRS_BLENDOP: - name = Get_DX8_Blend_Op_Name(value); - break; - default: - name.Format("UNKNOWN (%d)", value); - break; - } -} - -void DX8Wrapper::Get_DX8_Texture_Stage_State_Value_Name(StringClass& name, D3DTEXTURESTAGESTATETYPE state, unsigned value) -{ - switch (state) { - case D3DTSS_COLOROP: - case D3DTSS_ALPHAOP: - name = Get_DX8_Texture_Op_Name(value); - break; - - case D3DTSS_COLORARG0: - case D3DTSS_COLORARG1: - case D3DTSS_COLORARG2: - case D3DTSS_ALPHAARG0: - case D3DTSS_ALPHAARG1: - case D3DTSS_ALPHAARG2: - case D3DTSS_RESULTARG: - name = Get_DX8_Texture_Arg_Name(value); - break; - - case D3DTSS_ADDRESSU: - case D3DTSS_ADDRESSV: - case D3DTSS_ADDRESSW: - name = Get_DX8_Texture_Address_Name(value); - break; - - case D3DTSS_MAGFILTER: - case D3DTSS_MINFILTER: - case D3DTSS_MIPFILTER: - name = Get_DX8_Texture_Filter_Name(value); - break; - - case D3DTSS_TEXTURETRANSFORMFLAGS: - name = Get_DX8_Texture_Transform_Flag_Name(value); - break; - - // Floating point values - case D3DTSS_MIPMAPLODBIAS: - case D3DTSS_BUMPENVMAT00: - case D3DTSS_BUMPENVMAT01: - case D3DTSS_BUMPENVMAT10: - case D3DTSS_BUMPENVMAT11: - case D3DTSS_BUMPENVLSCALE: - case D3DTSS_BUMPENVLOFFSET: - name.Format("%f", *(float*)&value); - break; - - case D3DTSS_TEXCOORDINDEX: - if ((value & 0xffff0000) == D3DTSS_TCI_CAMERASPACENORMAL) { - name.Format("D3DTSS_TCI_CAMERASPACENORMAL|%d", value & 0xffff); - } - else if ((value & 0xffff0000) == D3DTSS_TCI_CAMERASPACEPOSITION) { - name.Format("D3DTSS_TCI_CAMERASPACEPOSITION|%d", value & 0xffff); - } - else if ((value & 0xffff0000) == D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR) { - name.Format("D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR|%d", value & 0xffff); - } - else { - name.Format("%d", value); - } - break; - - // Integer value - case D3DTSS_MAXMIPLEVEL: - case D3DTSS_MAXANISOTROPY: - name.Format("%d", value); - break; - // Hex values - case D3DTSS_BORDERCOLOR: - name.Format("0x%x", value); - break; - - default: - name.Format("UNKNOWN (%d)", value); - break; - } -} - -const char* DX8Wrapper::Get_DX8_Texture_Op_Name(unsigned value) -{ - switch (value) { - case D3DTOP_DISABLE: return "D3DTOP_DISABLE"; - case D3DTOP_SELECTARG1: return "D3DTOP_SELECTARG1"; - case D3DTOP_SELECTARG2: return "D3DTOP_SELECTARG2"; - case D3DTOP_MODULATE: return "D3DTOP_MODULATE"; - case D3DTOP_MODULATE2X: return "D3DTOP_MODULATE2X"; - case D3DTOP_MODULATE4X: return "D3DTOP_MODULATE4X"; - case D3DTOP_ADD: return "D3DTOP_ADD"; - case D3DTOP_ADDSIGNED: return "D3DTOP_ADDSIGNED"; - case D3DTOP_ADDSIGNED2X: return "D3DTOP_ADDSIGNED2X"; - case D3DTOP_SUBTRACT: return "D3DTOP_SUBTRACT"; - case D3DTOP_ADDSMOOTH: return "D3DTOP_ADDSMOOTH"; - case D3DTOP_BLENDDIFFUSEALPHA: return "D3DTOP_BLENDDIFFUSEALPHA"; - case D3DTOP_BLENDTEXTUREALPHA: return "D3DTOP_BLENDTEXTUREALPHA"; - case D3DTOP_BLENDFACTORALPHA: return "D3DTOP_BLENDFACTORALPHA"; - case D3DTOP_BLENDTEXTUREALPHAPM: return "D3DTOP_BLENDTEXTUREALPHAPM"; - case D3DTOP_BLENDCURRENTALPHA: return "D3DTOP_BLENDCURRENTALPHA"; - case D3DTOP_PREMODULATE: return "D3DTOP_PREMODULATE"; - case D3DTOP_MODULATEALPHA_ADDCOLOR: return "D3DTOP_MODULATEALPHA_ADDCOLOR"; - case D3DTOP_MODULATECOLOR_ADDALPHA: return "D3DTOP_MODULATECOLOR_ADDALPHA"; - case D3DTOP_MODULATEINVALPHA_ADDCOLOR: return "D3DTOP_MODULATEINVALPHA_ADDCOLOR"; - case D3DTOP_MODULATEINVCOLOR_ADDALPHA: return "D3DTOP_MODULATEINVCOLOR_ADDALPHA"; - case D3DTOP_BUMPENVMAP: return "D3DTOP_BUMPENVMAP"; - case D3DTOP_BUMPENVMAPLUMINANCE: return "D3DTOP_BUMPENVMAPLUMINANCE"; - case D3DTOP_DOTPRODUCT3: return "D3DTOP_DOTPRODUCT3"; - case D3DTOP_MULTIPLYADD: return "D3DTOP_MULTIPLYADD"; - case D3DTOP_LERP: return "D3DTOP_LERP"; - default: return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Texture_Arg_Name(unsigned value) -{ - switch (value) { - case D3DTA_CURRENT: return "D3DTA_CURRENT"; - case D3DTA_DIFFUSE: return "D3DTA_DIFFUSE"; - case D3DTA_SELECTMASK: return "D3DTA_SELECTMASK"; - case D3DTA_SPECULAR: return "D3DTA_SPECULAR"; - case D3DTA_TEMP: return "D3DTA_TEMP"; - case D3DTA_TEXTURE: return "D3DTA_TEXTURE"; - case D3DTA_TFACTOR: return "D3DTA_TFACTOR"; - case D3DTA_ALPHAREPLICATE: return "D3DTA_ALPHAREPLICATE"; - case D3DTA_COMPLEMENT: return "D3DTA_COMPLEMENT"; - default: return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Texture_Filter_Name(unsigned value) -{ - switch (value) { - case D3DTEXF_NONE: return "D3DTEXF_NONE"; - case D3DTEXF_POINT: return "D3DTEXF_POINT"; - case D3DTEXF_LINEAR: return "D3DTEXF_LINEAR"; - case D3DTEXF_ANISOTROPIC: return "D3DTEXF_ANISOTROPIC"; - case D3DTEXF_FLATCUBIC: return "D3DTEXF_FLATCUBIC"; - case D3DTEXF_GAUSSIANCUBIC: return "D3DTEXF_GAUSSIANCUBIC"; - default: return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Texture_Address_Name(unsigned value) -{ - switch (value) { - case D3DTADDRESS_WRAP: return "D3DTADDRESS_WRAP"; - case D3DTADDRESS_MIRROR: return "D3DTADDRESS_MIRROR"; - case D3DTADDRESS_CLAMP: return "D3DTADDRESS_CLAMP"; - case D3DTADDRESS_BORDER: return "D3DTADDRESS_BORDER"; - case D3DTADDRESS_MIRRORONCE: return "D3DTADDRESS_MIRRORONCE"; - default: return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Texture_Transform_Flag_Name(unsigned value) -{ - switch (value) { - case D3DTTFF_DISABLE: return "D3DTTFF_DISABLE"; - case D3DTTFF_COUNT1: return "D3DTTFF_COUNT1"; - case D3DTTFF_COUNT2: return "D3DTTFF_COUNT2"; - case D3DTTFF_COUNT3: return "D3DTTFF_COUNT3"; - case D3DTTFF_COUNT4: return "D3DTTFF_COUNT4"; - case D3DTTFF_PROJECTED: return "D3DTTFF_PROJECTED"; - default: return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_ZBuffer_Type_Name(unsigned value) -{ - switch (value) { - case D3DZB_FALSE: return "D3DZB_FALSE"; - case D3DZB_TRUE: return "D3DZB_TRUE"; - case D3DZB_USEW: return "D3DZB_USEW"; - default: return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Fill_Mode_Name(unsigned value) -{ - switch (value) { - case D3DFILL_POINT: return "D3DFILL_POINT"; - case D3DFILL_WIREFRAME: return "D3DFILL_WIREFRAME"; - case D3DFILL_SOLID: return "D3DFILL_SOLID"; - default: return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Shade_Mode_Name(unsigned value) -{ - switch (value) { - case D3DSHADE_FLAT: return "D3DSHADE_FLAT"; - case D3DSHADE_GOURAUD: return "D3DSHADE_GOURAUD"; - case D3DSHADE_PHONG: return "D3DSHADE_PHONG"; - default: return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Blend_Name(unsigned value) -{ - switch (value) { - case D3DBLEND_ZERO: return "D3DBLEND_ZERO"; - case D3DBLEND_ONE: return "D3DBLEND_ONE"; - case D3DBLEND_SRCCOLOR: return "D3DBLEND_SRCCOLOR"; - case D3DBLEND_INVSRCCOLOR: return "D3DBLEND_INVSRCCOLOR"; - case D3DBLEND_SRCALPHA: return "D3DBLEND_SRCALPHA"; - case D3DBLEND_INVSRCALPHA: return "D3DBLEND_INVSRCALPHA"; - case D3DBLEND_DESTALPHA: return "D3DBLEND_DESTALPHA"; - case D3DBLEND_INVDESTALPHA: return "D3DBLEND_INVDESTALPHA"; - case D3DBLEND_DESTCOLOR: return "D3DBLEND_DESTCOLOR"; - case D3DBLEND_INVDESTCOLOR: return "D3DBLEND_INVDESTCOLOR"; - case D3DBLEND_SRCALPHASAT: return "D3DBLEND_SRCALPHASAT"; - case D3DBLEND_BOTHSRCALPHA: return "D3DBLEND_BOTHSRCALPHA"; - case D3DBLEND_BOTHINVSRCALPHA: return "D3DBLEND_BOTHINVSRCALPHA"; - default: return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Cull_Mode_Name(unsigned value) -{ - switch (value) { - case D3DCULL_NONE: return "D3DCULL_NONE"; - case D3DCULL_CW: return "D3DCULL_CW"; - case D3DCULL_CCW: return "D3DCULL_CCW"; - default: return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Cmp_Func_Name(unsigned value) -{ - switch (value) { - case D3DCMP_NEVER: return "D3DCMP_NEVER"; - case D3DCMP_LESS: return "D3DCMP_LESS"; - case D3DCMP_EQUAL: return "D3DCMP_EQUAL"; - case D3DCMP_LESSEQUAL: return "D3DCMP_LESSEQUAL"; - case D3DCMP_GREATER: return "D3DCMP_GREATER"; - case D3DCMP_NOTEQUAL: return "D3DCMP_NOTEQUAL"; - case D3DCMP_GREATEREQUAL: return "D3DCMP_GREATEREQUAL"; - case D3DCMP_ALWAYS: return "D3DCMP_ALWAYS"; - default: return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Fog_Mode_Name(unsigned value) -{ - switch (value) { - case D3DFOG_NONE: return "D3DFOG_NONE"; - case D3DFOG_EXP: return "D3DFOG_EXP"; - case D3DFOG_EXP2: return "D3DFOG_EXP2"; - case D3DFOG_LINEAR: return "D3DFOG_LINEAR"; - default: return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Stencil_Op_Name(unsigned value) -{ - switch (value) { - case D3DSTENCILOP_KEEP: return "D3DSTENCILOP_KEEP"; - case D3DSTENCILOP_ZERO: return "D3DSTENCILOP_ZERO"; - case D3DSTENCILOP_REPLACE: return "D3DSTENCILOP_REPLACE"; - case D3DSTENCILOP_INCRSAT: return "D3DSTENCILOP_INCRSAT"; - case D3DSTENCILOP_DECRSAT: return "D3DSTENCILOP_DECRSAT"; - case D3DSTENCILOP_INVERT: return "D3DSTENCILOP_INVERT"; - case D3DSTENCILOP_INCR: return "D3DSTENCILOP_INCR"; - case D3DSTENCILOP_DECR: return "D3DSTENCILOP_DECR"; - default: return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Material_Source_Name(unsigned value) -{ - switch (value) { - case D3DMCS_MATERIAL: return "D3DMCS_MATERIAL"; - case D3DMCS_COLOR1: return "D3DMCS_COLOR1"; - case D3DMCS_COLOR2: return "D3DMCS_COLOR2"; - default: return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Vertex_Blend_Flag_Name(unsigned value) -{ - switch (value) { - case D3DVBF_DISABLE: return "D3DVBF_DISABLE"; - case D3DVBF_1WEIGHTS: return "D3DVBF_1WEIGHTS"; - case D3DVBF_2WEIGHTS: return "D3DVBF_2WEIGHTS"; - case D3DVBF_3WEIGHTS: return "D3DVBF_3WEIGHTS"; - case D3DVBF_TWEENING: return "D3DVBF_TWEENING"; - case D3DVBF_0WEIGHTS: return "D3DVBF_0WEIGHTS"; - default: return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Patch_Edge_Style_Name(unsigned value) -{ - switch (value) { - case D3DPATCHEDGE_DISCRETE: return "D3DPATCHEDGE_DISCRETE"; - case D3DPATCHEDGE_CONTINUOUS:return "D3DPATCHEDGE_CONTINUOUS"; - default: return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Debug_Monitor_Token_Name(unsigned value) -{ - switch (value) { - case D3DDMT_ENABLE: return "D3DDMT_ENABLE"; - case D3DDMT_DISABLE: return "D3DDMT_DISABLE"; - default: return "UNKNOWN"; - } -} - -const char* DX8Wrapper::Get_DX8_Blend_Op_Name(unsigned value) -{ - switch (value) { - case D3DBLENDOP_ADD: return "D3DBLENDOP_ADD"; - case D3DBLENDOP_SUBTRACT: return "D3DBLENDOP_SUBTRACT"; - case D3DBLENDOP_REVSUBTRACT: return "D3DBLENDOP_REVSUBTRACT"; - case D3DBLENDOP_MIN: return "D3DBLENDOP_MIN"; - case D3DBLENDOP_MAX: return "D3DBLENDOP_MAX"; - default: return "UNKNOWN"; - } -} - - -//============================================================================ -// DX8Wrapper::getBackBufferFormat -//============================================================================ - -WW3DFormat DX8Wrapper::getBackBufferFormat(void) -{ - return D3DFormat_To_WW3DFormat(_PresentParameters.BackBufferFormat); -} diff --git a/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_header_common.h b/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_header_common.h deleted file mode 100644 index 414256e15a6..00000000000 --- a/Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_header_common.h +++ /dev/null @@ -1,1516 +0,0 @@ -/* -** Command & Conquer Generals Zero Hour(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/dx8wrapper.h $* - * * - * Original Author:: Jani Penttinen * - * * - * Author : Kenny Mitchell * - * * - * $Modtime:: 08/05/02 2:40p $* - * * - * $Revision:: 92 $* - * * - * 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: * - * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - -#if defined(_MSC_VER) -#pragma once -#endif - -#ifndef DX8_WRAPPER_H -#define DX8_WRAPPER_H - -#include "always.h" -#include "dllist.h" -#include "d3d8.h" -#include "matrix4.h" -#include "statistics.h" -#include "wwstring.h" -#include "lightenvironment.h" -#include "shader.h" -#include "vector4.h" -#include "cpudetect.h" -#include "dx8caps.h" - -#include "texture.h" -#include "dx8vertexbuffer.h" -#include "dx8indexbuffer.h" -#include "vertmaterial.h" - - /* - ** Registry value names - */ -#define VALUE_NAME_RENDER_DEVICE_NAME "RenderDeviceName" -#define VALUE_NAME_RENDER_DEVICE_WIDTH "RenderDeviceWidth" -#define VALUE_NAME_RENDER_DEVICE_HEIGHT "RenderDeviceHeight" -#define VALUE_NAME_RENDER_DEVICE_DEPTH "RenderDeviceDepth" -#define VALUE_NAME_RENDER_DEVICE_WINDOWED "RenderDeviceWindowed" -#define VALUE_NAME_RENDER_DEVICE_TEXTURE_DEPTH "RenderDeviceTextureDepth" - -const unsigned MAX_TEXTURE_STAGES = 8; -const unsigned MAX_VERTEX_STREAMS = 2; -const unsigned MAX_VERTEX_SHADER_CONSTANTS = 96; -const unsigned MAX_PIXEL_SHADER_CONSTANTS = 8; -const unsigned MAX_SHADOW_MAPS = 1; - -#define prevVer -#define nextVer - - -enum { - BUFFER_TYPE_DX8, - BUFFER_TYPE_SORTING, - BUFFER_TYPE_DYNAMIC_DX8, - BUFFER_TYPE_DYNAMIC_SORTING, - BUFFER_TYPE_INVALID -}; - -class VertexMaterialClass; -class CameraClass; -class LightEnvironmentClass; -class RenderDeviceDescClass; -class VertexBufferClass; -class DynamicVBAccessClass; -class IndexBufferClass; -class DynamicIBAccessClass; -class TextureClass; -class ZTextureClass; -class LightClass; -class SurfaceClass; -class DX8Caps; - -#define DX8_RECORD_MATRIX_CHANGE() matrix_changes++ -#define DX8_RECORD_MATERIAL_CHANGE() material_changes++ -#define DX8_RECORD_VERTEX_BUFFER_CHANGE() vertex_buffer_changes++ -#define DX8_RECORD_INDEX_BUFFER_CHANGE() index_buffer_changes++ -#define DX8_RECORD_LIGHT_CHANGE() light_changes++ -#define DX8_RECORD_TEXTURE_CHANGE() texture_changes++ -#define DX8_RECORD_RENDER_STATE_CHANGE() render_state_changes++ -#define DX8_RECORD_TEXTURE_STAGE_STATE_CHANGE() texture_stage_state_changes++ -#define DX8_RECORD_DRAW_CALLS() draw_calls++ - -extern unsigned number_of_DX8_calls; -extern bool _DX8SingleThreaded; - -void DX8_Assert(); -void Log_DX8_ErrorCode(unsigned res); - -WWINLINE void DX8_ErrorCode(unsigned res) -{ - if (res == D3D_OK) return; - Log_DX8_ErrorCode(res); -} - -#ifdef WWDEBUG -#define DX8CALL_HRES(x,res) DX8_Assert(); res = DX8Wrapper::_Get_D3D_Device8()->x; DX8_ErrorCode(res); number_of_DX8_calls++; -#define DX8CALL(x) DX8_Assert(); DX8_ErrorCode(DX8Wrapper::_Get_D3D_Device8()->x); number_of_DX8_calls++; -#define DX8CALL_D3D(x) DX8_Assert(); DX8_ErrorCode(DX8Wrapper::_Get_D3D8()->x); number_of_DX8_calls++; -#define DX8_THREAD_ASSERT() if (_DX8SingleThreaded) { WWASSERT_PRINT(DX8Wrapper::_Get_Main_Thread_ID()==ThreadClass::_Get_Current_Thread_ID(),"DX8Wrapper::DX8 calls must be called from the main thread!"); } -#else -#define DX8CALL_HRES(x,res) res = DX8Wrapper::_Get_D3D_Device8()->x; number_of_DX8_calls++; -#define DX8CALL(x) DX8Wrapper::_Get_D3D_Device8()->x; number_of_DX8_calls++; -#define DX8CALL_D3D(x) DX8Wrapper::_Get_D3D8()->x; number_of_DX8_calls++; -#define DX8_THREAD_ASSERT() ; -#endif - - -#define no_EXTENDED_STATS -// EXTENDED_STATS collects additional timing statistics by turning off parts -// of the 3D drawing system (terrain, objects, etc.) -#ifdef EXTENDED_STATS -class DX8_Stats -{ -public: - bool m_showingStats; - bool m_disableTerrain; - bool m_disableWater; - bool m_disableObjects; - bool m_disableOverhead; - bool m_disableConsole; - int m_debugLinesToShow; - int m_sleepTime; -public: - DX8_Stats::DX8_Stats(void) { - m_disableConsole = m_showingStats = m_disableTerrain = m_disableWater = m_disableOverhead = m_disableObjects = false; - m_sleepTime = 0; - m_debugLinesToShow = -1; // -1 means show all expected lines of output - } -}; -#endif - - -// This virtual interface was added for the Generals RTS. -// It is called before resetting the dx8 device to ensure -// that all dx8 resources are released. Otherwise reset fails. jba. -class DX8_CleanupHook -{ -public: - virtual void ReleaseResources(void) = 0; - virtual void ReAcquireResources(void) = 0; -}; - - -struct RenderStateStruct -{ - ShaderClass shader; - VertexMaterialClass* material; - TextureBaseClass* Textures[MAX_TEXTURE_STAGES]; - D3DLIGHT8 Lights[4]; - bool LightEnable[4]; - //unsigned lightsHash; - Matrix4x4 world; - Matrix4x4 view; - unsigned vertex_buffer_types[MAX_VERTEX_STREAMS]; - unsigned index_buffer_type; - unsigned short vba_offset; - unsigned short vba_count; - unsigned short iba_offset; - VertexBufferClass* vertex_buffers[MAX_VERTEX_STREAMS]; - IndexBufferClass* index_buffer; - unsigned short index_base_offset; - - RenderStateStruct(); - ~RenderStateStruct(); - - RenderStateStruct& operator= (const RenderStateStruct& src); -}; - -/** -** DX8Wrapper -** -** DX8 interface wrapper class. This encapsulates the DX8 interface; adding redundant state -** detection, stat tracking, etc etc. In general, we will wrap all DX8 calls with at least -** an WWINLINE function so that we can add stat tracking, etc if needed. Direct access to the -** D3D device will require "friend" status and should be granted only in extreme circumstances :-) -*/ -class DX8Wrapper -{ - enum ChangedStates { - WORLD_CHANGED = 1 << 0, - VIEW_CHANGED = 1 << 1, - LIGHT0_CHANGED = 1 << 2, - LIGHT1_CHANGED = 1 << 3, - LIGHT2_CHANGED = 1 << 4, - LIGHT3_CHANGED = 1 << 5, - TEXTURE0_CHANGED = 1 << 6, - TEXTURE1_CHANGED = 1 << 7, - TEXTURE2_CHANGED = 1 << 8, - TEXTURE3_CHANGED = 1 << 9, - MATERIAL_CHANGED = 1 << 14, - SHADER_CHANGED = 1 << 15, - VERTEX_BUFFER_CHANGED = 1 << 16, - INDEX_BUFFER_CHANGED = 1 << 17, - WORLD_IDENTITY = 1 << 18, - VIEW_IDENTITY = 1 << 19, - - TEXTURES_CHANGED = - TEXTURE0_CHANGED | TEXTURE1_CHANGED | TEXTURE2_CHANGED | TEXTURE3_CHANGED, - LIGHTS_CHANGED = - LIGHT0_CHANGED | LIGHT1_CHANGED | LIGHT2_CHANGED | LIGHT3_CHANGED, - }; - - static void Draw_Sorting_IB_VB( - unsigned primitive_type, - unsigned short start_index, - unsigned short polygon_count, - unsigned short min_vertex_index, - unsigned short vertex_count); - - static void Draw( - unsigned primitive_type, - unsigned short start_index, - unsigned short polygon_count, - unsigned short min_vertex_index = 0, - unsigned short vertex_count = 0); - -public: -#ifdef EXTENDED_STATS - static DX8_Stats stats; -#endif - - static bool Init(void* hwnd, bool lite = false); - static void Shutdown(void); - - static void SetCleanupHook(DX8_CleanupHook* pCleanupHook) { m_pCleanupHook = pCleanupHook; }; - /* - ** Some WW3D sub-systems need to be initialized after the device is created and shutdown - ** before the device is released. - */ - static void Do_Onetime_Device_Dependent_Inits(void); - static void Do_Onetime_Device_Dependent_Shutdowns(void); - - static bool Is_Device_Lost() { return IsDeviceLost; } - static bool Is_Initted(void) { return IsInitted; } - - static bool Has_Stencil(void); - static void Get_Format_Name(unsigned int format, StringClass* tex_format); - - /* - ** Rendering - */ - static void Begin_Scene(void); - static void End_Scene(bool flip_frame = true); - - // Flip until the primary buffer is visible. - static void Flip_To_Primary(void); - - static void Clear(bool clear_color, bool clear_z_stencil, const Vector3& color, float dest_alpha = 0.0f, float z = 1.0f, unsigned int stencil = 0); - - static void Set_Viewport(CONST D3DVIEWPORT8* pViewport); - - static void Set_Vertex_Buffer(const VertexBufferClass* vb, unsigned stream = 0); - static void Set_Vertex_Buffer(const DynamicVBAccessClass& vba); - static void Set_Index_Buffer(const IndexBufferClass* ib, unsigned short index_base_offset); - static void Set_Index_Buffer(const DynamicIBAccessClass& iba, unsigned short index_base_offset); - static void Set_Index_Buffer_Index_Offset(unsigned offset); - - static void Get_Render_State(RenderStateStruct& state); - static void Set_Render_State(const RenderStateStruct& state); - static void Release_Render_State(); - - static void Set_DX8_Material(const D3DMATERIAL8* mat); - - static void Set_Gamma(float gamma, float bright, float contrast, bool calibrate = true, bool uselimit = true); - - // Set_ and Get_Transform() functions take the matrix in Westwood convention format. - - static void Set_DX8_ZBias(int zbias); - static void Set_Projection_Transform_With_Z_Bias(const Matrix4x4& matrix, float znear, float zfar); // pointer to 16 matrices - - static void Set_Transform(D3DTRANSFORMSTATETYPE transform, const Matrix4x4& m); - static void Set_Transform(D3DTRANSFORMSTATETYPE transform, const Matrix3D& m); - static void Get_Transform(D3DTRANSFORMSTATETYPE transform, Matrix4x4& m); - static void Set_World_Identity(); - static void Set_View_Identity(); - static bool Is_World_Identity(); - static bool Is_View_Identity(); - - // Note that *_DX8_Transform() functions take the matrix in DX8 format - transposed from Westwood convention. - - static void _Set_DX8_Transform(D3DTRANSFORMSTATETYPE transform, const Matrix4x4& m); - static void _Set_DX8_Transform(D3DTRANSFORMSTATETYPE transform, const Matrix3D& m); - static void _Get_DX8_Transform(D3DTRANSFORMSTATETYPE transform, Matrix4x4& m); - - static void Set_DX8_Light(int index, D3DLIGHT8* light); - static void Set_DX8_Render_State(D3DRENDERSTATETYPE state, unsigned value); - static void Set_DX8_Clip_Plane(DWORD Index, CONST float* pPlane); - static void Set_DX8_Texture_Stage_State(unsigned stage, D3DTEXTURESTAGESTATETYPE state, unsigned value); - static void Set_DX8_Texture(unsigned int stage, IDirect3DBaseTexture8* texture); - static void Set_Light_Environment(LightEnvironmentClass* light_env); - static LightEnvironmentClass* Get_Light_Environment() { return Light_Environment; } - static void Set_Fog(bool enable, const Vector3& color, float start, float end); - - static WWINLINE const D3DLIGHT8& Peek_Light(unsigned index); - static WWINLINE bool Is_Light_Enabled(unsigned index); - - static bool Validate_Device(void); - - // Deferred - - static void Set_Shader(const ShaderClass& shader); - static void Get_Shader(ShaderClass& shader); - static void Set_Texture(unsigned stage, TextureBaseClass* texture); - static void Set_Material(const VertexMaterialClass* material); - static void Set_Light(unsigned index, const D3DLIGHT8* light); - static void Set_Light(unsigned index, const LightClass& light); - - static void Apply_Render_State_Changes(); // Apply deferred render state changes (will be called automatically by Draw...) - - static void Draw_Triangles( - unsigned buffer_type, - unsigned short start_index, - unsigned short polygon_count, - unsigned short min_vertex_index, - unsigned short vertex_count); - static void Draw_Triangles( - unsigned short start_index, - unsigned short polygon_count, - unsigned short min_vertex_index, - unsigned short vertex_count); - static void Draw_Strip( - unsigned short start_index, - unsigned short index_count, - unsigned short min_vertex_index, - unsigned short vertex_count); - - /* - ** 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, - unsigned int height, - WW3DFormat format, - MipCountType mip_level_count, - D3DPOOL pool = D3DPOOL_MANAGED, - bool rendertarget = false - ); - static IDirect3DTexture8* _Create_DX8_Texture(const char* filename, MipCountType mip_level_count); - static IDirect3DTexture8* _Create_DX8_Texture(IDirect3DSurface8* surface, MipCountType mip_level_count); - - static IDirect3DSurface8* _Create_DX8_Surface(unsigned int width, unsigned int height, WW3DFormat format); - static IDirect3DSurface8* _Create_DX8_Surface(const char* filename); - static IDirect3DSurface8* _Get_DX8_Front_Buffer(); - static SurfaceClass* _Get_DX8_Back_Buffer(unsigned int num = 0); - - static void _Copy_DX8_Rects( - IDirect3DSurface8* pSourceSurface, - CONST RECT* pSourceRectsArray, - UINT cRects, - IDirect3DSurface8* pDestinationSurface, - CONST POINT* pDestPointsArray - ); - - static void _Update_Texture(TextureClass* system, TextureClass* video); - static void Flush_DX8_Resource_Manager(unsigned int bytes = 0); - static unsigned int Get_Free_Texture_RAM(); - - static unsigned _Get_Main_Thread_ID() { return _MainThreadID; } - static const D3DADAPTER_IDENTIFIER8& Get_Current_Adapter_Identifier() { return CurrentAdapterIdentifier; } - - /* - ** Statistics - */ - static void Begin_Statistics(); - static void End_Statistics(); - static unsigned Get_Last_Frame_Matrix_Changes(); - static unsigned Get_Last_Frame_Material_Changes(); - static unsigned Get_Last_Frame_Vertex_Buffer_Changes(); - static unsigned Get_Last_Frame_Index_Buffer_Changes(); - static unsigned Get_Last_Frame_Light_Changes(); - static unsigned Get_Last_Frame_Texture_Changes(); - static unsigned Get_Last_Frame_Render_State_Changes(); - static unsigned Get_Last_Frame_Texture_Stage_State_Changes(); - static unsigned Get_Last_Frame_DX8_Calls(); - static unsigned Get_Last_Frame_Draw_Calls(); - - static unsigned long Get_FrameCount(void); - - // Needed by shader class - static bool Get_Fog_Enable() { return FogEnable; } - static D3DCOLOR Get_Fog_Color() { return FogColor; } - - // Utilities - static Vector4 Convert_Color(unsigned color); - static unsigned int Convert_Color(const Vector4& color); - static unsigned int Convert_Color(const Vector3& color, const float alpha); - static void Clamp_Color(Vector4& color); - static unsigned int Convert_Color_Clamp(const Vector4& color); - - static void Set_Alpha(const float alpha, unsigned int& color); - - static void _Enable_Triangle_Draw(bool enable) { _EnableTriangleDraw = enable; } - static bool _Is_Triangle_Draw_Enabled() { return _EnableTriangleDraw; } - - /* - ** Additional swap chain interface - ** - ** Use this interface to render to multiple windows (in windowed mode). - ** To render to an additional window, the sequence of calls should look - ** something like this: - ** - ** DX8Wrapper::Set_Render_Target (swap_chain_ptr); - ** - ** WW3D::Begin_Render (true, true, Vector3 (0, 0, 0)); - ** WW3D::Render (scene, camera, FALSE, FALSE); - ** WW3D::End_Render (); - ** - ** swap_chain_ptr->Present (NULL, NULL, NULL, NULL); - ** - ** DX8Wrapper::Set_Render_Target ((IDirect3DSurface8 *)NULL); - ** - */ - static IDirect3DSwapChain8* Create_Additional_Swap_Chain(HWND render_window); - - /* - ** 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, 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(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(); - - static void Set_Vertex_Shader(DWORD vertex_shader); - static void Set_Pixel_Shader(DWORD pixel_shader); - - static void Set_Vertex_Shader_Constant(int reg, const void* data, int count); - static void Set_Pixel_Shader_Constant(int reg, const void* data, int count); - - static DWORD Get_Vertex_Processing_Behavior() { return Vertex_Processing_Behavior; } - - // Needed by scene lighting class - static void Set_Ambient(const Vector3& color); - static const Vector3& Get_Ambient() { return Ambient_Color; } - // shader system updates KJM ^ - - - - - static IDirect3DDevice8* _Get_D3D_Device8() { return D3DDevice; } - static IDirect3D8* _Get_D3D8() { return D3DInterface; } - /// Returns the display format - added by TR for video playback - not part of W3D - static WW3DFormat getBackBufferFormat(void); - static bool Reset_Device(bool reload_assets = true); - - static const DX8Caps* Get_Current_Caps() { WWASSERT(CurrentCaps); return CurrentCaps; } - - static bool Registry_Save_Render_Device(const char* sub_key); - static bool Registry_Load_Render_Device(const char* sub_key, bool resize_window); - - static const char* Get_DX8_Render_State_Name(D3DRENDERSTATETYPE state); - static const char* Get_DX8_Texture_Stage_State_Name(D3DTEXTURESTAGESTATETYPE state); - static unsigned Get_DX8_Render_State(D3DRENDERSTATETYPE state) { return RenderStates[state]; } - - // Names of the specific values of render states and texture stage states - static void Get_DX8_Texture_Stage_State_Value_Name(StringClass& name, D3DTEXTURESTAGESTATETYPE state, unsigned value); - static void Get_DX8_Render_State_Value_Name(StringClass& name, D3DRENDERSTATETYPE state, unsigned value); - - static const char* Get_DX8_Texture_Address_Name(unsigned value); - static const char* Get_DX8_Texture_Filter_Name(unsigned value); - static const char* Get_DX8_Texture_Arg_Name(unsigned value); - static const char* Get_DX8_Texture_Op_Name(unsigned value); - static const char* Get_DX8_Texture_Transform_Flag_Name(unsigned value); - static const char* Get_DX8_ZBuffer_Type_Name(unsigned value); - static const char* Get_DX8_Fill_Mode_Name(unsigned value); - static const char* Get_DX8_Shade_Mode_Name(unsigned value); - static const char* Get_DX8_Blend_Name(unsigned value); - static const char* Get_DX8_Cull_Mode_Name(unsigned value); - static const char* Get_DX8_Cmp_Func_Name(unsigned value); - static const char* Get_DX8_Fog_Mode_Name(unsigned value); - static const char* Get_DX8_Stencil_Op_Name(unsigned value); - static const char* Get_DX8_Material_Source_Name(unsigned value); - static const char* Get_DX8_Vertex_Blend_Flag_Name(unsigned value); - static const char* Get_DX8_Patch_Edge_Style_Name(unsigned value); - static const char* Get_DX8_Debug_Monitor_Token_Name(unsigned value); - static const char* Get_DX8_Blend_Op_Name(unsigned value); - - static void Invalidate_Cached_Render_States(void); - - static void Set_Draw_Polygon_Low_Bound_Limit(unsigned n) { DrawPolygonLowBoundLimit = n; } - -protected: - - static bool Create_Device(void); - static void Release_Device(void); - - static void Reset_Statistics(); - static void Enumerate_Devices(); - static void Set_Default_Global_Render_States(void); - - /* - ** Device Selection Code. - ** For backward compatibility, the public interface for these functions is in the ww3d. - ** header file. These functions are protected so that we aren't exposing two interfaces. - */ - static bool Set_Any_Render_Device(void); - static bool Set_Render_Device(const char* dev_name, int width = -1, int height = -1, int bits = -1, int windowed = -1, bool resize_window = false); - static bool Set_Render_Device(int dev = -1, int resx = -1, int resy = -1, int bits = -1, int windowed = -1, bool resize_window = false, bool reset_device = false, bool restore_assets = true); - static bool Set_Next_Render_Device(void); - static bool Toggle_Windowed(void); - - static int Get_Render_Device_Count(void); - static int Get_Render_Device(void); - static const RenderDeviceDescClass& Get_Render_Device_Desc(int deviceidx); - static const char* Get_Render_Device_Name(int device_index); - static bool Set_Device_Resolution(int width = -1, int height = -1, int bits = -1, int windowed = -1, bool resize_window = false); - static void Get_Device_Resolution(int& set_w, int& set_h, int& set_bits, bool& set_windowed); - static void Get_Render_Target_Resolution(int& set_w, int& set_h, int& set_bits, bool& set_windowed); - static int Get_Device_Resolution_Width(void) { return ResolutionWidth; } - static int Get_Device_Resolution_Height(void) { return ResolutionHeight; } - - static bool Registry_Save_Render_Device(const char* sub_key, int device, int width, int height, int depth, bool windowed, int texture_depth); - static bool Registry_Load_Render_Device(const char* sub_key, char* device, int device_len, int& width, int& height, int& depth, int& windowed, int& texture_depth); - static bool Is_Windowed(void) { return IsWindowed; } - - static void Set_Texture_Bitdepth(int depth) { WWASSERT(depth == 16 || depth == 32); TextureBitDepth = depth; } - static int Get_Texture_Bitdepth(void) { return TextureBitDepth; } - - static void Set_Swap_Interval(int swap); - static int Get_Swap_Interval(void); - static void Set_Polygon_Mode(int mode); - - /* - ** Internal functions - */ - static void Resize_And_Position_Window(); - static bool Find_Color_And_Z_Mode(int resx, int resy, int bitdepth, D3DFORMAT* set_colorbuffer, D3DFORMAT* set_backbuffer, D3DFORMAT* set_zmode); - static bool Find_Color_Mode(D3DFORMAT colorbuffer, int resx, int resy, UINT* mode); - static bool Find_Z_Mode(D3DFORMAT colorbuffer, D3DFORMAT backbuffer, D3DFORMAT* zmode); - static bool Test_Z_Mode(D3DFORMAT colorbuffer, D3DFORMAT backbuffer, D3DFORMAT zmode); - static void Compute_Caps(WW3DFormat display_format); - - /* - ** Protected Member Variables - */ - - static DX8_CleanupHook* m_pCleanupHook; - - static RenderStateStruct render_state; - static unsigned render_state_changed; - static Matrix4x4 DX8Transforms[D3DTS_WORLD + 1]; - - static bool IsInitted; - static bool IsDeviceLost; - static void* Hwnd; - static unsigned _MainThreadID; - - static bool _EnableTriangleDraw; - - static int CurRenderDevice; - static int ResolutionWidth; - static int ResolutionHeight; - static int BitDepth; - static int TextureBitDepth; - static bool IsWindowed; - static D3DFORMAT DisplayFormat; - - static D3DMATRIX old_world; - static D3DMATRIX old_view; - static D3DMATRIX old_prj; - - // shader system updates KJM v - static DWORD Vertex_Shader; - static DWORD Pixel_Shader; - - static Vector4 Vertex_Shader_Constants[MAX_VERTEX_SHADER_CONSTANTS]; - static Vector4 Pixel_Shader_Constants[MAX_PIXEL_SHADER_CONSTANTS]; - - static LightEnvironmentClass* Light_Environment; - static RenderInfoClass* Render_Info; - - static DWORD Vertex_Processing_Behavior; - - static ZTextureClass* Shadow_Map[MAX_SHADOW_MAPS]; - - static Vector3 Ambient_Color; - // shader system updates KJM ^ - - static bool world_identity; - static unsigned RenderStates[256]; - static unsigned TextureStageStates[MAX_TEXTURE_STAGES][32]; - static IDirect3DBaseTexture8* Textures[MAX_TEXTURE_STAGES]; - - // These fog settings are constant for all objects in a given scene, - // unlike the matching renderstates which vary based on shader settings. - static bool FogEnable; - static D3DCOLOR FogColor; - - static unsigned matrix_changes; - static unsigned material_changes; - static unsigned vertex_buffer_changes; - static unsigned index_buffer_changes; - static unsigned light_changes; - static unsigned texture_changes; - static unsigned render_state_changes; - static unsigned texture_stage_state_changes; - static unsigned draw_calls; - static bool CurrentDX8LightEnables[4]; - - static unsigned long FrameCount; - - static DX8Caps* CurrentCaps; - - static D3DADAPTER_IDENTIFIER8 CurrentAdapterIdentifier; - - static IDirect3D8* D3DInterface; //d3d8; - static IDirect3DDevice8* D3DDevice; //d3ddevice8; - - static IDirect3DSurface8* CurrentRenderTarget; - static IDirect3DSurface8* CurrentDepthBuffer; - static IDirect3DSurface8* DefaultRenderTarget; - static IDirect3DSurface8* DefaultDepthBuffer; - - static unsigned DrawPolygonLowBoundLimit; - - static bool IsRenderToTexture; - - static int ZBias; - static float ZNear; - static float ZFar; - static Matrix4x4 ProjectionMatrix; - - friend void DX8_Assert(); - friend class WW3D; - friend class DX8IndexBufferClass; - friend class DX8VertexBufferClass; -}; - -// shader system updates KJM v -WWINLINE void DX8Wrapper::Set_Vertex_Shader(DWORD vertex_shader) -{ -#if 0 //(gth) some code is bypassing this acessor function so we can't count on this variable... - // may be incorrect if shaders are created and destroyed dynamically - if (Vertex_Shader == vertex_shader) return; -#endif - - Vertex_Shader = vertex_shader; - DX8CALL(SetVertexShader(Vertex_Shader)); -} - -WWINLINE void DX8Wrapper::Set_Pixel_Shader(DWORD pixel_shader) -{ - // may be incorrect if shaders are created and destroyed dynamically - if (Pixel_Shader == pixel_shader) return; - - Pixel_Shader = pixel_shader; - DX8CALL(SetPixelShader(Pixel_Shader)); -} - -WWINLINE void DX8Wrapper::Set_Vertex_Shader_Constant(int reg, const void* data, int count) -{ - int memsize = sizeof(Vector4) * count; - - // may be incorrect if shaders are created and destroyed dynamically - if (memcmp(data, &Vertex_Shader_Constants[reg], memsize) == 0) return; - - memcpy(&Vertex_Shader_Constants[reg], data, memsize); - DX8CALL(SetVertexShaderConstant(reg, data, count)); -} - -WWINLINE void DX8Wrapper::Set_Pixel_Shader_Constant(int reg, const void* data, int count) -{ - int memsize = sizeof(Vector4) * count; - - // may be incorrect if shaders are created and destroyed dynamically - if (memcmp(data, &Pixel_Shader_Constants[reg], memsize) == 0) return; - - memcpy(&Pixel_Shader_Constants[reg], data, memsize); - DX8CALL(SetPixelShaderConstant(reg, data, count)); -} -// shader system updates KJM ^ - - -WWINLINE void DX8Wrapper::_Set_DX8_Transform(D3DTRANSFORMSTATETYPE transform, const Matrix4x4& m) -{ - WWASSERT(transform <= D3DTS_WORLD); -#if 0 // (gth) this optimization is breaking generals because they set the transform behind our backs. - if (m != DX8Transforms[transform]) -#endif - { - DX8Transforms[transform] = m; - SNAPSHOT_SAY(("DX8 - SetTransform %d [%f,%f,%f,%f][%f,%f,%f,%f][%f,%f,%f,%f][%f,%f,%f,%f]", transform, m[0][0], m[0][1], m[0][2], m[0][3], m[1][0], m[1][1], m[1][2], m[1][3], m[2][0], m[2][1], m[2][2], m[2][3], m[3][0], m[3][1], m[3][2], m[3][3])); - DX8_RECORD_MATRIX_CHANGE(); - DX8CALL(SetTransform(transform, (D3DMATRIX*)&m)); - } -} - - -WWINLINE void DX8Wrapper::_Set_DX8_Transform(D3DTRANSFORMSTATETYPE transform, const Matrix3D& m) -{ - WWASSERT(transform <= D3DTS_WORLD); - Matrix4x4 mtx(m); -#if 0 // (gth) this optimization is breaking generals because they set the transform behind our backs. - if (mtx != DX8Transforms[transform]) -#endif - { - DX8Transforms[transform] = mtx; - SNAPSHOT_SAY(("DX8 - SetTransform %d [%f,%f,%f,%f][%f,%f,%f,%f][%f,%f,%f,%f]", transform, m[0][0], m[0][1], m[0][2], m[0][3], m[1][0], m[1][1], m[1][2], m[1][3], m[2][0], m[2][1], m[2][2], m[2][3])); - DX8_RECORD_MATRIX_CHANGE(); - DX8CALL(SetTransform(transform, (D3DMATRIX*)&m)); - } -} - -WWINLINE void DX8Wrapper::_Get_DX8_Transform(D3DTRANSFORMSTATETYPE transform, Matrix4x4& m) -{ - DX8CALL(GetTransform(transform, (D3DMATRIX*)&m)); -} - -// ---------------------------------------------------------------------------- -// -// Set the index offset for the current index buffer -// -// ---------------------------------------------------------------------------- - -WWINLINE void DX8Wrapper::Set_Index_Buffer_Index_Offset(unsigned offset) -{ - if (render_state.index_base_offset == offset) return; - render_state.index_base_offset = offset; - render_state_changed |= INDEX_BUFFER_CHANGED; -} - -// ---------------------------------------------------------------------------- -// Set the fog settings. This function should be used, rather than setting the -// appropriate renderstates directly, because the shader sets some of the -// renderstates on a per-mesh / per-pass basis depending on global fog states -// (stored in the wrapper) as well as the shader settings. -// This function should be called rarely - once per scene would be appropriate. -// ---------------------------------------------------------------------------- - -WWINLINE void DX8Wrapper::Set_Fog(bool enable, const Vector3& color, float start, float end) -{ - // Set global states - FogEnable = enable; - FogColor = Convert_Color(color, 0.0f); - - // Invalidate the current shader (since the renderstates set by the shader - // depend on the global fog settings as well as the actual shader settings) - ShaderClass::Invalidate(); - - // Set renderstates which are not affected by the shader - Set_DX8_Render_State(D3DRS_FOGSTART, *(DWORD*)(&start)); - Set_DX8_Render_State(D3DRS_FOGEND, *(DWORD*)(&end)); -} - - -WWINLINE void DX8Wrapper::Set_Ambient(const Vector3& color) -{ - Ambient_Color = color; - Set_DX8_Render_State(D3DRS_AMBIENT, DX8Wrapper::Convert_Color(color, 0.0f)); -} - -// ---------------------------------------------------------------------------- -// -// Set vertex buffer to be used in the subsequent render calls. If there was -// a vertex buffer being used earlier, release the reference to it. Passing -// NULL just will release the vertex buffer. -// -// ---------------------------------------------------------------------------- - -WWINLINE void DX8Wrapper::Set_DX8_Material(const D3DMATERIAL8* mat) -{ - DX8_RECORD_MATERIAL_CHANGE(); - WWASSERT(mat); - SNAPSHOT_SAY(("DX8 - SetMaterial")); - DX8CALL(SetMaterial(mat)); -} - -WWINLINE void DX8Wrapper::Set_DX8_Light(int index, D3DLIGHT8* light) -{ - if (light) { - DX8_RECORD_LIGHT_CHANGE(); - DX8CALL(SetLight(index, light)); - DX8CALL(LightEnable(index, TRUE)); - CurrentDX8LightEnables[index] = true; - SNAPSHOT_SAY(("DX8 - SetLight %d", index)); - } - else if (CurrentDX8LightEnables[index]) { - DX8_RECORD_LIGHT_CHANGE(); - CurrentDX8LightEnables[index] = false; - DX8CALL(LightEnable(index, FALSE)); - SNAPSHOT_SAY(("DX8 - DisableLight %d", index)); - } -} - -WWINLINE void DX8Wrapper::Set_DX8_Render_State(D3DRENDERSTATETYPE state, unsigned value) -{ - // Can't monitor state changes because setShader call to GERD may change the states! - if (RenderStates[state] == value) return; - -#ifdef MESH_RENDER_SNAPSHOT_ENABLED - if (WW3D::Is_Snapshot_Activated()) { - StringClass value_name(0, true); - Get_DX8_Render_State_Value_Name(value_name, state, value); - SNAPSHOT_SAY(("DX8 - SetRenderState(state: %s, value: %s)", - Get_DX8_Render_State_Name(state), - value_name.str())); - } -#endif - - RenderStates[state] = value; - DX8CALL(SetRenderState(state, value)); - DX8_RECORD_RENDER_STATE_CHANGE(); -} - -WWINLINE void DX8Wrapper::Set_DX8_Clip_Plane(DWORD Index, CONST float* pPlane) -{ - DX8CALL(SetClipPlane(Index, pPlane)); -} - -WWINLINE void DX8Wrapper::Set_DX8_Texture_Stage_State(unsigned stage, D3DTEXTURESTAGESTATETYPE state, unsigned value) -{ - if (stage >= MAX_TEXTURE_STAGES) - { - DX8CALL(SetTextureStageState(stage, state, value)); - return; - } - - // Can't monitor state changes because setShader call to GERD may change the states! - if (TextureStageStates[stage][(unsigned int)state] == value) return; -#ifdef MESH_RENDER_SNAPSHOT_ENABLED - if (WW3D::Is_Snapshot_Activated()) { - StringClass value_name(0, true); - Get_DX8_Texture_Stage_State_Value_Name(value_name, state, value); - SNAPSHOT_SAY(("DX8 - SetTextureStageState(stage: %d, state: %s, value: %s)", - stage, - Get_DX8_Texture_Stage_State_Name(state), - value_name.str())); - } -#endif - - TextureStageStates[stage][(unsigned int)state] = value; - DX8CALL(SetTextureStageState(stage, state, value)); - DX8_RECORD_TEXTURE_STAGE_STATE_CHANGE(); -} - -WWINLINE void DX8Wrapper::Set_DX8_Texture(unsigned int stage, IDirect3DBaseTexture8* texture) -{ - if (stage >= MAX_TEXTURE_STAGES) - { - DX8CALL(SetTexture(stage, texture)); - return; - } - - if (Textures[stage] == texture) return; - - SNAPSHOT_SAY(("DX8 - SetTexture(%x) ", texture)); - - if (Textures[stage]) Textures[stage]->Release(); - Textures[stage] = texture; - if (Textures[stage]) Textures[stage]->AddRef(); - DX8CALL(SetTexture(stage, texture)); - DX8_RECORD_TEXTURE_CHANGE(); -} - -WWINLINE void DX8Wrapper::_Copy_DX8_Rects( - IDirect3DSurface8* pSourceSurface, - CONST RECT* pSourceRectsArray, - UINT cRects, - IDirect3DSurface8* pDestinationSurface, - CONST POINT* pDestPointsArray -) -{ - DX8CALL(CopyRects( - pSourceSurface, - pSourceRectsArray, - cRects, - pDestinationSurface, - pDestPointsArray)); -} - -WWINLINE Vector4 DX8Wrapper::Convert_Color(unsigned color) -{ - Vector4 col; - col[3] = ((color & 0xff000000) >> 24) / 255.0f; - col[0] = ((color & 0xff0000) >> 16) / 255.0f; - col[1] = ((color & 0xff00) >> 8) / 255.0f; - col[2] = ((color & 0xff) >> 0) / 255.0f; - // col=Vector4(1.0f,1.0f,1.0f,1.0f); - return col; -} - -#if 0 -WWINLINE unsigned int DX8Wrapper::Convert_Color(const Vector3& color, const float alpha) -{ - WWASSERT(color.X <= 1.0f); - WWASSERT(color.Y <= 1.0f); - WWASSERT(color.Z <= 1.0f); - WWASSERT(alpha <= 1.0f); - WWASSERT(color.X >= 0.0f); - WWASSERT(color.Y >= 0.0f); - WWASSERT(color.Z >= 0.0f); - WWASSERT(alpha >= 0.0f); - - return D3DCOLOR_COLORVALUE(color.X, color.Y, color.Z, alpha); -} -WWINLINE unsigned int DX8Wrapper::Convert_Color(const Vector4& color) -{ - WWASSERT(color.X <= 1.0f); - WWASSERT(color.Y <= 1.0f); - WWASSERT(color.Z <= 1.0f); - WWASSERT(color.W <= 1.0f); - WWASSERT(color.X >= 0.0f); - WWASSERT(color.Y >= 0.0f); - WWASSERT(color.Z >= 0.0f); - WWASSERT(color.W >= 0.0f); - - return D3DCOLOR_COLORVALUE(color.X, color.Y, color.Z, color.W); -} -#else - -// ---------------------------------------------------------------------------- -// -// Convert RGBA color from float vector to 32 bit integer -// Note: Color vector needs to be clamped to [0...1] range! -// -// ---------------------------------------------------------------------------- - -WWINLINE unsigned int DX8Wrapper::Convert_Color(const Vector3& color, float alpha) -{ -#if defined(_MSC_VER) && _MSC_VER < 1300 - const float scale = 255.0; - unsigned int col; - - // Multiply r, g, b and a components (0.0,...,1.0) by 255 and convert to integer. Or the integer values togerher - // such that 32 bit ingeger has AAAAAAAARRRRRRRRGGGGGGGGBBBBBBBB. - __asm - { - sub esp, 20 // space for a, r, g and b float plus fpu rounding mode - - // Store the fpu rounding mode - - fwait - fstcw[esp + 16] // store control word to stack - mov eax, [esp + 16] // load it to eax - mov edi, eax // take copy - and eax, ~(1024 | 2048) // mask out certain bits - or eax, (1024 | 2048) // or with precision control value "truncate" - sub edi, eax // did it change? - jz skip // .. if not, skip - mov[esp], eax // .. change control word - fldcw[esp] - skip: - - // Convert the color - - mov esi, dword ptr color - fld dword ptr[scale] - - fld dword ptr[esi] // r - fld dword ptr[esi + 4] // g - fld dword ptr[esi + 8] // b - fld dword ptr[alpha] // a - fld st(4) - fmul st(4), st - fmul st(3), st - fmul st(2), st - fmulp st(1), st - fistp dword ptr[esp + 0] // a - fistp dword ptr[esp + 4] // b - fistp dword ptr[esp + 8] // g - fistp dword ptr[esp + 12] // r - mov ecx, [esp] // a - mov eax, [esp + 4] // b - mov edx, [esp + 8] // g - mov ebx, [esp + 12] // r - shl ecx, 24 // a << 24 - shl ebx, 16 // r << 16 - shl edx, 8 // g << 8 - or eax, ecx // (a << 24) | b - or eax, ebx // (a << 24) | (r << 16) | b - or eax, edx // (a << 24) | (r << 16) | (g << 8) | b - - fstp st(0) - - // Restore fpu rounding mode - - cmp edi, 0 // did we change the value? - je not_changed // nope... skip now... - fwait - fldcw[esp + 16]; - not_changed: - add esp, 20 - - mov col, eax - } - return col; -#else - return color.Convert_To_ARGB(alpha); -#endif // defined(_MSC_VER) && _MSC_VER < 1300 -} - -// ---------------------------------------------------------------------------- -// -// Clamp color vector to [0...1] range -// -// ---------------------------------------------------------------------------- - -WWINLINE void DX8Wrapper::Clamp_Color(Vector4& color) -{ -#if defined(_MSC_VER) && _MSC_VER < 1300 - if (CPUDetectClass::Has_CMOV_Instruction()) { - __asm - { - mov esi, dword ptr color - - mov edx, 0x3f800000 - - mov edi, dword ptr[esi] - mov ebx, edi - sar edi, 31 - not edi // mask is now zero if negative value - and edi, ebx - cmp edi, edx // if no less than 1.0 set to 1.0 - cmovnb edi, edx - mov dword ptr[esi], edi - - mov edi, dword ptr[esi + 4] - mov ebx, edi - sar edi, 31 - not edi // mask is now zero if negative value - and edi, ebx - cmp edi, edx // if no less than 1.0 set to 1.0 - cmovnb edi, edx - mov dword ptr[esi + 4], edi - - mov edi, dword ptr[esi + 8] - mov ebx, edi - sar edi, 31 - not edi // mask is now zero if negative value - and edi, ebx - cmp edi, edx // if no less than 1.0 set to 1.0 - cmovnb edi, edx - mov dword ptr[esi + 8], edi - - mov edi, dword ptr[esi + 12] - mov ebx, edi - sar edi, 31 - not edi // mask is now zero if negative value - and edi, ebx - cmp edi, edx // if no less than 1.0 set to 1.0 - cmovnb edi, edx - mov dword ptr[esi + 12], edi - } - return; - } -#endif // defined(_MSC_VER) && _MSC_VER < 1300 - - for (int i = 0; i < 4; ++i) { - float f = (color[i] < 0.0f) ? 0.0f : color[i]; - color[i] = (f > 1.0f) ? 1.0f : f; - } -} - -// ---------------------------------------------------------------------------- -// -// Convert RGBA color from float vector to 32 bit integer -// -// ---------------------------------------------------------------------------- - -WWINLINE unsigned int DX8Wrapper::Convert_Color(const Vector4& color) -{ - return Convert_Color(reinterpret_cast(color), color[3]); -} - -WWINLINE unsigned int DX8Wrapper::Convert_Color_Clamp(const Vector4& color) -{ - Vector4 clamped_color = color; - DX8Wrapper::Clamp_Color(clamped_color); - return Convert_Color(reinterpret_cast(clamped_color), clamped_color[3]); -} - -#endif - - -WWINLINE void DX8Wrapper::Set_Alpha(const float alpha, unsigned int& color) -{ - unsigned char* component = (unsigned char*)&color; - - component[3] = 255.0f * alpha; -} - -WWINLINE void DX8Wrapper::Get_Render_State(RenderStateStruct& state) -{ - state = render_state; -} - -WWINLINE void DX8Wrapper::Get_Shader(ShaderClass& shader) -{ - shader = render_state.shader; -} - -WWINLINE void DX8Wrapper::Set_Texture(unsigned stage, TextureBaseClass* texture) -{ - WWASSERT(stage < (unsigned int)CurrentCaps->Get_Max_Textures_Per_Pass()); - if (texture == render_state.Textures[stage]) return; - REF_PTR_SET(render_state.Textures[stage], texture); - render_state_changed |= (TEXTURE0_CHANGED << stage); -} - -WWINLINE void DX8Wrapper::Set_Material(const VertexMaterialClass* material) -{ - /* if (material && render_state.material && - // !stricmp(material->Get_Name(),render_state.material->Get_Name())) { - material->Get_CRC()!=render_state.material->Get_CRC()) { - return; - } - */ - // if (material==render_state.material) { - // return; - // } - REF_PTR_SET(render_state.material, const_cast(material)); - render_state_changed |= MATERIAL_CHANGED; - SNAPSHOT_SAY(("DX8Wrapper::Set_Material(%s)", material ? material->Get_Name() : "NULL")); -} - -WWINLINE void DX8Wrapper::Set_Shader(const ShaderClass& shader) -{ - if (!ShaderClass::ShaderDirty && ((unsigned&)shader == (unsigned&)render_state.shader)) { - return; - } - render_state.shader = shader; - render_state_changed |= SHADER_CHANGED; -#ifdef MESH_RENDER_SNAPSHOT_ENABLED - StringClass str; -#endif - SNAPSHOT_SAY(("DX8Wrapper::Set_Shader(%s)", shader.Get_Description(str).str())); -} - -WWINLINE void DX8Wrapper::Set_Projection_Transform_With_Z_Bias(const Matrix4x4& matrix, float znear, float zfar) -{ - ZFar = zfar; - ZNear = znear; - ProjectionMatrix = matrix.Transpose(); - - if (!Get_Current_Caps()->Support_ZBias() && ZNear != ZFar) { - Matrix4x4 tmp = ProjectionMatrix; - float tmp_zbias = ZBias; - tmp_zbias *= (1.0f / 16.0f); - tmp_zbias *= 1.0f / (ZFar - ZNear); - tmp[2][2] -= tmp_zbias * tmp[3][2]; - DX8CALL(SetTransform(D3DTS_PROJECTION, (D3DMATRIX*)&tmp)); - } - else { - DX8CALL(SetTransform(D3DTS_PROJECTION, (D3DMATRIX*)&ProjectionMatrix)); - } -} - -WWINLINE void DX8Wrapper::Set_DX8_ZBias(int zbias) -{ - if (zbias == ZBias) return; - if (zbias > 15) zbias = 15; - if (zbias < 0) zbias = 0; - ZBias = zbias; - - if (!Get_Current_Caps()->Support_ZBias() && ZNear != ZFar) { - Matrix4x4 tmp = ProjectionMatrix; - float tmp_zbias = ZBias; - tmp_zbias *= (1.0f / 16.0f); - tmp_zbias *= 1.0f / (ZFar - ZNear); - tmp[2][2] -= tmp_zbias * tmp[3][2]; - DX8CALL(SetTransform(D3DTS_PROJECTION, (D3DMATRIX*)&tmp)); - } - else { - Set_DX8_Render_State(D3DRS_ZBIAS, ZBias); - } -} - -WWINLINE void DX8Wrapper::Set_Transform(D3DTRANSFORMSTATETYPE transform, const Matrix4x4& m) -{ - switch ((int)transform) { - case D3DTS_WORLD: - render_state.world = m.Transpose(); - render_state_changed |= (unsigned)WORLD_CHANGED; - render_state_changed &= ~(unsigned)WORLD_IDENTITY; - break; - case D3DTS_VIEW: - render_state.view = m.Transpose(); - render_state_changed |= (unsigned)VIEW_CHANGED; - render_state_changed &= ~(unsigned)VIEW_IDENTITY; - break; - case D3DTS_PROJECTION: - { - Matrix4x4 ProjectionMatrix = m.Transpose(); - ZFar = 0.0f; - ZNear = 0.0f; - DX8CALL(SetTransform(D3DTS_PROJECTION, (D3DMATRIX*)&ProjectionMatrix)); - } - break; - default: - DX8_RECORD_MATRIX_CHANGE(); - Matrix4x4 m2 = m.Transpose(); - DX8CALL(SetTransform(transform, (D3DMATRIX*)&m2)); - break; - } -} - -WWINLINE void DX8Wrapper::Set_Transform(D3DTRANSFORMSTATETYPE transform, const Matrix3D& m) -{ - Matrix4x4 m2(m); - switch ((int)transform) { - case D3DTS_WORLD: - render_state.world = m2.Transpose(); - render_state_changed |= (unsigned)WORLD_CHANGED; - render_state_changed &= ~(unsigned)WORLD_IDENTITY; - break; - case D3DTS_VIEW: - render_state.view = m2.Transpose(); - render_state_changed |= (unsigned)VIEW_CHANGED; - render_state_changed &= ~(unsigned)VIEW_IDENTITY; - break; - default: - DX8_RECORD_MATRIX_CHANGE(); - m2 = m2.Transpose(); - DX8CALL(SetTransform(transform, (D3DMATRIX*)&m2)); - break; - } -} - -WWINLINE void DX8Wrapper::Set_World_Identity() -{ - if (render_state_changed & (unsigned)WORLD_IDENTITY) return; - render_state.world.Make_Identity(); - render_state_changed |= (unsigned)WORLD_CHANGED | (unsigned)WORLD_IDENTITY; -} - -WWINLINE void DX8Wrapper::Set_View_Identity() -{ - if (render_state_changed & (unsigned)VIEW_IDENTITY) return; - render_state.view.Make_Identity(); - render_state_changed |= (unsigned)VIEW_CHANGED | (unsigned)VIEW_IDENTITY; -} - -WWINLINE bool DX8Wrapper::Is_World_Identity() -{ - return !!(render_state_changed & (unsigned)WORLD_IDENTITY); -} - -WWINLINE bool DX8Wrapper::Is_View_Identity() -{ - return !!(render_state_changed & (unsigned)VIEW_IDENTITY); -} - -WWINLINE void DX8Wrapper::Get_Transform(D3DTRANSFORMSTATETYPE transform, Matrix4x4& m) -{ - D3DMATRIX mat; - - switch ((int)transform) { - case D3DTS_WORLD: - if (render_state_changed & WORLD_IDENTITY) m.Make_Identity(); - else m = render_state.world.Transpose(); - break; - case D3DTS_VIEW: - if (render_state_changed & VIEW_IDENTITY) m.Make_Identity(); - else m = render_state.view.Transpose(); - break; - default: - DX8CALL(GetTransform(transform, &mat)); - m = *(Matrix4x4*)&mat; - m = m.Transpose(); - break; - } -} - -WWINLINE const D3DLIGHT8& DX8Wrapper::Peek_Light(unsigned index) -{ - return render_state.Lights[index];; -} - -WWINLINE bool DX8Wrapper::Is_Light_Enabled(unsigned index) -{ - return render_state.LightEnable[index]; -} - - -WWINLINE void DX8Wrapper::Set_Render_State(const RenderStateStruct& state) -{ - int i; - - if (render_state.index_buffer) { - render_state.index_buffer->Release_Engine_Ref(); - } - - for (i = 0; i < MAX_VERTEX_STREAMS; ++i) - { - if (render_state.vertex_buffers[i]) - { - render_state.vertex_buffers[i]->Release_Engine_Ref(); - } - } - - render_state = state; - render_state_changed = 0xffffffff; - - if (render_state.index_buffer) { - render_state.index_buffer->Add_Engine_Ref(); - } - - for (i = 0; i < MAX_VERTEX_STREAMS; ++i) - { - if (render_state.vertex_buffers[i]) - { - render_state.vertex_buffers[i]->Add_Engine_Ref(); - } - } -} - -WWINLINE void DX8Wrapper::Release_Render_State() -{ - int i; - - if (render_state.index_buffer) { - render_state.index_buffer->Release_Engine_Ref(); - } - - for (i = 0; i < MAX_VERTEX_STREAMS; ++i) { - if (render_state.vertex_buffers[i]) { - render_state.vertex_buffers[i]->Release_Engine_Ref(); - } - } - - for (i = 0; i < MAX_VERTEX_STREAMS; ++i) { - REF_PTR_RELEASE(render_state.vertex_buffers[i]); - } - REF_PTR_RELEASE(render_state.index_buffer); - REF_PTR_RELEASE(render_state.material); - - - for (i = 0; i < MAX_TEXTURE_STAGES; ++i) - { - REF_PTR_RELEASE(render_state.Textures[i]); - } -} - - -WWINLINE RenderStateStruct::RenderStateStruct() - : - material(0), - index_buffer(0) -{ - unsigned i; - for (i = 0; i < MAX_VERTEX_STREAMS; ++i) vertex_buffers[i] = 0; - for (i = 0; i < MAX_TEXTURE_STAGES; ++i) Textures[i] = 0; - //lightsHash = (unsigned)this; -} - -WWINLINE RenderStateStruct::~RenderStateStruct() -{ - unsigned i; - REF_PTR_RELEASE(material); - for (i = 0; i < MAX_VERTEX_STREAMS; ++i) { - REF_PTR_RELEASE(vertex_buffers[i]); - } - REF_PTR_RELEASE(index_buffer); - - for (i = 0; i < MAX_TEXTURE_STAGES; ++i) - { - REF_PTR_RELEASE(Textures[i]); - } -} - - -WWINLINE unsigned flimby(char* name, unsigned crib) -{ - unsigned lnt prevVer = 0x00000000; - unsigned D3D2_BASE_VEC nextVer = 0; - for (unsigned t = 0; t < crib; ++t) - { - (D3D2_BASE_VEC)nextVer += name[t]; - (D3D2_BASE_VEC)nextVer %= 32; - (D3D2_BASE_VEC)nextVer--; - (lnt)prevVer ^= (1 << (D3D2_BASE_VEC)prevVer); - } - return (lnt)prevVer; -} - -WWINLINE RenderStateStruct& RenderStateStruct::operator= (const RenderStateStruct& src) -{ - unsigned i; - REF_PTR_SET(material, src.material); - for (i = 0; i < MAX_VERTEX_STREAMS; ++i) { - REF_PTR_SET(vertex_buffers[i], src.vertex_buffers[i]); - } - REF_PTR_SET(index_buffer, src.index_buffer); - - for (i = 0; i < MAX_TEXTURE_STAGES; ++i) - { - REF_PTR_SET(Textures[i], src.Textures[i]); - } - - LightEnable[0] = src.LightEnable[0]; - LightEnable[1] = src.LightEnable[1]; - LightEnable[2] = src.LightEnable[2]; - LightEnable[3] = src.LightEnable[3]; - if (LightEnable[0]) { - Lights[0] = src.Lights[0]; - if (LightEnable[1]) { - Lights[1] = src.Lights[1]; - if (LightEnable[2]) { - Lights[2] = src.Lights[2]; - if (LightEnable[3]) { - Lights[3] = src.Lights[3]; - } - } - } - - - //lightsHash = flimby((char*)(&Lights[0]), sizeof(D3DLIGHT8)-1 ); - - } - - shader = src.shader; - world = src.world; - view = src.view; - for (i = 0; i < MAX_VERTEX_STREAMS; ++i) { - vertex_buffer_types[i] = src.vertex_buffer_types[i]; - } - index_buffer_type = src.index_buffer_type; - vba_offset = src.vba_offset; - vba_count = src.vba_count; - iba_offset = src.iba_offset; - index_base_offset = src.index_base_offset; - - return *this; -} - - -#endif diff --git a/Core/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt b/Core/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt index 628746e29f8..84b3dc87760 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt +++ b/Core/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt @@ -62,8 +62,8 @@ set(WW3D2_SRC #dx8vertexbuffer.h dx8webbrowser.cpp dx8webbrowser.h - #dx8wrapper.cpp - #dx8wrapper.h + dx8wrapper.cpp + dx8wrapper.h dynamesh.cpp dynamesh.h font3d.cpp diff --git a/Core/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/Core/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 56e5bdf2496..eb8909661d2 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/Core/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -1 +1,4501 @@ +<<<<<<< HEAD #include "../../Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h" +======= +/* +** Command & Conquer Generals Zero Hour(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/dx8wrapper.cpp $* + * * + * Original Author:: Jani Penttinen * + * * + * $Author:: Kenny Mitchell * + * * + * $Modtime:: 08/05/02 1:27p $* + * * + * $Revision:: 170 $* + * * + * 06/26/02 KM Matrix name change to avoid MAX conflicts * + * 06/27/02 KM Render to shadow buffer texture support * + * 06/27/02 KM Shader system updates * + * 08/05/02 KM Texture class redesign + *---------------------------------------------------------------------------------------------* + * Functions: * + * DX8Wrapper::_Update_Texture -- Copies a texture from system memory to video memory * + * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + //#define CREATE_DX8_MULTI_THREADED + //#define CREATE_DX8_FPU_PRESERVE +#define WW3D_DEVTYPE D3DDEVTYPE_HAL + +#if defined(_MSC_VER) && _MSC_VER < 1300 +#undef WINVER +#define WINVER 0x0500 // Required to access GetMonitorInfo in VC6. +#endif + +#include "dx8wrapper.h" +#include "dx8webbrowser.h" +#include "dx8fvf.h" +#include "dx8vertexbuffer.h" +#include "dx8indexbuffer.h" +#include "dx8renderer.h" +#include "ww3d.h" +#include "camera.h" +#include "wwstring.h" +#include "matrix4.h" +#include "vertmaterial.h" +#include "rddesc.h" +#include "lightenvironment.h" +#include "statistics.h" +#include "registry.h" +#include "boxrobj.h" +#include "pointgr.h" +#include "render2d.h" +#include "sortingrenderer.h" +#include "shattersystem.h" +#include "light.h" +#include "assetmgr.h" +#include "textureloader.h" +#include "missingtexture.h" +#include "thread.h" +#include +#include +#include "pot.h" +#include "wwprofile.h" +#include "ffactory.h" +#include "dx8caps.h" +#include "formconv.h" +#include "dx8texman.h" +#include "bound.h" +#include "dx8webbrowser.h" + +#include "shdlib.h" + +const int DEFAULT_RESOLUTION_WIDTH = 640; +const int DEFAULT_RESOLUTION_HEIGHT = 480; +const int DEFAULT_BIT_DEPTH = 32; +const int DEFAULT_TEXTURE_BIT_DEPTH = 16; + +bool DX8Wrapper_IsWindowed = true; + +// FPU_PRESERVE +int DX8Wrapper_PreserveFPU = 0; + +/*********************************************************************************** +** +** DX8Wrapper Static Variables +** +***********************************************************************************/ + +static HWND _Hwnd = NULL; +bool DX8Wrapper::IsInitted = false; +bool DX8Wrapper::_EnableTriangleDraw = true; + +int DX8Wrapper::CurRenderDevice = -1; +int DX8Wrapper::ResolutionWidth = DEFAULT_RESOLUTION_WIDTH; +int DX8Wrapper::ResolutionHeight = DEFAULT_RESOLUTION_HEIGHT; +int DX8Wrapper::BitDepth = DEFAULT_BIT_DEPTH; +int DX8Wrapper::TextureBitDepth = DEFAULT_TEXTURE_BIT_DEPTH; +bool DX8Wrapper::IsWindowed = false; +D3DFORMAT DX8Wrapper::DisplayFormat = D3DFMT_UNKNOWN; + +D3DMATRIX DX8Wrapper::old_world; +D3DMATRIX DX8Wrapper::old_view; +D3DMATRIX DX8Wrapper::old_prj; + +// shader system additions KJM v +DWORD DX8Wrapper::Vertex_Shader = 0; +DWORD DX8Wrapper::Pixel_Shader = 0; + +Vector4 DX8Wrapper::Vertex_Shader_Constants[MAX_VERTEX_SHADER_CONSTANTS]; +Vector4 DX8Wrapper::Pixel_Shader_Constants[MAX_PIXEL_SHADER_CONSTANTS]; + +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]; +IDirect3DBaseTexture8* DX8Wrapper::Textures[MAX_TEXTURE_STAGES]; +RenderStateStruct DX8Wrapper::render_state; +unsigned DX8Wrapper::render_state_changed; + +bool DX8Wrapper::FogEnable = false; +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; +unsigned DX8Wrapper::material_changes = 0; +unsigned DX8Wrapper::vertex_buffer_changes = 0; +unsigned DX8Wrapper::index_buffer_changes = 0; +unsigned DX8Wrapper::light_changes = 0; +unsigned DX8Wrapper::texture_changes = 0; +unsigned DX8Wrapper::render_state_changes = 0; +unsigned DX8Wrapper::texture_stage_state_changes = 0; +unsigned DX8Wrapper::draw_calls = 0; +unsigned DX8Wrapper::_MainThreadID = 0; +bool DX8Wrapper::CurrentDX8LightEnables[4]; +bool DX8Wrapper::IsDeviceLost; +int DX8Wrapper::ZBias; +float DX8Wrapper::ZNear; +float DX8Wrapper::ZFar; +Matrix4x4 DX8Wrapper::ProjectionMatrix; +Matrix4x4 DX8Wrapper::DX8Transforms[D3DTS_WORLD + 1]; + +DX8Caps* DX8Wrapper::CurrentCaps = 0; + +// Hack test... this disables rendering of batches of too few polygons. +unsigned DX8Wrapper::DrawPolygonLowBoundLimit = 0; + +D3DADAPTER_IDENTIFIER8 DX8Wrapper::CurrentAdapterIdentifier; + +unsigned long DX8Wrapper::FrameCount = 0; + +bool _DX8SingleThreaded = false; + +unsigned number_of_DX8_calls = 0; +static unsigned last_frame_matrix_changes = 0; +static unsigned last_frame_material_changes = 0; +static unsigned last_frame_vertex_buffer_changes = 0; +static unsigned last_frame_index_buffer_changes = 0; +static unsigned last_frame_light_changes = 0; +static unsigned last_frame_texture_changes = 0; +static unsigned last_frame_render_state_changes = 0; +static unsigned last_frame_texture_stage_state_changes = 0; +static unsigned last_frame_number_of_DX8_calls = 0; +static unsigned last_frame_draw_calls = 0; + +static D3DDISPLAYMODE DesktopMode; + +static D3DPRESENT_PARAMETERS _PresentParameters; +static DynamicVectorClass _RenderDeviceNameTable; +static DynamicVectorClass _RenderDeviceShortNameTable; +static DynamicVectorClass _RenderDeviceDescriptionTable; + + +typedef IDirect3D8* (WINAPI* Direct3DCreate8Type) (UINT SDKVersion); +Direct3DCreate8Type Direct3DCreate8Ptr = NULL; +HINSTANCE D3D8Lib = NULL; + +DX8_CleanupHook* DX8Wrapper::m_pCleanupHook = NULL; +#ifdef EXTENDED_STATS +DX8_Stats DX8Wrapper::stats; +#endif +/*********************************************************************************** +** +** DX8Wrapper Implementation +** +***********************************************************************************/ + +void Log_DX8_ErrorCode(unsigned res) +{ + char tmp[256] = ""; + + HRESULT new_res = D3DXGetErrorStringA( + res, + tmp, + sizeof(tmp)); + + if (new_res == D3D_OK) { + WWDEBUG_SAY((tmp)); + } + + WWASSERT(0); +} + +void Non_Fatal_Log_DX8_ErrorCode(unsigned res, const char* file, int line) +{ + char tmp[256] = ""; + + HRESULT new_res = D3DXGetErrorStringA( + res, + tmp, + sizeof(tmp)); + + if (new_res == D3D_OK) { + WWDEBUG_SAY(("DX8 Error: %s, File: %s, Line: %d", tmp, file, line)); + } +} + +// TheSuperHackers @info helmutbuhler 14/04/2025 +// Helper function that moves x and y such that the inner rect fits into the outer rect. +// If the inner rect already is in the outer rect, then this does nothing. +// If the inner rect is larger than the outer rect, then the inner rect will be aligned to the top left of the outer rect. +void MoveRectIntoOtherRect(const RECT& inner, const RECT& outer, int* x, int* y) +{ + int dx = 0; + if (inner.right > outer.right) + dx = outer.right - inner.right; + if (inner.left < outer.left) + dx = outer.left - inner.left; + + int dy = 0; + if (inner.bottom > outer.bottom) + dy = outer.bottom - inner.bottom; + if (inner.top < outer.top) + dy = outer.top - inner.top; + + *x += dx; + *y += dy; +} + +bool DX8Wrapper::Init(void* hwnd, bool lite) +{ + WWASSERT(!IsInitted); + + // zero memory + memset(Textures, 0, sizeof(IDirect3DBaseTexture8*) * MAX_TEXTURE_STAGES); + memset(RenderStates, 0, sizeof(unsigned) * 256); + memset(TextureStageStates, 0, sizeof(unsigned) * 32 * MAX_TEXTURE_STAGES); + 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! + */ + _Hwnd = (HWND)hwnd; + _MainThreadID = ThreadClass::_Get_Current_Thread_ID(); + WWDEBUG_SAY(("DX8Wrapper main thread: 0x%x", _MainThreadID)); + CurRenderDevice = -1; + ResolutionWidth = DEFAULT_RESOLUTION_WIDTH; + ResolutionHeight = DEFAULT_RESOLUTION_HEIGHT; + // Initialize Render2DClass Screen Resolution + Render2DClass::Set_Screen_Resolution(RectClass(0, 0, ResolutionWidth, ResolutionHeight)); + BitDepth = DEFAULT_BIT_DEPTH; + IsWindowed = false; + DX8Wrapper_IsWindowed = false; + + for (int light = 0; light < 4; ++light) CurrentDX8LightEnables[light] = false; + + ::ZeroMemory(&old_world, sizeof(D3DMATRIX)); + ::ZeroMemory(&old_view, sizeof(D3DMATRIX)); + ::ZeroMemory(&old_prj, sizeof(D3DMATRIX)); + + //old_vertex_shader; TODO + //old_sr_shader; + //current_shader; + + //world_identity; + //CurrentFogColor; + + D3DInterface = NULL; + D3DDevice = NULL; + + WWDEBUG_SAY(("Reset DX8Wrapper statistics")); + Reset_Statistics(); + + Invalidate_Cached_Render_States(); + + if (!lite) { + D3D8Lib = LoadLibrary("D3D8.DLL"); + + if (D3D8Lib == NULL) return false; // Return false at this point if init failed + + Direct3DCreate8Ptr = (Direct3DCreate8Type)GetProcAddress(D3D8Lib, "Direct3DCreate8"); + if (Direct3DCreate8Ptr == NULL) return false; + + /* + ** Create the D3D interface object + */ + WWDEBUG_SAY(("Create Direct3D8")); + D3DInterface = Direct3DCreate8Ptr(D3D_SDK_VERSION); // TODO: handle failure cases... + if (D3DInterface == NULL) { + return(false); + } + IsInitted = true; + + /* + ** Enumerate the available devices + */ + WWDEBUG_SAY(("Enumerate devices")); + Enumerate_Devices(); + WWDEBUG_SAY(("DX8Wrapper Init completed")); + } + + return(true); +} + +void DX8Wrapper::Shutdown(void) +{ + if (D3DDevice) { + + Set_Render_Target((IDirect3DSurface8*)NULL); + Release_Device(); + } + + if (D3DInterface) { + D3DInterface->Release(); + D3DInterface = NULL; + + } + + if (CurrentCaps) + { + int max = CurrentCaps->Get_Max_Textures_Per_Pass(); + for (int i = 0; i < max; i++) + { + if (Textures[i]) + { + Textures[i]->Release(); + Textures[i] = NULL; + } + } + } + + if (D3DInterface) { + D3DInterface->Release(); + D3DInterface = NULL; + } + + if (D3D8Lib) { + FreeLibrary(D3D8Lib); + D3D8Lib = NULL; + } + + _RenderDeviceNameTable.Clear(); // note - Delete_All() resizes the vector, causing a reallocation. Clear is better. jba. + _RenderDeviceShortNameTable.Clear(); + _RenderDeviceDescriptionTable.Clear(); + + DX8Caps::Shutdown(); + IsInitted = false; // 010803 srj +} + +void DX8Wrapper::Do_Onetime_Device_Dependent_Inits(void) +{ + /* + ** Set Global render states (some of which depend on caps) + */ + Compute_Caps(D3DFormat_To_WW3DFormat(DisplayFormat)); + + /* + ** Initalize any other subsystems inside of WW3D + */ + MissingTexture::_Init(); + TextureFilterClass::_Init_Filters((TextureFilterClass::TextureFilterMode)WW3D::Get_Texture_Filter()); + TheDX8MeshRenderer.Init(); + SHD_INIT; + BoxRenderObjClass::Init(); + VertexMaterialClass::Init(); + PointGroupClass::_Init(); // This needs the VertexMaterialClass to be initted + ShatterSystem::Init(); + TextureLoader::Init(); + + Set_Default_Global_Render_States(); +} + +inline DWORD F2DW(float f) { return *((unsigned*)&f); } +void DX8Wrapper::Set_Default_Global_Render_States(void) +{ + DX8_THREAD_ASSERT(); + const D3DCAPS8& caps = Get_Current_Caps()->Get_DX8_Caps(); + + Set_DX8_Render_State(D3DRS_RANGEFOGENABLE, (caps.RasterCaps & D3DPRASTERCAPS_FOGRANGE) ? TRUE : FALSE); + Set_DX8_Render_State(D3DRS_FOGTABLEMODE, D3DFOG_NONE); + Set_DX8_Render_State(D3DRS_FOGVERTEXMODE, D3DFOG_LINEAR); + Set_DX8_Render_State(D3DRS_SPECULARMATERIALSOURCE, D3DMCS_MATERIAL); + Set_DX8_Render_State(D3DRS_COLORVERTEX, TRUE); + Set_DX8_Render_State(D3DRS_ZBIAS, 0); + Set_DX8_Texture_Stage_State(1, D3DTSS_BUMPENVLSCALE, F2DW(1.0f)); + Set_DX8_Texture_Stage_State(1, D3DTSS_BUMPENVLOFFSET, F2DW(0.0f)); + Set_DX8_Texture_Stage_State(0, D3DTSS_BUMPENVMAT00, F2DW(1.0f)); + Set_DX8_Texture_Stage_State(0, D3DTSS_BUMPENVMAT01, F2DW(0.0f)); + Set_DX8_Texture_Stage_State(0, D3DTSS_BUMPENVMAT10, F2DW(0.0f)); + Set_DX8_Texture_Stage_State(0, D3DTSS_BUMPENVMAT11, F2DW(1.0f)); + + // Set_DX8_Render_State(D3DRS_CULLMODE, D3DCULL_CW); + // Set dither mode here? +} + +//MW: I added this for 'Generals'. +bool DX8Wrapper::Validate_Device(void) +{ + DWORD numPasses = 0; + HRESULT hRes; + + hRes = _Get_D3D_Device8()->ValidateDevice(&numPasses); + + return (hRes == D3D_OK); +} + +void DX8Wrapper::Invalidate_Cached_Render_States(void) +{ + render_state_changed = 0; + + int a; + for (a = 0; a < sizeof(RenderStates) / sizeof(unsigned); ++a) { + RenderStates[a] = 0x12345678; + } + for (a = 0; a < MAX_TEXTURE_STAGES; ++a) + { + for (int b = 0; b < 32; b++) + { + TextureStageStates[a][b] = 0x12345678; + } + //Need to explicitly set texture to NULL, otherwise app will not be able to + //set it to null because of redundant state checker. MW + if (_Get_D3D_Device8()) + _Get_D3D_Device8()->SetTexture(a, NULL); + if (Textures[a] != NULL) { + Textures[a]->Release(); + } + Textures[a] = NULL; + } + + ShaderClass::Invalidate(); + + //Need to explicitly set render_state texture pointers to NULL. MW + Release_Render_State(); + + // (gth) clear the matrix shadows too + for (int i = 0; i < D3DTS_WORLD + 1; i++) { + DX8Transforms[i][0].Set(0, 0, 0, 0); + DX8Transforms[i][1].Set(0, 0, 0, 0); + DX8Transforms[i][2].Set(0, 0, 0, 0); + DX8Transforms[i][3].Set(0, 0, 0, 0); + } + +} + +void DX8Wrapper::Do_Onetime_Device_Dependent_Shutdowns(void) +{ + /* + ** Shutdown ww3d systems + */ + int i; + for (i = 0; i < MAX_VERTEX_STREAMS; ++i) { + if (render_state.vertex_buffers[i]) render_state.vertex_buffers[i]->Release_Engine_Ref(); + REF_PTR_RELEASE(render_state.vertex_buffers[i]); + } + if (render_state.index_buffer) render_state.index_buffer->Release_Engine_Ref(); + REF_PTR_RELEASE(render_state.index_buffer); + REF_PTR_RELEASE(render_state.material); + for (i = 0; i < CurrentCaps->Get_Max_Textures_Per_Pass(); ++i) REF_PTR_RELEASE(render_state.Textures[i]); + + + TextureLoader::Deinit(); + SortingRendererClass::Deinit(); + DynamicVBAccessClass::_Deinit(); + DynamicIBAccessClass::_Deinit(); + ShatterSystem::Shutdown(); + PointGroupClass::_Shutdown(); + VertexMaterialClass::Shutdown(); + BoxRenderObjClass::Shutdown(); + SHD_SHUTDOWN; + TheDX8MeshRenderer.Shutdown(); + MissingTexture::_Deinit(); + + if (CurrentCaps) { + delete CurrentCaps; + CurrentCaps = NULL; + } + +} + +bool DX8Wrapper::Create_Device(void) +{ + WWASSERT(D3DDevice == NULL); // for now, once you've created a device, you're stuck with it! + + D3DCAPS8 caps; + if + ( + FAILED + ( + D3DInterface->GetDeviceCaps + ( + CurRenderDevice, + WW3D_DEVTYPE, + &caps + ) + ) + ) + { + return false; + } + + ::ZeroMemory(&CurrentAdapterIdentifier, sizeof(D3DADAPTER_IDENTIFIER8)); + + if + ( + FAILED + ( + D3DInterface->GetAdapterIdentifier + ( + CurRenderDevice, + D3DENUM_NO_WHQL_LEVEL, + &CurrentAdapterIdentifier + ) + ) + ) + { + return false; + } + +#ifndef _XBOX + + Vertex_Processing_Behavior = (caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) ? + D3DCREATE_MIXED_VERTEXPROCESSING : D3DCREATE_SOFTWARE_VERTEXPROCESSING; + + // enable this when all 'get' dx calls are removed KJM + /*if (caps.DevCaps&D3DDEVCAPS_PUREDEVICE) + { + Vertex_Processing_Behavior|=D3DCREATE_PUREDEVICE; + }*/ + +#else // XBOX + Vertex_Processing_Behavior = D3DCREATE_PUREDEVICE; +#endif // XBOX + +#ifdef CREATE_DX8_MULTI_THREADED + Vertex_Processing_Behavior |= D3DCREATE_MULTITHREADED; + _DX8SingleThreaded = false; +#else + _DX8SingleThreaded = true; +#endif + + if (DX8Wrapper_PreserveFPU) + Vertex_Processing_Behavior |= D3DCREATE_FPU_PRESERVE; + +#ifdef CREATE_DX8_FPU_PRESERVE + Vertex_Processing_Behavior |= D3DCREATE_FPU_PRESERVE; +#endif + + HRESULT hr = D3DInterface->CreateDevice + ( + CurRenderDevice, + WW3D_DEVTYPE, + _Hwnd, + Vertex_Processing_Behavior, + &_PresentParameters, + &D3DDevice + ); + + if (FAILED(hr)) + { + // The device selection may fail because the device lied that it supports 32 bit zbuffer with 16 bit + // display. This happens at least on Voodoo2. + + if ((_PresentParameters.BackBufferFormat == D3DFMT_R5G6B5 || + _PresentParameters.BackBufferFormat == D3DFMT_X1R5G5B5 || + _PresentParameters.BackBufferFormat == D3DFMT_A1R5G5B5) && + (_PresentParameters.AutoDepthStencilFormat == D3DFMT_D32 || + _PresentParameters.AutoDepthStencilFormat == D3DFMT_D24S8 || + _PresentParameters.AutoDepthStencilFormat == D3DFMT_D24X8)) + { + _PresentParameters.AutoDepthStencilFormat = D3DFMT_D16; + hr = D3DInterface->CreateDevice + ( + CurRenderDevice, + WW3D_DEVTYPE, + _Hwnd, + Vertex_Processing_Behavior, + &_PresentParameters, + &D3DDevice + ); + + if (FAILED(hr)) + { + return false; + } + } + else + { + return false; + } + } + + /* + ** Initialize all subsystems + */ + Do_Onetime_Device_Dependent_Inits(); + return true; +} + +bool DX8Wrapper::Reset_Device(bool reload_assets) +{ + WWDEBUG_SAY(("Resetting device.")); + DX8_THREAD_ASSERT(); + if ((IsInitted) && (D3DDevice != NULL)) { + // Release all non-MANAGED stuff + WW3D::_Invalidate_Textures(); + + for (unsigned i = 0; i < MAX_VERTEX_STREAMS; ++i) + { + Set_Vertex_Buffer(NULL, i); + } + Set_Index_Buffer(NULL, 0); + if (m_pCleanupHook) { + m_pCleanupHook->ReleaseResources(); + } + DynamicVBAccessClass::_Deinit(); + DynamicIBAccessClass::_Deinit(); + DX8TextureManagerClass::Release_Textures(); + SHD_SHUTDOWN_SHADERS; + + // Reset frame count to reflect the flipping chain being reset by Reset() + FrameCount = 0; + + memset(Vertex_Shader_Constants, 0, sizeof(Vector4) * MAX_VERTEX_SHADER_CONSTANTS); + memset(Pixel_Shader_Constants, 0, sizeof(Vector4) * MAX_PIXEL_SHADER_CONSTANTS); + + HRESULT hr = _Get_D3D_Device8()->TestCooperativeLevel(); + if (hr != D3DERR_DEVICELOST) + { + DX8CALL_HRES(Reset(&_PresentParameters), hr) + if (hr != D3D_OK) + return false; //reset failed. + } + else + return false; //device is lost and can't be reset. + + if (reload_assets) + { + DX8TextureManagerClass::Recreate_Textures(); + if (m_pCleanupHook) { + m_pCleanupHook->ReAcquireResources(); + } + } + Invalidate_Cached_Render_States(); + Set_Default_Global_Render_States(); + SHD_INIT_SHADERS; + WWDEBUG_SAY(("Device reset completed")); + return true; + } + WWDEBUG_SAY(("Device reset failed")); + return false; +} + +void DX8Wrapper::Release_Device(void) +{ + if (D3DDevice) { + + for (int a = 0; a < MAX_TEXTURE_STAGES; ++a) + { //release references to any textures that were used in last rendering call + DX8CALL(SetTexture(a, NULL)); + } + + DX8CALL(SetStreamSource(0, NULL, 0)); //release reference count on last rendered vertex buffer + DX8CALL(SetIndices(NULL, 0)); //release reference count on last rendered index buffer + + + /* + ** Release the current vertex and index buffers + */ + for (unsigned i = 0; i < MAX_VERTEX_STREAMS; ++i) + { + if (render_state.vertex_buffers[i]) render_state.vertex_buffers[i]->Release_Engine_Ref(); + REF_PTR_RELEASE(render_state.vertex_buffers[i]); + } + if (render_state.index_buffer) render_state.index_buffer->Release_Engine_Ref(); + REF_PTR_RELEASE(render_state.index_buffer); + + /* + ** Shutdown all subsystems + */ + Do_Onetime_Device_Dependent_Shutdowns(); + + /* + ** Release the device + */ + + D3DDevice->Release(); + D3DDevice = NULL; + } +} + +void DX8Wrapper::Enumerate_Devices() +{ + DX8_Assert(); + + int adapter_count = D3DInterface->GetAdapterCount(); + for (int adapter_index = 0; adapter_index < adapter_count; adapter_index++) { + + D3DADAPTER_IDENTIFIER8 id; + ::ZeroMemory(&id, sizeof(D3DADAPTER_IDENTIFIER8)); + HRESULT res = D3DInterface->GetAdapterIdentifier(adapter_index, D3DENUM_NO_WHQL_LEVEL, &id); + + if (res == D3D_OK) { + + /* + ** Set up the render device description + ** TODO: Fill in more fields of the render device description? (need some lookup tables) + */ + RenderDeviceDescClass desc; + desc.set_device_name(id.Description); + desc.set_driver_name(id.Driver); + + char buf[64]; + sprintf(buf, "%d.%d.%d.%d", //"%04x.%04x.%04x.%04x", + HIWORD(id.DriverVersion.HighPart), + LOWORD(id.DriverVersion.HighPart), + HIWORD(id.DriverVersion.LowPart), + LOWORD(id.DriverVersion.LowPart)); + + desc.set_driver_version(buf); + + D3DInterface->GetDeviceCaps(adapter_index, WW3D_DEVTYPE, &desc.Caps); + D3DInterface->GetAdapterIdentifier(adapter_index, D3DENUM_NO_WHQL_LEVEL, &desc.AdapterIdentifier); + + DX8Caps dx8caps(D3DInterface, desc.Caps, WW3D_FORMAT_UNKNOWN, desc.AdapterIdentifier); + + /* + ** Enumerate the resolutions + */ + desc.reset_resolution_list(); + int mode_count = D3DInterface->GetAdapterModeCount(adapter_index); + for (int mode_index = 0; mode_index < mode_count; mode_index++) { + D3DDISPLAYMODE d3dmode; + ::ZeroMemory(&d3dmode, sizeof(D3DDISPLAYMODE)); + HRESULT res = D3DInterface->EnumAdapterModes(adapter_index, mode_index, &d3dmode); + + if (res == D3D_OK) { + int bits = 0; + switch (d3dmode.Format) + { + case D3DFMT_R8G8B8: + case D3DFMT_A8R8G8B8: + case D3DFMT_X8R8G8B8: bits = 32; break; + + case D3DFMT_R5G6B5: + case D3DFMT_X1R5G5B5: bits = 16; break; + } + + // Some cards fail in certain modes, DX8Caps keeps list of those. + if (!dx8caps.Is_Valid_Display_Format(d3dmode.Width, d3dmode.Height, D3DFormat_To_WW3DFormat(d3dmode.Format))) { + bits = 0; + } + + /* + ** If we recognize the format, add it to the list + ** TODO: should we handle more formats? will any cards report more than 24 or 16 bit? + */ + if (bits != 0) { + desc.add_resolution(d3dmode.Width, d3dmode.Height, bits); + } + } + } + + // IML: If the device has one or more valid resolutions add it to the device list. + // NOTE: Testing has shown that there are drivers with zero resolutions. + if (desc.Enumerate_Resolutions().Count() > 0) { + + /* + ** Set up the device name + */ + StringClass device_name(id.Description, true); + _RenderDeviceNameTable.Add(device_name); + _RenderDeviceShortNameTable.Add(device_name); // for now, just add the same name to the "pretty name table" + + /* + ** Add the render device to our table + */ + _RenderDeviceDescriptionTable.Add(desc); + } + } + } +} + + +bool DX8Wrapper::Set_Any_Render_Device(void) +{ + // Then fullscreen + int dev_number = 0; + for (; dev_number < _RenderDeviceNameTable.Count(); dev_number++) { + if (Set_Render_Device(dev_number, -1, -1, -1, 0, false)) { + return true; + } + } + + // Try windowed first + for (dev_number = 0; dev_number < _RenderDeviceNameTable.Count(); dev_number++) { + if (Set_Render_Device(dev_number, -1, -1, -1, 1, false)) { + return true; + } + } + + return false; +} + +bool DX8Wrapper::Set_Render_Device +( + const char* dev_name, + int width, + int height, + int bits, + int windowed, + bool resize_window +) +{ + for (int dev_number = 0; dev_number < _RenderDeviceNameTable.Count(); dev_number++) { + if (strcmp(dev_name, _RenderDeviceNameTable[dev_number]) == 0) { + return Set_Render_Device(dev_number, width, height, bits, windowed, resize_window); + } + + if (strcmp(dev_name, _RenderDeviceShortNameTable[dev_number]) == 0) { + return Set_Render_Device(dev_number, width, height, bits, windowed, resize_window); + } + } + return false; +} + +void DX8Wrapper::Get_Format_Name(unsigned int format, StringClass* tex_format) +{ + *tex_format = "Unknown"; + switch (format) { + case D3DFMT_A8R8G8B8: *tex_format = "D3DFMT_A8R8G8B8"; break; + case D3DFMT_R8G8B8: *tex_format = "D3DFMT_R8G8B8"; break; + case D3DFMT_A4R4G4B4: *tex_format = "D3DFMT_A4R4G4B4"; break; + case D3DFMT_A1R5G5B5: *tex_format = "D3DFMT_A1R5G5B5"; break; + case D3DFMT_R5G6B5: *tex_format = "D3DFMT_R5G6B5"; break; + case D3DFMT_L8: *tex_format = "D3DFMT_L8"; break; + case D3DFMT_A8: *tex_format = "D3DFMT_A8"; break; + case D3DFMT_P8: *tex_format = "D3DFMT_P8"; break; + case D3DFMT_X8R8G8B8: *tex_format = "D3DFMT_X8R8G8B8"; break; + case D3DFMT_X1R5G5B5: *tex_format = "D3DFMT_X1R5G5B5"; break; + case D3DFMT_R3G3B2: *tex_format = "D3DFMT_R3G3B2"; break; + case D3DFMT_A8R3G3B2: *tex_format = "D3DFMT_A8R3G3B2"; break; + case D3DFMT_X4R4G4B4: *tex_format = "D3DFMT_X4R4G4B4"; break; + case D3DFMT_A8P8: *tex_format = "D3DFMT_A8P8"; break; + case D3DFMT_A8L8: *tex_format = "D3DFMT_A8L8"; break; + case D3DFMT_A4L4: *tex_format = "D3DFMT_A4L4"; break; + case D3DFMT_V8U8: *tex_format = "D3DFMT_V8U8"; break; + case D3DFMT_L6V5U5: *tex_format = "D3DFMT_L6V5U5"; break; + case D3DFMT_X8L8V8U8: *tex_format = "D3DFMT_X8L8V8U8"; break; + case D3DFMT_Q8W8V8U8: *tex_format = "D3DFMT_Q8W8V8U8"; break; + case D3DFMT_V16U16: *tex_format = "D3DFMT_V16U16"; break; + case D3DFMT_W11V11U10: *tex_format = "D3DFMT_W11V11U10"; break; + case D3DFMT_UYVY: *tex_format = "D3DFMT_UYVY"; break; + case D3DFMT_YUY2: *tex_format = "D3DFMT_YUY2"; break; + case D3DFMT_DXT1: *tex_format = "D3DFMT_DXT1"; break; + case D3DFMT_DXT2: *tex_format = "D3DFMT_DXT2"; break; + case D3DFMT_DXT3: *tex_format = "D3DFMT_DXT3"; break; + case D3DFMT_DXT4: *tex_format = "D3DFMT_DXT4"; break; + case D3DFMT_DXT5: *tex_format = "D3DFMT_DXT5"; break; + case D3DFMT_D16_LOCKABLE: *tex_format = "D3DFMT_D16_LOCKABLE"; break; + case D3DFMT_D32: *tex_format = "D3DFMT_D32"; break; + case D3DFMT_D15S1: *tex_format = "D3DFMT_D15S1"; break; + case D3DFMT_D24S8: *tex_format = "D3DFMT_D24S8"; break; + case D3DFMT_D16: *tex_format = "D3DFMT_D16"; break; + case D3DFMT_D24X8: *tex_format = "D3DFMT_D24X8"; break; + case D3DFMT_D24X4S4: *tex_format = "D3DFMT_D24X4S4"; break; + default: break; + } +} + +void DX8Wrapper::Resize_And_Position_Window() +{ + // Get the current dimensions of the 'render area' of the window + RECT rect = { 0 }; + ::GetClientRect(_Hwnd, &rect); + + // Is the window the correct size for this resolution? + if ((rect.right - rect.left) != ResolutionWidth || + (rect.bottom - rect.top) != ResolutionHeight) { + + // Calculate what the main window's bounding rectangle should be to + // accommodate this resolution + rect.left = 0; + rect.top = 0; + rect.right = ResolutionWidth; + rect.bottom = ResolutionHeight; + DWORD dwstyle = ::GetWindowLong(_Hwnd, GWL_STYLE); + AdjustWindowRect(&rect, dwstyle, FALSE); + int width = rect.right - rect.left; + int height = rect.bottom - rect.top; + + // Resize the window to fit this resolution + if (!IsWindowed) + { + ::SetWindowPos(_Hwnd, HWND_TOPMOST, 0, 0, width, height, SWP_NOSIZE | SWP_NOMOVE); + + DEBUG_LOG(("Window resized to w:%d h:%d", width, height)); + } + else + { + // TheSuperHackers @feature helmutbuhler 14/04/2025 + // Center the window in the workarea of the monitor it is on. + MONITORINFO mi = { sizeof(MONITORINFO) }; + GetMonitorInfo(MonitorFromWindow(_Hwnd, MONITOR_DEFAULTTOPRIMARY), &mi); + int left = (mi.rcWork.left + mi.rcWork.right - width) / 2; + int top = (mi.rcWork.top + mi.rcWork.bottom - height) / 2; + + // TheSuperHackers @feature helmutbuhler 14/04/2025 + // Move the window to try fit it into the monitor area, if one of its dimensions is larger than the work area. + // Otherwise align the window to the top left edges, if it is even larger than the monitor area. + RECT rectClient; + rectClient.left = left - rect.left; + rectClient.top = top - rect.top; + rectClient.right = rectClient.left + ResolutionWidth; + rectClient.bottom = rectClient.top + ResolutionHeight; + MoveRectIntoOtherRect(rectClient, mi.rcMonitor, &left, &top); + + ::SetWindowPos(_Hwnd, NULL, left, top, width, height, SWP_NOZORDER); + + DEBUG_LOG(("Window positioned to x:%d y:%d, resized to w:%d h:%d", left, top, width, height)); + } + } +} + + + +bool DX8Wrapper::Set_Render_Device(int dev, int width, int height, int bits, int windowed, + bool resize_window, bool reset_device, bool restore_assets) +{ + WWASSERT(IsInitted); + WWASSERT(dev >= -1); + WWASSERT(dev < _RenderDeviceNameTable.Count()); + + /* + ** If user has never selected a render device, start out with device 0 + */ + if ((CurRenderDevice == -1) && (dev == -1)) { + CurRenderDevice = 0; + } + else if (dev != -1) { + CurRenderDevice = dev; + } + + /* + ** If user doesn't want to change res, set the res variables to match the + ** current resolution + */ + if (width != -1) ResolutionWidth = width; + if (height != -1) ResolutionHeight = height; + + // Initialize Render2DClass Screen Resolution + Render2DClass::Set_Screen_Resolution(RectClass(0, 0, ResolutionWidth, ResolutionHeight)); + + if (bits != -1) BitDepth = bits; + if (windowed != -1) IsWindowed = (windowed != 0); + DX8Wrapper_IsWindowed = IsWindowed; + + WWDEBUG_SAY(("Attempting Set_Render_Device: name: %s (%s:%s), width: %d, height: %d, windowed: %d", + _RenderDeviceNameTable[CurRenderDevice].str(), _RenderDeviceDescriptionTable[CurRenderDevice].Get_Driver_Name(), + _RenderDeviceDescriptionTable[CurRenderDevice].Get_Driver_Version(), ResolutionWidth, ResolutionHeight, (IsWindowed ? 1 : 0))); + +#ifdef _WINDOWS + // PWG 4/13/2000 - changed so that if you say to resize the window it resizes + // regardless of whether its windowed or not as OpenGL resizes its self around + // the caption and edges of the window type you provide, so its important to + // push the client area to be the size you really want. + // if ( resize_window && windowed ) { + if (resize_window) { + Resize_And_Position_Window(); + } +#endif + //must be either resetting existing device or creating a new one. + WWASSERT(reset_device || D3DDevice == NULL); + + /* + ** Initialize values for D3DPRESENT_PARAMETERS members. + */ + ::ZeroMemory(&_PresentParameters, sizeof(D3DPRESENT_PARAMETERS)); + + _PresentParameters.BackBufferWidth = ResolutionWidth; + _PresentParameters.BackBufferHeight = ResolutionHeight; + _PresentParameters.BackBufferCount = IsWindowed ? 1 : 2; + + _PresentParameters.MultiSampleType = D3DMULTISAMPLE_NONE; + //I changed this to discard all the time (even when full-screen) since that the most efficient. 07-16-03 MW: + _PresentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;//IsWindowed ? D3DSWAPEFFECT_DISCARD : D3DSWAPEFFECT_FLIP; // Shouldn't this be D3DSWAPEFFECT_FLIP? + _PresentParameters.hDeviceWindow = _Hwnd; + _PresentParameters.Windowed = IsWindowed; + + _PresentParameters.EnableAutoDepthStencil = TRUE; // Driver will attempt to match Z-buffer depth + _PresentParameters.Flags = 0; // We're not going to lock the backbuffer + + _PresentParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; + _PresentParameters.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT; + + /* + ** Set up the buffer formats. Several issues here: + ** - if in windowed mode, the backbuffer must use the current display format. + ** - the depth buffer must use + */ + if (IsWindowed) { + + D3DDISPLAYMODE desktop_mode; + ::ZeroMemory(&desktop_mode, sizeof(D3DDISPLAYMODE)); + D3DInterface->GetAdapterDisplayMode(CurRenderDevice, &desktop_mode); + + DisplayFormat = _PresentParameters.BackBufferFormat = desktop_mode.Format; + + // In windowed mode, define the bitdepth from desktop mode (as it can't be changed) + switch (_PresentParameters.BackBufferFormat) { + case D3DFMT_X8R8G8B8: + case D3DFMT_A8R8G8B8: + case D3DFMT_R8G8B8: BitDepth = 32; break; + case D3DFMT_A4R4G4B4: + case D3DFMT_A1R5G5B5: + case D3DFMT_R5G6B5: BitDepth = 16; break; + case D3DFMT_L8: + case D3DFMT_A8: + case D3DFMT_P8: BitDepth = 8; break; + default: + // Unknown backbuffer format probably means the device can't do windowed + return false; + } + + if (BitDepth == 32 && D3DInterface->CheckDeviceType(0, D3DDEVTYPE_HAL, desktop_mode.Format, D3DFMT_A8R8G8B8, TRUE) == D3D_OK) + { //promote 32-bit modes to include destination alpha + _PresentParameters.BackBufferFormat = D3DFMT_A8R8G8B8; + } + + /* + ** Find a appropriate Z buffer + */ + if (!Find_Z_Mode(DisplayFormat, _PresentParameters.BackBufferFormat, &_PresentParameters.AutoDepthStencilFormat)) + { + // If opening 32 bit mode failed, try 16 bit, even if the desktop happens to be 32 bit + if (BitDepth == 32) { + BitDepth = 16; + _PresentParameters.BackBufferFormat = D3DFMT_R5G6B5; + if (!Find_Z_Mode(_PresentParameters.BackBufferFormat, _PresentParameters.BackBufferFormat, &_PresentParameters.AutoDepthStencilFormat)) { + _PresentParameters.AutoDepthStencilFormat = D3DFMT_UNKNOWN; + } + } + else { + _PresentParameters.AutoDepthStencilFormat = D3DFMT_UNKNOWN; + } + } + + } + else { + + /* + ** Try to find a mode that matches the user's desired bit-depth. + */ + Find_Color_And_Z_Mode(ResolutionWidth, ResolutionHeight, BitDepth, &DisplayFormat, + &_PresentParameters.BackBufferFormat, &_PresentParameters.AutoDepthStencilFormat); + } + + /* + ** Time to actually create the device. + */ + if (_PresentParameters.AutoDepthStencilFormat == D3DFMT_UNKNOWN) { + if (BitDepth == 32) { + _PresentParameters.AutoDepthStencilFormat = D3DFMT_D32; + } + else { + _PresentParameters.AutoDepthStencilFormat = D3DFMT_D16; + } + } + + StringClass displayFormat; + StringClass backbufferFormat; + + Get_Format_Name(DisplayFormat, &displayFormat); + Get_Format_Name(_PresentParameters.BackBufferFormat, &backbufferFormat); + + WWDEBUG_SAY(("Using Display/BackBuffer Formats: %s/%s", displayFormat.str(), backbufferFormat.str())); + + bool ret; + + if (reset_device) + { + WWDEBUG_SAY(("DX8Wrapper::Set_Render_Device is resetting the device.")); + ret = Reset_Device(restore_assets); //reset device without restoring data - we're likely switching out of the app. + } + else + ret = Create_Device(); + + WWDEBUG_SAY(("Reset/Create_Device done, reset_device=%d, restore_assets=%d", reset_device, restore_assets)); + + return ret; +} + +bool DX8Wrapper::Set_Next_Render_Device(void) +{ + int new_dev = (CurRenderDevice + 1) % _RenderDeviceNameTable.Count(); + return Set_Render_Device(new_dev); +} + +bool DX8Wrapper::Toggle_Windowed(void) +{ +#ifdef WW3D_DX8 + // State OK? + assert(IsInitted); + if (IsInitted) { + + // Get information about the current render device's resolutions + const RenderDeviceDescClass& render_device = Get_Render_Device_Desc(); + const DynamicVectorClass& resolutions = render_device.Enumerate_Resolutions(); + + // Loop through all the resolutions supported by the current device. + // If we aren't currently running under one of these resolutions, + // then we should probably to the closest resolution before + // toggling the windowed state. + int curr_res = -1; + for (int res = 0; + (res < resolutions.Count()) && (curr_res == -1); + res++) { + + // Is this the resolution we are looking for? + if ((resolutions[res].Width == ResolutionWidth) && + (resolutions[res].Height == ResolutionHeight) && + (resolutions[res].BitDepth == BitDepth)) { + curr_res = res; + } + } + + if (curr_res == -1) { + + // We don't match any of the standard resolutions, + // so set the first resolution and toggle the windowed state. + return Set_Device_Resolution(resolutions[0].Width, + resolutions[0].Height, + resolutions[0].BitDepth, + !IsWindowed, true); + } + else { + + // Toggle the windowed state + return Set_Device_Resolution(-1, -1, -1, !IsWindowed, true); + } + } +#endif //WW3D_DX8 + + return false; +} + +void DX8Wrapper::Set_Swap_Interval(int swap) +{ + switch (swap) { + case 0: _PresentParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; break; + case 1: _PresentParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_ONE; break; + case 2: _PresentParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_TWO; break; + case 3: _PresentParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_THREE; break; + default: _PresentParameters.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_ONE; break; + } + + WWDEBUG_SAY(("DX8Wrapper::Set_Swap_Interval is resetting the device.")); + Reset_Device(); +} + +int DX8Wrapper::Get_Swap_Interval(void) +{ + return _PresentParameters.FullScreen_PresentationInterval; +} + +bool DX8Wrapper::Has_Stencil(void) +{ + bool has_stencil = (_PresentParameters.AutoDepthStencilFormat == D3DFMT_D24S8 || + _PresentParameters.AutoDepthStencilFormat == D3DFMT_D24X4S4); + return has_stencil; +} + +int DX8Wrapper::Get_Render_Device_Count(void) +{ + return _RenderDeviceNameTable.Count(); + +} +int DX8Wrapper::Get_Render_Device(void) +{ + assert(IsInitted); + return CurRenderDevice; +} + +const RenderDeviceDescClass& DX8Wrapper::Get_Render_Device_Desc(int deviceidx) +{ + WWASSERT(IsInitted); + + if ((deviceidx == -1) && (CurRenderDevice == -1)) { + CurRenderDevice = 0; + } + + // if the device index is -1 then we want the current device + if (deviceidx == -1) { + WWASSERT(CurRenderDevice >= 0); + WWASSERT(CurRenderDevice < _RenderDeviceNameTable.Count()); + return _RenderDeviceDescriptionTable[CurRenderDevice]; + } + + // We can only ask for multiple device information if the devices + // have been detected. + WWASSERT(deviceidx >= 0); + WWASSERT(deviceidx < _RenderDeviceNameTable.Count()); + return _RenderDeviceDescriptionTable[deviceidx]; +} + +const char* DX8Wrapper::Get_Render_Device_Name(int device_index) +{ + device_index = device_index % _RenderDeviceShortNameTable.Count(); + return _RenderDeviceShortNameTable[device_index]; +} + +bool DX8Wrapper::Set_Device_Resolution(int width, int height, int bits, int windowed, bool resize_window) +{ + if (D3DDevice != NULL) { + + if (width != -1) { + _PresentParameters.BackBufferWidth = ResolutionWidth = width; + } + if (height != -1) { + _PresentParameters.BackBufferHeight = ResolutionHeight = height; + } + if (resize_window) + { + Resize_And_Position_Window(); + } +#pragma message("TODO: support changing windowed status and changing the bit depth") + WWDEBUG_SAY(("DX8Wrapper::Set_Device_Resolution is resetting the device.")); + return Reset_Device(); + } + else { + return false; + } +} + +void DX8Wrapper::Get_Device_Resolution(int& set_w, int& set_h, int& set_bits, bool& set_windowed) +{ + WWASSERT(IsInitted); + + set_w = ResolutionWidth; + set_h = ResolutionHeight; + set_bits = BitDepth; + set_windowed = IsWindowed; + + return; +} + +void DX8Wrapper::Get_Render_Target_Resolution(int& set_w, int& set_h, int& set_bits, bool& set_windowed) +{ + WWASSERT(IsInitted); + + if (CurrentRenderTarget != NULL) { + D3DSURFACE_DESC info; + CurrentRenderTarget->GetDesc(&info); + + set_w = info.Width; + set_h = info.Height; + set_bits = BitDepth; // should we get the actual bit depth of the target? + set_windowed = IsWindowed; // this doesn't really make sense for render targets (shouldn't matter)... + + } + else { + Get_Device_Resolution(set_w, set_h, set_bits, set_windowed); + } + + return; +} + +bool DX8Wrapper::Registry_Save_Render_Device(const char* sub_key) +{ + int width, height, depth; + bool windowed; + Get_Device_Resolution(width, height, depth, windowed); + return Registry_Save_Render_Device(sub_key, CurRenderDevice, ResolutionWidth, ResolutionHeight, BitDepth, IsWindowed, TextureBitDepth); +} + +bool DX8Wrapper::Registry_Save_Render_Device(const char* sub_key, int device, int width, int height, int depth, bool windowed, int texture_depth) +{ + RegistryClass* registry = W3DNEW RegistryClass(sub_key); + WWASSERT(registry); + + if (!registry->Is_Valid()) { + delete registry; + WWDEBUG_SAY(("Error getting Registry")); + return false; + } + + registry->Set_String(VALUE_NAME_RENDER_DEVICE_NAME, + _RenderDeviceShortNameTable[device]); + registry->Set_Int(VALUE_NAME_RENDER_DEVICE_WIDTH, width); + registry->Set_Int(VALUE_NAME_RENDER_DEVICE_HEIGHT, height); + registry->Set_Int(VALUE_NAME_RENDER_DEVICE_DEPTH, depth); + registry->Set_Int(VALUE_NAME_RENDER_DEVICE_WINDOWED, windowed); + registry->Set_Int(VALUE_NAME_RENDER_DEVICE_TEXTURE_DEPTH, texture_depth); + + delete registry; + return true; +} + +bool DX8Wrapper::Registry_Load_Render_Device(const char* sub_key, bool resize_window) +{ + char name[200]; + int width, height, depth, windowed; + + if (Registry_Load_Render_Device(sub_key, + name, + sizeof(name), + width, + height, + depth, + windowed, + TextureBitDepth) && + (*name != 0)) + { + WWDEBUG_SAY(("Device %s (%d X %d) %d bit windowed:%d", name, width, height, depth, windowed)); + + if (TextureBitDepth == 16 || TextureBitDepth == 32) { + // WWDEBUG_SAY(( "Texture depth %d", TextureBitDepth)); + } + else { + WWDEBUG_SAY(("Invalid texture depth %d, switching to 16 bits", TextureBitDepth)); + TextureBitDepth = 16; + } + + + // _RenderDeviceDescriptionTable. + + + if (Set_Render_Device(name, width, height, depth, windowed, resize_window) != true) { + if (depth == 16) depth = 32; + else depth = 16; + if (Set_Render_Device(name, width, height, depth, windowed, resize_window) == true) { + return true; + } + if (depth == 16) depth = 32; + else depth = 16; + // we'll test resolutions down, so if start is 640, increase to begin with... + if (width == 640) { + width = 1024; + height = 768; + } + for (;;) { + if (width > 2048) { + width = 2048; + height = 1536; + } + else if (width > 1920) { + width = 1920; + height = 1440; + } + else if (width > 1600) { + width = 1600; + height = 1200; + } + else if (width > 1280) { + width = 1280; + height = 1024; + } + else if (width > 1024) { + width = 1024; + height = 768; + } + else if (width > 800) { + width = 800; + height = 600; + } + else if (width != 640) { + width = 640; + height = 480; + } + else { + return Set_Any_Render_Device(); + } + for (int i = 0; i < 2; ++i) { + if (Set_Render_Device(name, width, height, depth, windowed, resize_window) == true) { + return true; + } + if (depth == 16) depth = 32; + else depth = 16; + } + } + } + + return true; + } + + WWDEBUG_SAY(("Error getting Registry")); + + return Set_Any_Render_Device(); +} + +bool DX8Wrapper::Registry_Load_Render_Device(const char* sub_key, char* device, int device_len, int& width, int& height, int& depth, int& windowed, int& texture_depth) +{ + RegistryClass registry(sub_key); + + if (registry.Is_Valid()) { + registry.Get_String(VALUE_NAME_RENDER_DEVICE_NAME, + device, device_len); + + width = registry.Get_Int(VALUE_NAME_RENDER_DEVICE_WIDTH, -1); + height = registry.Get_Int(VALUE_NAME_RENDER_DEVICE_HEIGHT, -1); + depth = registry.Get_Int(VALUE_NAME_RENDER_DEVICE_DEPTH, -1); + windowed = registry.Get_Int(VALUE_NAME_RENDER_DEVICE_WINDOWED, -1); + texture_depth = registry.Get_Int(VALUE_NAME_RENDER_DEVICE_TEXTURE_DEPTH, -1); + return true; + } + *device = 0; + width = -1; + height = -1; + depth = -1; + windowed = -1; + texture_depth = -1; + return false; +} + + +bool DX8Wrapper::Find_Color_And_Z_Mode(int resx, int resy, int bitdepth, D3DFORMAT* set_colorbuffer, D3DFORMAT* set_backbuffer, D3DFORMAT* set_zmode) +{ + static D3DFORMAT _formats16[] = + { + D3DFMT_R5G6B5, + D3DFMT_X1R5G5B5, + D3DFMT_A1R5G5B5 + }; + + static D3DFORMAT _formats32[] = + { + D3DFMT_A8R8G8B8, + D3DFMT_X8R8G8B8, + D3DFMT_R8G8B8, + }; + + /* + ** Select the table that we're going to use to search for a valid backbuffer format + */ + D3DFORMAT* format_table = NULL; + int format_count = 0; + + if (BitDepth == 16) { + format_table = _formats16; + format_count = sizeof(_formats16) / sizeof(D3DFORMAT); + } + else { + format_table = _formats32; + format_count = sizeof(_formats32) / sizeof(D3DFORMAT); + } + + /* + ** now search for a valid format + */ + bool found = false; + unsigned int mode = 0; + + int format_index = 0; + for (; format_index < format_count; format_index++) { + found |= Find_Color_Mode(format_table[format_index], resx, resy, &mode); + if (found) break; + } + + if (!found) { + return false; + } + else { + *set_backbuffer = *set_colorbuffer = format_table[format_index]; + } + + if (bitdepth == 32 && *set_colorbuffer == D3DFMT_X8R8G8B8 && D3DInterface->CheckDeviceType(0, D3DDEVTYPE_HAL, *set_colorbuffer, D3DFMT_A8R8G8B8, TRUE) == D3D_OK) + { //promote 32-bit modes to include destination alpha when supported + *set_backbuffer = D3DFMT_A8R8G8B8; + } + + /* + ** We found a backbuffer format, now find a zbuffer format + */ + return Find_Z_Mode(*set_colorbuffer, *set_backbuffer, set_zmode); +}; + + +// find the resolution mode with at least resx,resy with the highest supported +// refresh rate +bool DX8Wrapper::Find_Color_Mode(D3DFORMAT colorbuffer, int resx, int resy, UINT* mode) +{ + UINT i, j, modemax; + UINT rx, ry; + D3DDISPLAYMODE dmode; + ::ZeroMemory(&dmode, sizeof(D3DDISPLAYMODE)); + + rx = (unsigned int)resx; + ry = (unsigned int)resy; + + bool found = false; + + modemax = D3DInterface->GetAdapterModeCount(D3DADAPTER_DEFAULT); + + i = 0; + + while (i < modemax && !found) + { + D3DInterface->EnumAdapterModes(D3DADAPTER_DEFAULT, i, &dmode); + if (dmode.Width == rx && dmode.Height == ry && dmode.Format == colorbuffer) { + WWDEBUG_SAY(("Found valid color mode. Width = %d Height = %d Format = %d", dmode.Width, dmode.Height, dmode.Format)); + found = true; + } + i++; + } + + i--; // this is the first valid mode + + // no match + if (!found) { + WWDEBUG_SAY(("Failed to find a valid color mode")); + return false; + } + + // go to the highest refresh rate in this mode + bool stillok = true; + + j = i; + while (j < modemax && stillok) + { + D3DInterface->EnumAdapterModes(D3DADAPTER_DEFAULT, j, &dmode); + if (dmode.Width == rx && dmode.Height == ry && dmode.Format == colorbuffer) + stillok = true; else stillok = false; + j++; + } + + if (stillok == false) *mode = j - 2; + else *mode = i; + + return true; +} + +// Helper function to find a Z buffer mode for the colorbuffer +// Will look for greatest Z precision +bool DX8Wrapper::Find_Z_Mode(D3DFORMAT colorbuffer, D3DFORMAT backbuffer, D3DFORMAT* zmode) +{ + //MW: Swapped the next 2 tests so that Stencil modes get tested first. + if (Test_Z_Mode(colorbuffer, backbuffer, D3DFMT_D24S8)) + { + *zmode = D3DFMT_D24S8; + WWDEBUG_SAY(("Found zbuffer mode D3DFMT_D24S8")); + return true; + } + + if (Test_Z_Mode(colorbuffer, backbuffer, D3DFMT_D32)) + { + *zmode = D3DFMT_D32; + WWDEBUG_SAY(("Found zbuffer mode D3DFMT_D32")); + return true; + } + + if (Test_Z_Mode(colorbuffer, backbuffer, D3DFMT_D24X8)) + { + *zmode = D3DFMT_D24X8; + WWDEBUG_SAY(("Found zbuffer mode D3DFMT_D24X8")); + return true; + } + + if (Test_Z_Mode(colorbuffer, backbuffer, D3DFMT_D24X4S4)) + { + *zmode = D3DFMT_D24X4S4; + WWDEBUG_SAY(("Found zbuffer mode D3DFMT_D24X4S4")); + return true; + } + + if (Test_Z_Mode(colorbuffer, backbuffer, D3DFMT_D16)) + { + *zmode = D3DFMT_D16; + WWDEBUG_SAY(("Found zbuffer mode D3DFMT_D16")); + return true; + } + + if (Test_Z_Mode(colorbuffer, backbuffer, D3DFMT_D15S1)) + { + *zmode = D3DFMT_D15S1; + WWDEBUG_SAY(("Found zbuffer mode D3DFMT_D15S1")); + return true; + } + + // can't find a match + WWDEBUG_SAY(("Failed to find a valid zbuffer mode")); + return false; +} + +bool DX8Wrapper::Test_Z_Mode(D3DFORMAT colorbuffer, D3DFORMAT backbuffer, D3DFORMAT zmode) +{ + // See if we have this mode first + if (FAILED(D3DInterface->CheckDeviceFormat(D3DADAPTER_DEFAULT, WW3D_DEVTYPE, + colorbuffer, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, zmode))) + { + WWDEBUG_SAY(("CheckDeviceFormat failed. Colorbuffer format = %d Zbufferformat = %d", colorbuffer, zmode)); + return false; + } + + // Then see if it matches the color buffer + if (FAILED(D3DInterface->CheckDepthStencilMatch(D3DADAPTER_DEFAULT, WW3D_DEVTYPE, + colorbuffer, backbuffer, zmode))) + { + WWDEBUG_SAY(("CheckDepthStencilMatch failed. Colorbuffer format = %d Backbuffer format = %d Zbufferformat = %d", colorbuffer, backbuffer, zmode)); + return false; + } + return true; +} + + +void DX8Wrapper::Reset_Statistics() +{ + matrix_changes = 0; + material_changes = 0; + vertex_buffer_changes = 0; + index_buffer_changes = 0; + light_changes = 0; + texture_changes = 0; + render_state_changes = 0; + texture_stage_state_changes = 0; + draw_calls = 0; + + number_of_DX8_calls = 0; + last_frame_matrix_changes = 0; + last_frame_material_changes = 0; + last_frame_vertex_buffer_changes = 0; + last_frame_index_buffer_changes = 0; + last_frame_light_changes = 0; + last_frame_texture_changes = 0; + last_frame_render_state_changes = 0; + last_frame_texture_stage_state_changes = 0; + last_frame_number_of_DX8_calls = 0; + last_frame_draw_calls = 0; +} + +void DX8Wrapper::Begin_Statistics() +{ + matrix_changes = 0; + material_changes = 0; + vertex_buffer_changes = 0; + index_buffer_changes = 0; + light_changes = 0; + texture_changes = 0; + render_state_changes = 0; + texture_stage_state_changes = 0; + number_of_DX8_calls = 0; + draw_calls = 0; +} + +void DX8Wrapper::End_Statistics() +{ + last_frame_matrix_changes = matrix_changes; + last_frame_material_changes = material_changes; + last_frame_vertex_buffer_changes = vertex_buffer_changes; + last_frame_index_buffer_changes = index_buffer_changes; + last_frame_light_changes = light_changes; + last_frame_texture_changes = texture_changes; + last_frame_render_state_changes = render_state_changes; + last_frame_texture_stage_state_changes = texture_stage_state_changes; + last_frame_number_of_DX8_calls = number_of_DX8_calls; + last_frame_draw_calls = draw_calls; +} + +unsigned DX8Wrapper::Get_Last_Frame_Matrix_Changes() { return last_frame_matrix_changes; } +unsigned DX8Wrapper::Get_Last_Frame_Material_Changes() { return last_frame_material_changes; } +unsigned DX8Wrapper::Get_Last_Frame_Vertex_Buffer_Changes() { return last_frame_vertex_buffer_changes; } +unsigned DX8Wrapper::Get_Last_Frame_Index_Buffer_Changes() { return last_frame_index_buffer_changes; } +unsigned DX8Wrapper::Get_Last_Frame_Light_Changes() { return last_frame_light_changes; } +unsigned DX8Wrapper::Get_Last_Frame_Texture_Changes() { return last_frame_texture_changes; } +unsigned DX8Wrapper::Get_Last_Frame_Render_State_Changes() { return last_frame_render_state_changes; } +unsigned DX8Wrapper::Get_Last_Frame_Texture_Stage_State_Changes() { return last_frame_texture_stage_state_changes; } +unsigned DX8Wrapper::Get_Last_Frame_DX8_Calls() { return last_frame_number_of_DX8_calls; } +unsigned DX8Wrapper::Get_Last_Frame_Draw_Calls() { return last_frame_draw_calls; } +unsigned long DX8Wrapper::Get_FrameCount(void) { return FrameCount; } + +void DX8_Assert() +{ + WWASSERT(DX8Wrapper::_Get_D3D8()); + DX8_THREAD_ASSERT(); +} + +void DX8Wrapper::Begin_Scene(void) +{ + DX8_THREAD_ASSERT(); + +#if ENABLE_EMBEDDED_BROWSER + DX8WebBrowser::Update(); +#endif + + DX8CALL(BeginScene()); + + DX8WebBrowser::Update(); +} + +void DX8Wrapper::End_Scene(bool flip_frames) +{ + DX8_THREAD_ASSERT(); + DX8CALL(EndScene()); + + DX8WebBrowser::Render(0); + + if (flip_frames) { + DX8_Assert(); + HRESULT hr; + { + WWPROFILE("DX8Device::Present()"); + hr = _Get_D3D_Device8()->Present(NULL, NULL, NULL, NULL); + } + + number_of_DX8_calls++; + + if (SUCCEEDED(hr)) { +#ifdef EXTENDED_STATS + if (stats.m_sleepTime) { + ::Sleep(stats.m_sleepTime); + } +#endif + IsDeviceLost = false; + FrameCount++; + } + else { + IsDeviceLost = true; + } + + // If the device was lost we need to check for cooperative level and possibly reset the device + if (hr == D3DERR_DEVICELOST) { + hr = _Get_D3D_Device8()->TestCooperativeLevel(); + if (hr == D3DERR_DEVICENOTRESET) { + WWDEBUG_SAY(("DX8Wrapper::End_Scene is resetting the device.")); + Reset_Device(); + } + else { + // Sleep it not active + ThreadClass::Sleep_Ms(200); + } + } + else { + DX8_ErrorCode(hr); + } + } + + // Each frame, release all of the buffers and textures. + Set_Vertex_Buffer(NULL); + Set_Index_Buffer(NULL, 0); + for (int i = 0; i < CurrentCaps->Get_Max_Textures_Per_Pass(); ++i) Set_Texture(i, NULL); + Set_Material(NULL); +} + + +void DX8Wrapper::Flip_To_Primary(void) +{ + // If we are fullscreen and the current frame is odd then we need + // to force a page flip to ensure that the first buffer in the flipping + // chain is the one visible. + if (!IsWindowed) { + DX8_Assert(); + + int numBuffers = (_PresentParameters.BackBufferCount + 1); + int visibleBuffer = (FrameCount % numBuffers); + int flipCount = ((numBuffers - visibleBuffer) % numBuffers); + int resetAttempts = 0; + + while ((flipCount > 0) && (resetAttempts < 3)) { + HRESULT hr = _Get_D3D_Device8()->TestCooperativeLevel(); + + if (FAILED(hr)) { + WWDEBUG_SAY(("TestCooperativeLevel Failed!")); + + if (D3DERR_DEVICELOST == hr) { + IsDeviceLost = true; + WWDEBUG_SAY(("DEVICELOST: Cannot flip to primary.")); + return; + } + IsDeviceLost = false; + + if (D3DERR_DEVICENOTRESET == hr) { + WWDEBUG_SAY(("DEVICENOTRESET")); + Reset_Device(); + resetAttempts++; + } + } + else { + WWDEBUG_SAY(("Flipping: %ld", FrameCount)); + hr = _Get_D3D_Device8()->Present(NULL, NULL, NULL, NULL); + + if (SUCCEEDED(hr)) { + IsDeviceLost = false; + FrameCount++; + WWDEBUG_SAY(("Flip to primary succeeded %ld", FrameCount)); + } + else { + IsDeviceLost = true; + } + } + + --flipCount; + } + } +} + + + +//********************************************************************************************** +//! Clear current render device +/*! KM +/* 5/17/02 KM Fixed support for render to texture with depth/stencil buffers +*/ +void DX8Wrapper::Clear(bool clear_color, bool clear_z_stencil, const Vector3& color, float dest_alpha, float z, unsigned int stencil) +{ + DX8_THREAD_ASSERT(); + + // If we try to clear a stencil buffer which is not there, the entire call will fail + // KJM fixed this to get format from back buffer (incase render to texture is used) + /*bool has_stencil = ( _PresentParameters.AutoDepthStencilFormat == D3DFMT_D15S1 || + _PresentParameters.AutoDepthStencilFormat == D3DFMT_D24S8 || + _PresentParameters.AutoDepthStencilFormat == D3DFMT_D24X4S4);*/ + bool has_stencil = false; + IDirect3DSurface8* depthbuffer; + + _Get_D3D_Device8()->GetDepthStencilSurface(&depthbuffer); + number_of_DX8_calls++; + + if (depthbuffer) + { + D3DSURFACE_DESC desc; + depthbuffer->GetDesc(&desc); + has_stencil = + ( + desc.Format == D3DFMT_D15S1 || + desc.Format == D3DFMT_D24S8 || + desc.Format == D3DFMT_D24X4S4 + ); + + // release ref + depthbuffer->Release(); + } + + DWORD flags = 0; + if (clear_color) flags |= D3DCLEAR_TARGET; + if (clear_z_stencil) flags |= D3DCLEAR_ZBUFFER; + if (clear_z_stencil && has_stencil) flags |= D3DCLEAR_STENCIL; + if (flags) + { + DX8CALL(Clear(0, NULL, flags, Convert_Color(color, dest_alpha), z, stencil)); + } +} + +void DX8Wrapper::Set_Viewport(CONST D3DVIEWPORT8* pViewport) +{ + DX8_THREAD_ASSERT(); + DX8CALL(SetViewport(pViewport)); +} + +// ---------------------------------------------------------------------------- +// +// Set vertex buffer. A reference to previous vertex buffer is released and +// this one is assigned the current vertex buffer. The DX8 vertex buffer will +// actually be set in Apply() which is called by Draw_Indexed_Triangles(). +// +// ---------------------------------------------------------------------------- + +void DX8Wrapper::Set_Vertex_Buffer(const VertexBufferClass* vb, unsigned stream) +{ + render_state.vba_offset = 0; + render_state.vba_count = 0; + if (render_state.vertex_buffers[stream]) { + render_state.vertex_buffers[stream]->Release_Engine_Ref(); + } + REF_PTR_SET(render_state.vertex_buffers[stream], const_cast(vb)); + if (vb) { + vb->Add_Engine_Ref(); + render_state.vertex_buffer_types[stream] = vb->Type(); + } + else { + render_state.vertex_buffer_types[stream] = BUFFER_TYPE_INVALID; + } + render_state_changed |= VERTEX_BUFFER_CHANGED; +} + +// ---------------------------------------------------------------------------- +// +// Set index buffer. A reference to previous index buffer is released and +// this one is assigned the current index buffer. The DX8 index buffer will +// actually be set in Apply() which is called by Draw_Indexed_Triangles(). +// +// ---------------------------------------------------------------------------- + +void DX8Wrapper::Set_Index_Buffer(const IndexBufferClass* ib, unsigned short index_base_offset) +{ + render_state.iba_offset = 0; + if (render_state.index_buffer) { + render_state.index_buffer->Release_Engine_Ref(); + } + REF_PTR_SET(render_state.index_buffer, const_cast(ib)); + render_state.index_base_offset = index_base_offset; + if (ib) { + ib->Add_Engine_Ref(); + render_state.index_buffer_type = ib->Type(); + } + else { + render_state.index_buffer_type = BUFFER_TYPE_INVALID; + } + render_state_changed |= INDEX_BUFFER_CHANGED; +} + +// ---------------------------------------------------------------------------- +// +// Set vertex buffer using dynamic access object. +// +// ---------------------------------------------------------------------------- + +void DX8Wrapper::Set_Vertex_Buffer(const DynamicVBAccessClass& vba_) +{ + // Release all streams (only one stream allowed in the legacy pipeline) + for (int i = 1; i < MAX_VERTEX_STREAMS; ++i) { + DX8Wrapper::Set_Vertex_Buffer(NULL, i); + } + + if (render_state.vertex_buffers[0]) render_state.vertex_buffers[0]->Release_Engine_Ref(); + DynamicVBAccessClass& vba = const_cast(vba_); + render_state.vertex_buffer_types[0] = vba.Get_Type(); + render_state.vba_offset = vba.VertexBufferOffset; + render_state.vba_count = vba.Get_Vertex_Count(); + REF_PTR_SET(render_state.vertex_buffers[0], vba.VertexBuffer); + render_state.vertex_buffers[0]->Add_Engine_Ref(); + render_state_changed |= VERTEX_BUFFER_CHANGED; + render_state_changed |= INDEX_BUFFER_CHANGED; // vba_offset changes so index buffer needs to be reset as well. +} + +// ---------------------------------------------------------------------------- +// +// Set index buffer using dynamic access object. +// +// ---------------------------------------------------------------------------- + +void DX8Wrapper::Set_Index_Buffer(const DynamicIBAccessClass& iba_, unsigned short index_base_offset) +{ + if (render_state.index_buffer) render_state.index_buffer->Release_Engine_Ref(); + + DynamicIBAccessClass& iba = const_cast(iba_); + render_state.index_base_offset = index_base_offset; + render_state.index_buffer_type = iba.Get_Type(); + render_state.iba_offset = iba.IndexBufferOffset; + REF_PTR_SET(render_state.index_buffer, iba.IndexBuffer); + render_state.index_buffer->Add_Engine_Ref(); + render_state_changed |= INDEX_BUFFER_CHANGED; +} + +// ---------------------------------------------------------------------------- +// +// Private function for the special case of rendering polygons from sorting +// index and vertex buffers. +// +// ---------------------------------------------------------------------------- + +void DX8Wrapper::Draw_Sorting_IB_VB( + unsigned primitive_type, + unsigned short start_index, + unsigned short polygon_count, + unsigned short min_vertex_index, + unsigned short vertex_count) +{ + WWASSERT(render_state.vertex_buffer_types[0] == BUFFER_TYPE_SORTING || render_state.vertex_buffer_types[0] == BUFFER_TYPE_DYNAMIC_SORTING); + WWASSERT(render_state.index_buffer_type == BUFFER_TYPE_SORTING || render_state.index_buffer_type == BUFFER_TYPE_DYNAMIC_SORTING); + + // Fill dynamic vertex buffer with sorting vertex buffer vertices + DynamicVBAccessClass dyn_vb_access(BUFFER_TYPE_DYNAMIC_DX8, dynamic_fvf_type, vertex_count); + { + DynamicVBAccessClass::WriteLockClass lock(&dyn_vb_access); + VertexFormatXYZNDUV2* src = static_cast(render_state.vertex_buffers[0])->VertexBuffer; + VertexFormatXYZNDUV2* dest = lock.Get_Formatted_Vertex_Array(); + src += render_state.vba_offset + render_state.index_base_offset + min_vertex_index; + unsigned size = dyn_vb_access.FVF_Info().Get_FVF_Size() * vertex_count / sizeof(unsigned); + unsigned* dest_u = (unsigned*)dest; + unsigned* src_u = (unsigned*)src; + + for (unsigned i = 0; i < size; ++i) { + *dest_u++ = *src_u++; + } + } + + DX8CALL(SetStreamSource( + 0, + static_cast(dyn_vb_access.VertexBuffer)->Get_DX8_Vertex_Buffer(), + dyn_vb_access.FVF_Info().Get_FVF_Size())); + // If using FVF format VB, set the FVF as vertex shader (may not be needed here KM) + unsigned fvf = dyn_vb_access.FVF_Info().Get_FVF(); + if (fvf != 0) { + DX8CALL(SetVertexShader(fvf)); + } + DX8_RECORD_VERTEX_BUFFER_CHANGE(); + + unsigned index_count = 0; + switch (primitive_type) { + case D3DPT_TRIANGLELIST: index_count = polygon_count * 3; break; + case D3DPT_TRIANGLESTRIP: index_count = polygon_count + 2; break; + case D3DPT_TRIANGLEFAN: index_count = polygon_count + 2; break; + default: WWASSERT(0); break; // Unsupported primitive type + } + + // Fill dynamic index buffer with sorting index buffer vertices + DynamicIBAccessClass dyn_ib_access(BUFFER_TYPE_DYNAMIC_DX8, index_count); + { + DynamicIBAccessClass::WriteLockClass lock(&dyn_ib_access); + unsigned short* dest = lock.Get_Index_Array(); + unsigned short* src = NULL; + src = static_cast(render_state.index_buffer)->index_buffer; + src += render_state.iba_offset + start_index; + + for (unsigned short i = 0; i < index_count; ++i) { + unsigned short index = *src++; + index -= min_vertex_index; + WWASSERT(index < vertex_count); + *dest++ = index; + } + } + + DX8CALL(SetIndices( + static_cast(dyn_ib_access.IndexBuffer)->Get_DX8_Index_Buffer(), + dyn_vb_access.VertexBufferOffset)); + DX8_RECORD_INDEX_BUFFER_CHANGE(); + + DX8_RECORD_DRAW_CALLS(); + DX8CALL(DrawIndexedPrimitive( + D3DPT_TRIANGLELIST, + 0, // start vertex + vertex_count, + dyn_ib_access.IndexBufferOffset, + polygon_count)); + + DX8_RECORD_RENDER(polygon_count, vertex_count, render_state.shader); +} + +// ---------------------------------------------------------------------------- +// +// +// +// ---------------------------------------------------------------------------- + +void DX8Wrapper::Draw( + unsigned primitive_type, + unsigned short start_index, + unsigned short polygon_count, + unsigned short min_vertex_index, + unsigned short vertex_count) +{ + if (DrawPolygonLowBoundLimit && DrawPolygonLowBoundLimit >= polygon_count) return; + + DX8_THREAD_ASSERT(); + SNAPSHOT_SAY(("DX8 - draw")); + + Apply_Render_State_Changes(); + + // Debug feature to disable triangle drawing... + if (!_Is_Triangle_Draw_Enabled()) return; + +#ifdef MESH_RENDER_SNAPSHOT_ENABLED + if (WW3D::Is_Snapshot_Activated()) { + unsigned long passes = 0; + SNAPSHOT_SAY(("ValidateDevice:")); + HRESULT res = D3DDevice->ValidateDevice(&passes); + switch (res) { + case D3D_OK: + SNAPSHOT_SAY(("OK")); + break; + + case D3DERR_CONFLICTINGTEXTUREFILTER: + SNAPSHOT_SAY(("D3DERR_CONFLICTINGTEXTUREFILTER")); + break; + case D3DERR_CONFLICTINGTEXTUREPALETTE: + SNAPSHOT_SAY(("D3DERR_CONFLICTINGTEXTUREPALETTE")); + break; + case D3DERR_DEVICELOST: + SNAPSHOT_SAY(("D3DERR_DEVICELOST")); + break; + case D3DERR_TOOMANYOPERATIONS: + SNAPSHOT_SAY(("D3DERR_TOOMANYOPERATIONS")); + break; + case D3DERR_UNSUPPORTEDALPHAARG: + SNAPSHOT_SAY(("D3DERR_UNSUPPORTEDALPHAARG")); + break; + case D3DERR_UNSUPPORTEDALPHAOPERATION: + SNAPSHOT_SAY(("D3DERR_UNSUPPORTEDALPHAOPERATION")); + break; + case D3DERR_UNSUPPORTEDCOLORARG: + SNAPSHOT_SAY(("D3DERR_UNSUPPORTEDCOLORARG")); + break; + case D3DERR_UNSUPPORTEDCOLOROPERATION: + SNAPSHOT_SAY(("D3DERR_UNSUPPORTEDCOLOROPERATION")); + break; + case D3DERR_UNSUPPORTEDFACTORVALUE: + SNAPSHOT_SAY(("D3DERR_UNSUPPORTEDFACTORVALUE")); + break; + case D3DERR_UNSUPPORTEDTEXTUREFILTER: + SNAPSHOT_SAY(("D3DERR_UNSUPPORTEDTEXTUREFILTER")); + break; + case D3DERR_WRONGTEXTUREFORMAT: + SNAPSHOT_SAY(("D3DERR_WRONGTEXTUREFORMAT")); + break; + default: + SNAPSHOT_SAY(("UNKNOWN Error")); + break; + } + } +#endif // MESH_RENDER_SHAPSHOT_ENABLED + + + SNAPSHOT_SAY(("DX8 - draw %d polygons (%d vertices)", polygon_count, vertex_count)); + + if (vertex_count < 3) { + min_vertex_index = 0; + switch (render_state.vertex_buffer_types[0]) { + case BUFFER_TYPE_DX8: + case BUFFER_TYPE_SORTING: + vertex_count = render_state.vertex_buffers[0]->Get_Vertex_Count() - render_state.index_base_offset - render_state.vba_offset - min_vertex_index; + break; + case BUFFER_TYPE_DYNAMIC_DX8: + case BUFFER_TYPE_DYNAMIC_SORTING: + vertex_count = render_state.vba_count; + break; + } + } + + switch (render_state.vertex_buffer_types[0]) { + case BUFFER_TYPE_DX8: + case BUFFER_TYPE_DYNAMIC_DX8: + switch (render_state.index_buffer_type) { + case BUFFER_TYPE_DX8: + case BUFFER_TYPE_DYNAMIC_DX8: + { + /* if ((start_index+render_state.iba_offset+polygon_count*3) > render_state.index_buffer->Get_Index_Count()) + { WWASSERT_PRINT(0,"OVERFLOWING INDEX BUFFER"); + ///@todo: MUST FIND OUT WHY THIS HAPPENS WITH LOTS OF PARTICLES ON BIG FIGHT! -MW + break; + }*/ + DX8_RECORD_RENDER(polygon_count, vertex_count, render_state.shader); + DX8_RECORD_DRAW_CALLS(); + DX8CALL(DrawIndexedPrimitive( + (D3DPRIMITIVETYPE)primitive_type, + min_vertex_index, + vertex_count, + start_index + render_state.iba_offset, + polygon_count)); + } + break; + case BUFFER_TYPE_SORTING: + case BUFFER_TYPE_DYNAMIC_SORTING: + WWASSERT_PRINT(0, "VB and IB must of same type (sorting or dx8)"); + break; + case BUFFER_TYPE_INVALID: + WWASSERT(0); + break; + } + break; + case BUFFER_TYPE_SORTING: + case BUFFER_TYPE_DYNAMIC_SORTING: + switch (render_state.index_buffer_type) { + case BUFFER_TYPE_DX8: + case BUFFER_TYPE_DYNAMIC_DX8: + WWASSERT_PRINT(0, "VB and IB must of same type (sorting or dx8)"); + break; + case BUFFER_TYPE_SORTING: + case BUFFER_TYPE_DYNAMIC_SORTING: + Draw_Sorting_IB_VB(primitive_type, start_index, polygon_count, min_vertex_index, vertex_count); + break; + case BUFFER_TYPE_INVALID: + WWASSERT(0); + break; + } + break; + case BUFFER_TYPE_INVALID: + WWASSERT(0); + break; + } +} + +// ---------------------------------------------------------------------------- +// +// +// +// ---------------------------------------------------------------------------- + +void DX8Wrapper::Draw_Triangles( + unsigned buffer_type, + unsigned short start_index, + unsigned short polygon_count, + unsigned short min_vertex_index, + unsigned short vertex_count) +{ + if (buffer_type == BUFFER_TYPE_SORTING || buffer_type == BUFFER_TYPE_DYNAMIC_SORTING) { + SortingRendererClass::Insert_Triangles(start_index, polygon_count, min_vertex_index, vertex_count); + } + else { + Draw(D3DPT_TRIANGLELIST, start_index, polygon_count, min_vertex_index, vertex_count); + } +} + +// ---------------------------------------------------------------------------- +// +// +// +// ---------------------------------------------------------------------------- + +void DX8Wrapper::Draw_Triangles( + unsigned short start_index, + unsigned short polygon_count, + unsigned short min_vertex_index, + unsigned short vertex_count) +{ + Draw(D3DPT_TRIANGLELIST, start_index, polygon_count, min_vertex_index, vertex_count); +} + +// ---------------------------------------------------------------------------- +// +// +// +// ---------------------------------------------------------------------------- + +void DX8Wrapper::Draw_Strip( + unsigned short start_index, + unsigned short polygon_count, + unsigned short min_vertex_index, + unsigned short vertex_count) +{ + Draw(D3DPT_TRIANGLESTRIP, start_index, polygon_count, min_vertex_index, vertex_count); +} + + + +// ---------------------------------------------------------------------------- +// +// +// +// ---------------------------------------------------------------------------- + +void DX8Wrapper::Apply_Render_State_Changes() +{ + SNAPSHOT_SAY(("DX8Wrapper::Apply_Render_State_Changes()")); + + if (!render_state_changed) return; + if (render_state_changed & SHADER_CHANGED) { + SNAPSHOT_SAY(("DX8 - apply shader")); + render_state.shader.Apply(); + } + + unsigned mask = TEXTURE0_CHANGED; + int i = 0; + for (; i < CurrentCaps->Get_Max_Textures_Per_Pass(); ++i, mask <<= 1) + { + if (render_state_changed & mask) + { + SNAPSHOT_SAY(("DX8 - apply texture %d (%s)", i, render_state.Textures[i] ? render_state.Textures[i]->Get_Full_Path().str() : "NULL")); + + if (render_state.Textures[i]) + { + render_state.Textures[i]->Apply(i); + } + else + { + TextureBaseClass::Apply_Null(i); + } + } + } + + if (render_state_changed & MATERIAL_CHANGED) + { + SNAPSHOT_SAY(("DX8 - apply material")); + VertexMaterialClass* material = const_cast(render_state.material); + if (material) + { + material->Apply(); + } + else VertexMaterialClass::Apply_Null(); + } + + if (render_state_changed & LIGHTS_CHANGED) + { + unsigned mask = LIGHT0_CHANGED; + for (unsigned index = 0; index < 4; ++index, mask <<= 1) { + if (render_state_changed & mask) { + SNAPSHOT_SAY(("DX8 - apply light %d", index)); + if (render_state.LightEnable[index]) { +#ifdef MESH_RENDER_SNAPSHOT_ENABLED + if (WW3D::Is_Snapshot_Activated()) { + D3DLIGHT8* light = &(render_state.Lights[index]); + static const char* _light_types[] = { "Unknown", "Point","Spot", "Directional" }; + WWASSERT((light->Type >= 0) && (light->Type <= 3)); + + SNAPSHOT_SAY((" type = %s amb = %4.2f,%4.2f,%4.2f diff = %4.2f,%4.2f,%4.2f spec = %4.2f, %4.2f, %4.2f", + _light_types[light->Type], + light->Ambient.r, light->Ambient.g, light->Ambient.b, + light->Diffuse.r, light->Diffuse.g, light->Diffuse.b, + light->Specular.r, light->Specular.g, light->Specular.b)); + SNAPSHOT_SAY((" pos = %f, %f, %f dir = %f, %f, %f", + light->Position.x, light->Position.y, light->Position.z, + light->Direction.x, light->Direction.y, light->Direction.z)); + } +#endif + + Set_DX8_Light(index, &render_state.Lights[index]); + } + else { + Set_DX8_Light(index, NULL); + SNAPSHOT_SAY((" clearing light to NULL")); + } + } + } + } + + if (render_state_changed & WORLD_CHANGED) { + SNAPSHOT_SAY(("DX8 - apply world matrix")); + _Set_DX8_Transform(D3DTS_WORLD, render_state.world); + } + if (render_state_changed & VIEW_CHANGED) { + SNAPSHOT_SAY(("DX8 - apply view matrix")); + _Set_DX8_Transform(D3DTS_VIEW, render_state.view); + } + if (render_state_changed & VERTEX_BUFFER_CHANGED) { + SNAPSHOT_SAY(("DX8 - apply vb change")); + for (i = 0; i < MAX_VERTEX_STREAMS; ++i) { + if (render_state.vertex_buffers[i]) { + switch (render_state.vertex_buffer_types[i]) {//->Type()) { + case BUFFER_TYPE_DX8: + case BUFFER_TYPE_DYNAMIC_DX8: + DX8CALL(SetStreamSource( + i, + static_cast(render_state.vertex_buffers[i])->Get_DX8_Vertex_Buffer(), + render_state.vertex_buffers[i]->FVF_Info().Get_FVF_Size())); + DX8_RECORD_VERTEX_BUFFER_CHANGE(); + { + // If the VB format is FVF, set the FVF as a vertex shader + unsigned fvf = render_state.vertex_buffers[i]->FVF_Info().Get_FVF(); + if (fvf != 0) { + Set_Vertex_Shader(fvf); + } + } + break; + case BUFFER_TYPE_SORTING: + case BUFFER_TYPE_DYNAMIC_SORTING: + break; + default: + WWASSERT(0); + } + } + else { + DX8CALL(SetStreamSource(i, NULL, 0)); + DX8_RECORD_VERTEX_BUFFER_CHANGE(); + } + } + } + if (render_state_changed & INDEX_BUFFER_CHANGED) { + SNAPSHOT_SAY(("DX8 - apply ib change")); + if (render_state.index_buffer) { + switch (render_state.index_buffer_type) {//->Type()) { + case BUFFER_TYPE_DX8: + case BUFFER_TYPE_DYNAMIC_DX8: + DX8CALL(SetIndices( + static_cast(render_state.index_buffer)->Get_DX8_Index_Buffer(), + render_state.index_base_offset + render_state.vba_offset)); + DX8_RECORD_INDEX_BUFFER_CHANGE(); + break; + case BUFFER_TYPE_SORTING: + case BUFFER_TYPE_DYNAMIC_SORTING: + break; + default: + WWASSERT(0); + } + } + else { + DX8CALL(SetIndices( + NULL, + 0)); + DX8_RECORD_INDEX_BUFFER_CHANGE(); + } + } + + render_state_changed &= ((unsigned)WORLD_IDENTITY | (unsigned)VIEW_IDENTITY); + + SNAPSHOT_SAY(("DX8Wrapper::Apply_Render_State_Changes() - finished")); +} + +IDirect3DTexture8* DX8Wrapper::_Create_DX8_Texture +( + unsigned int width, + unsigned int height, + WW3DFormat format, + MipCountType mip_level_count, + D3DPOOL pool, + bool rendertarget +) +{ + DX8_THREAD_ASSERT(); + DX8_Assert(); + IDirect3DTexture8* 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 = D3DXCreateTexture( + DX8Wrapper::_Get_D3D_Device8(), + width, + height, + 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 = D3DXCreateTexture( + DX8Wrapper::_Get_D3D_Device8(), + width, + height, + 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 = D3DXCreateTexture( + DX8Wrapper::_Get_D3D_Device8(), + width, + height, + 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 = D3DXCreateTexture( + DX8Wrapper::_Get_D3D_Device8(), + width, + height, + 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; +} + +IDirect3DTexture8* DX8Wrapper::_Create_DX8_Texture +( + const char* filename, + MipCountType mip_level_count +) +{ + DX8_THREAD_ASSERT(); + DX8_Assert(); + IDirect3DTexture8* texture = NULL; + + // NOTE: If the original image format is not supported as a texture format, it will + // automatically be converted to an appropriate format. + // NOTE: It is possible to get the size and format of the original image file from this + // function as well, so if we later want to second-guess D3DX's format conversion decisions + // we can do so after this function is called.. + unsigned result = D3DXCreateTextureFromFileExA( + _Get_D3D_Device8(), + filename, + D3DX_DEFAULT, + D3DX_DEFAULT, + mip_level_count,//create_mipmaps ? 0 : 1, + 0, + D3DFMT_UNKNOWN, + D3DPOOL_MANAGED, + D3DX_FILTER_BOX, + D3DX_FILTER_BOX, + 0, + NULL, + NULL, + &texture); + + if (result != D3D_OK) { + return MissingTexture::_Get_Missing_Texture(); + } + + // Make sure texture wasn't paletted! + D3DSURFACE_DESC desc; + texture->GetLevelDesc(0, &desc); + if (desc.Format == D3DFMT_P8) { + texture->Release(); + return MissingTexture::_Get_Missing_Texture(); + } + return texture; +} + +IDirect3DTexture8* DX8Wrapper::_Create_DX8_Texture +( + IDirect3DSurface8* surface, + MipCountType mip_level_count +) +{ + DX8_THREAD_ASSERT(); + DX8_Assert(); + IDirect3DTexture8* texture = NULL; + + D3DSURFACE_DESC surface_desc; + ::ZeroMemory(&surface_desc, sizeof(D3DSURFACE_DESC)); + surface->GetDesc(&surface_desc); + + // This function will create a texture with a different (but similar) format if the surface is + // not in a supported texture format. + WW3DFormat format = D3DFormat_To_WW3DFormat(surface_desc.Format); + texture = _Create_DX8_Texture(surface_desc.Width, surface_desc.Height, format, mip_level_count); + + // Copy the surface to the texture + IDirect3DSurface8* tex_surface = NULL; + texture->GetSurfaceLevel(0, &tex_surface); + DX8_ErrorCode(D3DXLoadSurfaceFromSurface(tex_surface, NULL, NULL, surface, NULL, NULL, D3DX_FILTER_BOX, 0)); + tex_surface->Release(); + + // Create mipmaps if needed + if (mip_level_count != MIP_LEVELS_1) + { + DX8_ErrorCode(D3DXFilterTexture(texture, NULL, 0, D3DX_FILTER_BOX)); + } + + return 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(); + DX8_Assert(); + + IDirect3DSurface8* surface = NULL; + + // Paletted surfaces not supported! + WWASSERT(format != D3DFMT_P8); + + DX8CALL(CreateImageSurface(width, height, WW3DFormat_To_D3DFormat(format), &surface)); + + return surface; +} + +IDirect3DSurface8* DX8Wrapper::_Create_DX8_Surface(const char* filename_) +{ + DX8_THREAD_ASSERT(); + DX8_Assert(); + + // Note: Since there is no "D3DXCreateSurfaceFromFile" and no "GetSurfaceInfoFromFile" (the + // latter is supposed to be added to D3DX in a future version), we create a texture from the + // file (w/o mipmaps), check that its surface is equal to the original file data (which it + // will not be if the file is not in a texture-supported format or size). If so, copy its + // surface (we might be able to just get its surface and add a ref to it but I'm not sure so + // I'm not going to risk it) and release the texture. If not, create a surface according to + // the file data and use D3DXLoadSurfaceFromFile. This is a horrible hack, but it saves us + // having to write file loaders. Will fix this when D3DX provides us with the right functions. + // Create a surface the size of the file image data + IDirect3DSurface8* surface = NULL; + + { + + file_auto_ptr myfile(_TheFileFactory, filename_); + // If file not found, create a surface with missing texture in it + + if (!myfile->Is_Available()) { + // If file not found, try the dds format + // else create a surface with missing texture in it + char compressed_name[200]; + strncpy(compressed_name, filename_, ARRAY_SIZE(compressed_name)); + compressed_name[ARRAY_SIZE(compressed_name) - 1] = '\0'; + char* ext = strstr(compressed_name, "."); + if (ext && (strlen(ext) == 4) && + ((ext[1] == 't') || (ext[1] == 'T')) && + ((ext[2] == 'g') || (ext[2] == 'G')) && + ((ext[3] == 'a') || (ext[3] == 'A'))) { + ext[1] = 'd'; + ext[2] = 'd'; + ext[3] = 's'; + } + file_auto_ptr myfile2(_TheFileFactory, compressed_name); + if (!myfile2->Is_Available()) + return MissingTexture::_Create_Missing_Surface(); + } + } + + StringClass filename_string(filename_, true); + surface = TextureLoader::Load_Surface_Immediate( + filename_string, + WW3D_FORMAT_UNKNOWN, + true); + return surface; +} + + +/*********************************************************************************************** + * DX8Wrapper::_Update_Texture -- Copies a texture from system memory to video memory * + * * + * * + * * + * * + * INPUT: * + * * + * OUTPUT: * + * * + * WARNINGS: * + * * + * HISTORY: * + * 4/26/2001 hy : Created. * + *=============================================================================================*/ +void DX8Wrapper::_Update_Texture(TextureClass* system, TextureClass* video) +{ + WWASSERT(system); + WWASSERT(video); + WWASSERT(system->Get_Pool() == TextureClass::POOL_SYSTEMMEM); + WWASSERT(video->Get_Pool() == TextureClass::POOL_DEFAULT); + DX8CALL(UpdateTexture(system->Peek_D3D_Base_Texture(), video->Peek_D3D_Base_Texture())); +} + +void DX8Wrapper::Compute_Caps(WW3DFormat display_format) +{ + DX8_THREAD_ASSERT(); + DX8_Assert(); + delete CurrentCaps; + CurrentCaps = new DX8Caps(_Get_D3D8(), D3DDevice, display_format, Get_Current_Adapter_Identifier()); +} + + +void DX8Wrapper::Set_Light(unsigned index, const D3DLIGHT8* light) +{ + if (light) { + render_state.Lights[index] = *light; + render_state.LightEnable[index] = true; + } + else { + render_state.LightEnable[index] = false; + } + render_state_changed |= (LIGHT0_CHANGED << index); +} + +void DX8Wrapper::Set_Light(unsigned index, const LightClass& light) +{ + D3DLIGHT8 dlight; + Vector3 temp; + memset(&dlight, 0, sizeof(D3DLIGHT8)); + + switch (light.Get_Type()) + { + case LightClass::POINT: + { + dlight.Type = D3DLIGHT_POINT; + } + break; + case LightClass::DIRECTIONAL: + { + dlight.Type = D3DLIGHT_DIRECTIONAL; + } + break; + case LightClass::SPOT: + { + dlight.Type = D3DLIGHT_SPOT; + } + break; + } + + light.Get_Diffuse(&temp); + temp *= light.Get_Intensity(); + dlight.Diffuse.r = temp.X; + dlight.Diffuse.g = temp.Y; + dlight.Diffuse.b = temp.Z; + dlight.Diffuse.a = 1.0f; + + light.Get_Specular(&temp); + temp *= light.Get_Intensity(); + dlight.Specular.r = temp.X; + dlight.Specular.g = temp.Y; + dlight.Specular.b = temp.Z; + dlight.Specular.a = 1.0f; + + light.Get_Ambient(&temp); + temp *= light.Get_Intensity(); + dlight.Ambient.r = temp.X; + dlight.Ambient.g = temp.Y; + dlight.Ambient.b = temp.Z; + dlight.Ambient.a = 1.0f; + + temp = light.Get_Position(); + dlight.Position = *(D3DVECTOR*)&temp; + + light.Get_Spot_Direction(temp); + dlight.Direction = *(D3DVECTOR*)&temp; + + dlight.Range = light.Get_Attenuation_Range(); + dlight.Falloff = light.Get_Spot_Exponent(); + dlight.Theta = light.Get_Spot_Angle(); + dlight.Phi = light.Get_Spot_Angle(); + + // Inverse linear light 1/(1+D) + double a, b; + light.Get_Far_Attenuation_Range(a, b); + dlight.Attenuation0 = 1.0f; + if (fabs(a - b) < 1e-5) + // if the attenuation range is too small assume uniform with cutoff + dlight.Attenuation1 = 0.0f; + else + // this will cause the light to drop to half intensity at the first far attenuation + dlight.Attenuation1 = (float)1.0 / a; + dlight.Attenuation2 = 0.0f; + + Set_Light(index, &dlight); +} + +//********************************************************************************************** +//! Set the light environment. This is a lighting model which used up to four +//! directional lights to produce the lighting. +/*! 5/27/02 KJM Added shader light environment support +*/ +void DX8Wrapper::Set_Light_Environment(LightEnvironmentClass* light_env) +{ + // Shader light environment support * +// if (Light_Environment && light_env && (*Light_Environment)==(*light_env)) return; + + Light_Environment = light_env; + + if (light_env) + { + int light_count = light_env->Get_Light_Count(); + unsigned int color = Convert_Color(light_env->Get_Equivalent_Ambient(), 0.0f); + if (RenderStates[D3DRS_AMBIENT] != color) + { + Set_DX8_Render_State(D3DRS_AMBIENT, color); + //buggy Radeon 9700 driver doesn't apply new ambient unless the material also changes. +#if 1 + render_state_changed |= MATERIAL_CHANGED; +#endif + } + + D3DLIGHT8 light; + int l = 0; + for (; l < light_count; ++l) { + + ::ZeroMemory(&light, sizeof(D3DLIGHT8)); + + light.Type = D3DLIGHT_DIRECTIONAL; + (Vector3&)light.Diffuse = light_env->Get_Light_Diffuse(l); + Vector3 dir = -light_env->Get_Light_Direction(l); + light.Direction = (const D3DVECTOR&)(dir); + + // (gth) TODO: put specular into LightEnvironment? Much work to be done on lights :-)' + if (l == 0) { + light.Specular.r = light.Specular.g = light.Specular.b = 1.0f; + } + + if (light_env->isPointLight(l)) { + light.Type = D3DLIGHT_POINT; + (Vector3&)light.Diffuse = light_env->getPointDiffuse(l); + (Vector3&)light.Ambient = light_env->getPointAmbient(l); + light.Position = (const D3DVECTOR&)light_env->getPointCenter(l); + light.Range = light_env->getPointOrad(l); + + // Inverse linear light 1/(1+D) + double a, b; + b = light_env->getPointOrad(l); + a = light_env->getPointIrad(l); + + //(gth) CNC3 Generals code for the attenuation factors is causing the lights to over-brighten + //I'm changing the Attenuation0 parameter to 1.0 to avoid this problem. +#if 0 + light.Attenuation0 = 0.01f; +#else + light.Attenuation0 = 1.0f; +#endif + if (fabs(a - b) < 1e-5) + // if the attenuation range is too small assume uniform with cutoff + light.Attenuation1 = 0.0f; + else + // this will cause the light to drop to half intensity at the first far attenuation + light.Attenuation1 = (float)0.1 / a; + + light.Attenuation2 = 8.0f / (b * b); + } + + Set_Light(l, &light); + } + + for (; l < 4; ++l) { + Set_Light(l, NULL); + } + } + /* else { + for (int l=0;l<4;++l) { + Set_Light(l,NULL); + } + } + */ +} + + +IDirect3DSurface8* DX8Wrapper::_Get_DX8_Front_Buffer() +{ + DX8_THREAD_ASSERT(); + D3DDISPLAYMODE mode; + + DX8CALL(GetDisplayMode(&mode)); + + IDirect3DSurface8* fb = NULL; + + DX8CALL(CreateImageSurface(mode.Width, mode.Height, D3DFMT_A8R8G8B8, &fb)); + + DX8CALL(GetFrontBuffer(fb)); + return fb; +} + +SurfaceClass* DX8Wrapper::_Get_DX8_Back_Buffer(unsigned int num) +{ + DX8_THREAD_ASSERT(); + + IDirect3DSurface8* bb; + SurfaceClass* surf = NULL; + DX8CALL(GetBackBuffer(num, D3DBACKBUFFER_TYPE_MONO, &bb)); + if (bb) + { + surf = NEW_REF(SurfaceClass, (bb)); + bb->Release(); + } + + return surf; +} + +TextureClass* +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 + // + const D3DCAPS8& dx8caps = Get_Current_Caps()->Get_DX8_Caps(); + float poweroftwosize = width; + if (height > 0 && height < width) { + poweroftwosize = height; + } + poweroftwosize = ::Find_POT(poweroftwosize); + + if (poweroftwosize > dx8caps.MaxTextureWidth) { + poweroftwosize = dx8caps.MaxTextureWidth; + } + if (poweroftwosize > dx8caps.MaxTextureHeight) { + poweroftwosize = dx8caps.MaxTextureHeight; + } + + width = height = poweroftwosize; + + // + // Attempt to create the render target + // + 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++; + + // 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 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)) + { + WWDEBUG_SAY(("DX8Wrapper - Render target with depth format is not supported")); + return; + } + + // 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) + { + poweroftwosize = height; + } + poweroftwosize = ::Find_POT(poweroftwosize); + + if (poweroftwosize > dx8caps.MaxTextureWidth) + { + poweroftwosize = dx8caps.MaxTextureWidth; + } + + if (poweroftwosize > dx8caps.MaxTextureHeight) + { + poweroftwosize = dx8caps.MaxTextureHeight; + } + + width = height = poweroftwosize; + + // Attempt to create the render target + 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); + } + + *target = tex; + + // attempt to create the depth stencil buffer + *depth_buffer = NEW_REF + ( + ZTextureClass, + ( + width, + height, + zformat, + MIP_LEVELS_1, + TextureClass::POOL_DEFAULT + ) + ); +} + +/*! + * Set render target + * KM Added optional custom z target + */ +void DX8Wrapper::Set_Render_Target_With_Z +( + TextureClass* texture, + ZTextureClass* ztexture +) +{ + 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 +DX8Wrapper::Set_Render_Target(IDirect3DSwapChain8* swap_chain) +{ + DX8_THREAD_ASSERT(); + WWASSERT(swap_chain != NULL); + + // + // Get the back buffer for the swap chain + // + LPDIRECT3DSURFACE8 render_target = NULL; + swap_chain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &render_target); + + // + // Set this back buffer as the render targer + // + Set_Render_Target(render_target, true); + + // + // Release our hold on the back buffer + // + if (render_target != NULL) { + render_target->Release(); + render_target = NULL; + } + + IsRenderToTexture = false; + + return; +} + +void +DX8Wrapper::Set_Render_Target(IDirect3DSurface8* render_target, bool use_default_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; + WWASSERT(CurrentRenderTarget != NULL); + if (CurrentRenderTarget != NULL) + { + CurrentRenderTarget->AddRef(); + + // + // Switch render targets + // + 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; +// } + + 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 +} + + +IDirect3DSwapChain8* +DX8Wrapper::Create_Additional_Swap_Chain(HWND render_window) +{ + DX8_Assert(); + + // + // Configure the presentation parameters for a windowed render target + // + D3DPRESENT_PARAMETERS params = { 0 }; + params.BackBufferFormat = _PresentParameters.BackBufferFormat; + params.BackBufferCount = 1; + params.MultiSampleType = D3DMULTISAMPLE_NONE; + params.SwapEffect = D3DSWAPEFFECT_COPY_VSYNC; + params.hDeviceWindow = render_window; + params.Windowed = TRUE; + params.EnableAutoDepthStencil = TRUE; + params.AutoDepthStencilFormat = _PresentParameters.AutoDepthStencilFormat; + params.Flags = 0; + params.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT; + params.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; + + // + // Create the swap chain + // + IDirect3DSwapChain8* swap_chain = NULL; + DX8CALL(CreateAdditionalSwapChain(¶ms, &swap_chain)); + return swap_chain; +} + +void DX8Wrapper::Flush_DX8_Resource_Manager(unsigned int bytes) +{ + DX8_Assert(); + DX8CALL(ResourceManagerDiscardBytes(bytes)); +} + +unsigned int DX8Wrapper::Get_Free_Texture_RAM() +{ + DX8_Assert(); + number_of_DX8_calls++; + return DX8Wrapper::_Get_D3D_Device8()->GetAvailableTextureMem(); +} + +// Converts a linear gamma ramp to one that is controlled by: +// Gamma - controls the curvature of the middle of the curve +// Bright - controls the minimum value of the curve +// Contrast - controls the difference between the maximum and the minimum of the curve +void DX8Wrapper::Set_Gamma(float gamma, float bright, float contrast, bool calibrate, bool uselimit) +{ + gamma = Bound(gamma, 0.6f, 6.0f); + bright = Bound(bright, -0.5f, 0.5f); + contrast = Bound(contrast, 0.5f, 2.0f); + float oo_gamma = 1.0f / gamma; + + DX8_Assert(); + number_of_DX8_calls++; + + DWORD flag = (calibrate ? D3DSGR_CALIBRATE : D3DSGR_NO_CALIBRATION); + + D3DGAMMARAMP ramp; + float limit; + + // IML: I'm not really sure what the intent of the 'limit' variable is. It does not produce useful results for my purposes. + if (uselimit) { + limit = (contrast - 1) / 2 * contrast; + } + else { + limit = 0.0f; + } + + // HY - arrived at this equation after much trial and error. + for (int i = 0; i < 256; i++) { + float in, out; + in = i / 256.0f; + float x = in - limit; + x = Bound(x, 0.0f, 1.0f); + x = powf(x, oo_gamma); + out = contrast * x + bright; + out = Bound(out, 0.0f, 1.0f); + ramp.red[i] = (WORD)(out * 65535); + ramp.green[i] = (WORD)(out * 65535); + ramp.blue[i] = (WORD)(out * 65535); + } + + if (Get_Current_Caps()->Support_Gamma()) { + DX8Wrapper::_Get_D3D_Device8()->SetGammaRamp(flag, &ramp); + } + else { + HWND hwnd = GetDesktopWindow(); + HDC hdc = GetDC(hwnd); + if (hdc) + { + SetDeviceGammaRamp(hdc, &ramp); + ReleaseDC(hwnd, hdc); + } + } +} + +//********************************************************************************************** +//! Resets render device to default state +/*! +*/ +void DX8Wrapper::Apply_Default_State() +{ + SNAPSHOT_SAY(("DX8Wrapper::Apply_Default_State()")); + + // only set states used in game + Set_DX8_Render_State(D3DRS_ZENABLE, TRUE); + // Set_DX8_Render_State(D3DRS_FILLMODE, D3DFILL_SOLID); + Set_DX8_Render_State(D3DRS_SHADEMODE, D3DSHADE_GOURAUD); + //Set_DX8_Render_State(D3DRS_LINEPATTERN, 0); + Set_DX8_Render_State(D3DRS_ZWRITEENABLE, TRUE); + Set_DX8_Render_State(D3DRS_ALPHATESTENABLE, FALSE); + //Set_DX8_Render_State(D3DRS_LASTPIXEL, FALSE); + Set_DX8_Render_State(D3DRS_SRCBLEND, D3DBLEND_ONE); + Set_DX8_Render_State(D3DRS_DESTBLEND, D3DBLEND_ZERO); + Set_DX8_Render_State(D3DRS_CULLMODE, D3DCULL_CW); + Set_DX8_Render_State(D3DRS_ZFUNC, D3DCMP_LESSEQUAL); + Set_DX8_Render_State(D3DRS_ALPHAREF, 0); + Set_DX8_Render_State(D3DRS_ALPHAFUNC, D3DCMP_LESSEQUAL); + Set_DX8_Render_State(D3DRS_DITHERENABLE, FALSE); + Set_DX8_Render_State(D3DRS_ALPHABLENDENABLE, FALSE); + Set_DX8_Render_State(D3DRS_FOGENABLE, FALSE); + Set_DX8_Render_State(D3DRS_SPECULARENABLE, FALSE); + // Set_DX8_Render_State(D3DRS_ZVISIBLE, FALSE); + // Set_DX8_Render_State(D3DRS_FOGCOLOR, 0); + // Set_DX8_Render_State(D3DRS_FOGTABLEMODE, D3DFOG_NONE); + // Set_DX8_Render_State(D3DRS_FOGSTART, 0); + + // Set_DX8_Render_State(D3DRS_FOGEND, WWMath::Float_As_Int(1.0f)); + // Set_DX8_Render_State(D3DRS_FOGDENSITY, WWMath::Float_As_Int(1.0f)); + + //Set_DX8_Render_State(D3DRS_EDGEANTIALIAS, FALSE); + Set_DX8_Render_State(D3DRS_ZBIAS, 0); + // Set_DX8_Render_State(D3DRS_RANGEFOGENABLE, FALSE); + Set_DX8_Render_State(D3DRS_STENCILENABLE, FALSE); + Set_DX8_Render_State(D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP); + Set_DX8_Render_State(D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP); + Set_DX8_Render_State(D3DRS_STENCILPASS, D3DSTENCILOP_KEEP); + Set_DX8_Render_State(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); + Set_DX8_Render_State(D3DRS_STENCILREF, 0); + Set_DX8_Render_State(D3DRS_STENCILMASK, 0xffffffff); + Set_DX8_Render_State(D3DRS_STENCILWRITEMASK, 0xffffffff); + Set_DX8_Render_State(D3DRS_TEXTUREFACTOR, 0); + /* Set_DX8_Render_State(D3DRS_WRAP0, D3DWRAP_U| D3DWRAP_V); + Set_DX8_Render_State(D3DRS_WRAP1, D3DWRAP_U| D3DWRAP_V); + Set_DX8_Render_State(D3DRS_WRAP2, D3DWRAP_U| D3DWRAP_V); + Set_DX8_Render_State(D3DRS_WRAP3, D3DWRAP_U| D3DWRAP_V); + Set_DX8_Render_State(D3DRS_WRAP4, D3DWRAP_U| D3DWRAP_V); + Set_DX8_Render_State(D3DRS_WRAP5, D3DWRAP_U| D3DWRAP_V); + Set_DX8_Render_State(D3DRS_WRAP6, D3DWRAP_U| D3DWRAP_V); + Set_DX8_Render_State(D3DRS_WRAP7, D3DWRAP_U| D3DWRAP_V);*/ + Set_DX8_Render_State(D3DRS_CLIPPING, TRUE); + Set_DX8_Render_State(D3DRS_LIGHTING, FALSE); + //Set_DX8_Render_State(D3DRS_AMBIENT, 0); +// Set_DX8_Render_State(D3DRS_FOGVERTEXMODE, D3DFOG_NONE); + Set_DX8_Render_State(D3DRS_COLORVERTEX, TRUE); + /* Set_DX8_Render_State(D3DRS_LOCALVIEWER, TRUE); + Set_DX8_Render_State(D3DRS_NORMALIZENORMALS, FALSE); + Set_DX8_Render_State(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1); + Set_DX8_Render_State(D3DRS_SPECULARMATERIALSOURCE, D3DMCS_COLOR2); + Set_DX8_Render_State(D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_MATERIAL); + Set_DX8_Render_State(D3DRS_EMISSIVEMATERIALSOURCE, D3DMCS_MATERIAL); + Set_DX8_Render_State(D3DRS_VERTEXBLEND, D3DVBF_DISABLE);*/ + //Set_DX8_Render_State(D3DRS_CLIPPLANEENABLE, 0); + Set_DX8_Render_State(D3DRS_SOFTWAREVERTEXPROCESSING, FALSE); + //Set_DX8_Render_State(D3DRS_POINTSIZE, 0x3f800000); + //Set_DX8_Render_State(D3DRS_POINTSIZE_MIN, 0); + //Set_DX8_Render_State(D3DRS_POINTSPRITEENABLE, FALSE); + //Set_DX8_Render_State(D3DRS_POINTSCALEENABLE, FALSE); + //Set_DX8_Render_State(D3DRS_POINTSCALE_A, 0); + //Set_DX8_Render_State(D3DRS_POINTSCALE_B, 0); + //Set_DX8_Render_State(D3DRS_POINTSCALE_C, 0); + //Set_DX8_Render_State(D3DRS_MULTISAMPLEANTIALIAS, TRUE); + //Set_DX8_Render_State(D3DRS_MULTISAMPLEMASK, 0xffffffff); + //Set_DX8_Render_State(D3DRS_PATCHEDGESTYLE, D3DPATCHEDGE_DISCRETE); + //Set_DX8_Render_State(D3DRS_PATCHSEGMENTS, 0x3f800000); + //Set_DX8_Render_State(D3DRS_DEBUGMONITORTOKEN, D3DDMT_ENABLE); + //Set_DX8_Render_State(D3DRS_POINTSIZE_MAX, Float_At_Int(64.0f)); + //Set_DX8_Render_State(D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE); + Set_DX8_Render_State(D3DRS_COLORWRITEENABLE, 0x0000000f); + //Set_DX8_Render_State(D3DRS_TWEENFACTOR, 0); + Set_DX8_Render_State(D3DRS_BLENDOP, D3DBLENDOP_ADD); + //Set_DX8_Render_State(D3DRS_POSITIONORDER, D3DORDER_CUBIC); + //Set_DX8_Render_State(D3DRS_NORMALORDER, D3DORDER_LINEAR); + + // disable TSS stages + int i; + for (i = 0; i < CurrentCaps->Get_Max_Textures_Per_Pass(); i++) + { + Set_DX8_Texture_Stage_State(i, D3DTSS_COLOROP, D3DTOP_DISABLE); + Set_DX8_Texture_Stage_State(i, D3DTSS_COLORARG1, D3DTA_TEXTURE); + Set_DX8_Texture_Stage_State(i, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + + Set_DX8_Texture_Stage_State(i, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + Set_DX8_Texture_Stage_State(i, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + Set_DX8_Texture_Stage_State(i, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); + + /*Set_DX8_Texture_Stage_State(i, D3DTSS_BUMPENVMAT00, 0); + Set_DX8_Texture_Stage_State(i, D3DTSS_BUMPENVMAT01, 0); + Set_DX8_Texture_Stage_State(i, D3DTSS_BUMPENVMAT10, 0); + Set_DX8_Texture_Stage_State(i, D3DTSS_BUMPENVMAT11, 0); + Set_DX8_Texture_Stage_State(i, D3DTSS_BUMPENVLSCALE, 0); + Set_DX8_Texture_Stage_State(i, D3DTSS_BUMPENVLOFFSET, 0);*/ + + Set_DX8_Texture_Stage_State(i, D3DTSS_TEXCOORDINDEX, i); + + + Set_DX8_Texture_Stage_State(i, D3DTSS_ADDRESSU, D3DTADDRESS_WRAP); + Set_DX8_Texture_Stage_State(i, D3DTSS_ADDRESSV, D3DTADDRESS_WRAP); + Set_DX8_Texture_Stage_State(i, D3DTSS_BORDERCOLOR, 0); + // Set_DX8_Texture_Stage_State(i, D3DTSS_MAGFILTER, D3DTEXF_LINEAR); + // Set_DX8_Texture_Stage_State(i, D3DTSS_MINFILTER, D3DTEXF_LINEAR); + // Set_DX8_Texture_Stage_State(i, D3DTSS_MIPFILTER, D3DTEXF_LINEAR); + // Set_DX8_Texture_Stage_State(i, D3DTSS_MIPMAPLODBIAS, 0); + // Set_DX8_Texture_Stage_State(i, D3DTSS_MAXMIPLEVEL, 0); + // Set_DX8_Texture_Stage_State(i, D3DTSS_MAXANISOTROPY, 1); + //Set_DX8_Texture_Stage_State(i, D3DTSS_ADDRESSW, D3DTADDRESS_WRAP); + //Set_DX8_Texture_Stage_State(i, D3DTSS_COLORARG0, D3DTA_CURRENT); + //Set_DX8_Texture_Stage_State(i, D3DTSS_ALPHAARG0, D3DTA_CURRENT); + //Set_DX8_Texture_Stage_State(i, D3DTSS_RESULTARG, D3DTA_CURRENT); + + Set_DX8_Texture_Stage_State(i, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE); + Set_Texture(i, NULL); + } + + // DX8Wrapper::Set_Material(NULL); + VertexMaterialClass::Apply_Null(); + + for (unsigned index = 0; index < 4; ++index) { + SNAPSHOT_SAY(("Clearing light %d to NULL", index)); + Set_DX8_Light(index, NULL); + } + + // set up simple default TSS + Vector4 vconst[MAX_VERTEX_SHADER_CONSTANTS]; + memset(vconst, 0, sizeof(Vector4) * MAX_VERTEX_SHADER_CONSTANTS); + Set_Vertex_Shader_Constant(0, vconst, MAX_VERTEX_SHADER_CONSTANTS); + + Vector4 pconst[MAX_PIXEL_SHADER_CONSTANTS]; + memset(pconst, 0, sizeof(Vector4) * MAX_PIXEL_SHADER_CONSTANTS); + Set_Pixel_Shader_Constant(0, pconst, MAX_PIXEL_SHADER_CONSTANTS); + + Set_Vertex_Shader(DX8_FVF_XYZNDUV2); + Set_Pixel_Shader(0); + + ShaderClass::Invalidate(); +} + +const char* DX8Wrapper::Get_DX8_Render_State_Name(D3DRENDERSTATETYPE state) +{ + switch (state) { + case D3DRS_ZENABLE: return "D3DRS_ZENABLE"; + case D3DRS_FILLMODE: return "D3DRS_FILLMODE"; + case D3DRS_SHADEMODE: return "D3DRS_SHADEMODE"; + case D3DRS_LINEPATTERN: return "D3DRS_LINEPATTERN"; + case D3DRS_ZWRITEENABLE: return "D3DRS_ZWRITEENABLE"; + case D3DRS_ALPHATESTENABLE: return "D3DRS_ALPHATESTENABLE"; + case D3DRS_LASTPIXEL: return "D3DRS_LASTPIXEL"; + case D3DRS_SRCBLEND: return "D3DRS_SRCBLEND"; + case D3DRS_DESTBLEND: return "D3DRS_DESTBLEND"; + case D3DRS_CULLMODE: return "D3DRS_CULLMODE"; + case D3DRS_ZFUNC: return "D3DRS_ZFUNC"; + case D3DRS_ALPHAREF: return "D3DRS_ALPHAREF"; + case D3DRS_ALPHAFUNC: return "D3DRS_ALPHAFUNC"; + case D3DRS_DITHERENABLE: return "D3DRS_DITHERENABLE"; + case D3DRS_ALPHABLENDENABLE: return "D3DRS_ALPHABLENDENABLE"; + case D3DRS_FOGENABLE: return "D3DRS_FOGENABLE"; + case D3DRS_SPECULARENABLE: return "D3DRS_SPECULARENABLE"; + case D3DRS_ZVISIBLE: return "D3DRS_ZVISIBLE"; + case D3DRS_FOGCOLOR: return "D3DRS_FOGCOLOR"; + case D3DRS_FOGTABLEMODE: return "D3DRS_FOGTABLEMODE"; + case D3DRS_FOGSTART: return "D3DRS_FOGSTART"; + case D3DRS_FOGEND: return "D3DRS_FOGEND"; + case D3DRS_FOGDENSITY: return "D3DRS_FOGDENSITY"; + case D3DRS_EDGEANTIALIAS: return "D3DRS_EDGEANTIALIAS"; + case D3DRS_ZBIAS: return "D3DRS_ZBIAS"; + case D3DRS_RANGEFOGENABLE: return "D3DRS_RANGEFOGENABLE"; + case D3DRS_STENCILENABLE: return "D3DRS_STENCILENABLE"; + case D3DRS_STENCILFAIL: return "D3DRS_STENCILFAIL"; + case D3DRS_STENCILZFAIL: return "D3DRS_STENCILZFAIL"; + case D3DRS_STENCILPASS: return "D3DRS_STENCILPASS"; + case D3DRS_STENCILFUNC: return "D3DRS_STENCILFUNC"; + case D3DRS_STENCILREF: return "D3DRS_STENCILREF"; + case D3DRS_STENCILMASK: return "D3DRS_STENCILMASK"; + case D3DRS_STENCILWRITEMASK: return "D3DRS_STENCILWRITEMASK"; + case D3DRS_TEXTUREFACTOR: return "D3DRS_TEXTUREFACTOR"; + case D3DRS_WRAP0: return "D3DRS_WRAP0"; + case D3DRS_WRAP1: return "D3DRS_WRAP1"; + case D3DRS_WRAP2: return "D3DRS_WRAP2"; + case D3DRS_WRAP3: return "D3DRS_WRAP3"; + case D3DRS_WRAP4: return "D3DRS_WRAP4"; + case D3DRS_WRAP5: return "D3DRS_WRAP5"; + case D3DRS_WRAP6: return "D3DRS_WRAP6"; + case D3DRS_WRAP7: return "D3DRS_WRAP7"; + case D3DRS_CLIPPING: return "D3DRS_CLIPPING"; + case D3DRS_LIGHTING: return "D3DRS_LIGHTING"; + case D3DRS_AMBIENT: return "D3DRS_AMBIENT"; + case D3DRS_FOGVERTEXMODE: return "D3DRS_FOGVERTEXMODE"; + case D3DRS_COLORVERTEX: return "D3DRS_COLORVERTEX"; + case D3DRS_LOCALVIEWER: return "D3DRS_LOCALVIEWER"; + case D3DRS_NORMALIZENORMALS: return "D3DRS_NORMALIZENORMALS"; + case D3DRS_DIFFUSEMATERIALSOURCE: return "D3DRS_DIFFUSEMATERIALSOURCE"; + case D3DRS_SPECULARMATERIALSOURCE: return "D3DRS_SPECULARMATERIALSOURCE"; + case D3DRS_AMBIENTMATERIALSOURCE: return "D3DRS_AMBIENTMATERIALSOURCE"; + case D3DRS_EMISSIVEMATERIALSOURCE: return "D3DRS_EMISSIVEMATERIALSOURCE"; + case D3DRS_VERTEXBLEND: return "D3DRS_VERTEXBLEND"; + case D3DRS_CLIPPLANEENABLE: return "D3DRS_CLIPPLANEENABLE"; + case D3DRS_SOFTWAREVERTEXPROCESSING: return "D3DRS_SOFTWAREVERTEXPROCESSING"; + case D3DRS_POINTSIZE: return "D3DRS_POINTSIZE"; + case D3DRS_POINTSIZE_MIN: return "D3DRS_POINTSIZE_MIN"; + case D3DRS_POINTSPRITEENABLE: return "D3DRS_POINTSPRITEENABLE"; + case D3DRS_POINTSCALEENABLE: return "D3DRS_POINTSCALEENABLE"; + case D3DRS_POINTSCALE_A: return "D3DRS_POINTSCALE_A"; + case D3DRS_POINTSCALE_B: return "D3DRS_POINTSCALE_B"; + case D3DRS_POINTSCALE_C: return "D3DRS_POINTSCALE_C"; + case D3DRS_MULTISAMPLEANTIALIAS: return "D3DRS_MULTISAMPLEANTIALIAS"; + case D3DRS_MULTISAMPLEMASK: return "D3DRS_MULTISAMPLEMASK"; + case D3DRS_PATCHEDGESTYLE: return "D3DRS_PATCHEDGESTYLE"; + case D3DRS_PATCHSEGMENTS: return "D3DRS_PATCHSEGMENTS"; + case D3DRS_DEBUGMONITORTOKEN: return "D3DRS_DEBUGMONITORTOKEN"; + case D3DRS_POINTSIZE_MAX: return "D3DRS_POINTSIZE_MAX"; + case D3DRS_INDEXEDVERTEXBLENDENABLE: return "D3DRS_INDEXEDVERTEXBLENDENABLE"; + case D3DRS_COLORWRITEENABLE: return "D3DRS_COLORWRITEENABLE"; + case D3DRS_TWEENFACTOR: return "D3DRS_TWEENFACTOR"; + case D3DRS_BLENDOP: return "D3DRS_BLENDOP"; + // case D3DRS_POSITIONORDER : return "D3DRS_POSITIONORDER"; + // case D3DRS_NORMALORDER : return "D3DRS_NORMALORDER"; + default: return "UNKNOWN"; + } +} + +const char* DX8Wrapper::Get_DX8_Texture_Stage_State_Name(D3DTEXTURESTAGESTATETYPE state) +{ + switch (state) { + case D3DTSS_COLOROP: return "D3DTSS_COLOROP"; + case D3DTSS_COLORARG1: return "D3DTSS_COLORARG1"; + case D3DTSS_COLORARG2: return "D3DTSS_COLORARG2"; + case D3DTSS_ALPHAOP: return "D3DTSS_ALPHAOP"; + case D3DTSS_ALPHAARG1: return "D3DTSS_ALPHAARG1"; + case D3DTSS_ALPHAARG2: return "D3DTSS_ALPHAARG2"; + case D3DTSS_BUMPENVMAT00: return "D3DTSS_BUMPENVMAT00"; + case D3DTSS_BUMPENVMAT01: return "D3DTSS_BUMPENVMAT01"; + case D3DTSS_BUMPENVMAT10: return "D3DTSS_BUMPENVMAT10"; + case D3DTSS_BUMPENVMAT11: return "D3DTSS_BUMPENVMAT11"; + case D3DTSS_TEXCOORDINDEX: return "D3DTSS_TEXCOORDINDEX"; + case D3DTSS_ADDRESSU: return "D3DTSS_ADDRESSU"; + case D3DTSS_ADDRESSV: return "D3DTSS_ADDRESSV"; + case D3DTSS_BORDERCOLOR: return "D3DTSS_BORDERCOLOR"; + case D3DTSS_MAGFILTER: return "D3DTSS_MAGFILTER"; + case D3DTSS_MINFILTER: return "D3DTSS_MINFILTER"; + case D3DTSS_MIPFILTER: return "D3DTSS_MIPFILTER"; + case D3DTSS_MIPMAPLODBIAS: return "D3DTSS_MIPMAPLODBIAS"; + case D3DTSS_MAXMIPLEVEL: return "D3DTSS_MAXMIPLEVEL"; + case D3DTSS_MAXANISOTROPY: return "D3DTSS_MAXANISOTROPY"; + case D3DTSS_BUMPENVLSCALE: return "D3DTSS_BUMPENVLSCALE"; + case D3DTSS_BUMPENVLOFFSET: return "D3DTSS_BUMPENVLOFFSET"; + case D3DTSS_TEXTURETRANSFORMFLAGS: return "D3DTSS_TEXTURETRANSFORMFLAGS"; + case D3DTSS_ADDRESSW: return "D3DTSS_ADDRESSW"; + case D3DTSS_COLORARG0: return "D3DTSS_COLORARG0"; + case D3DTSS_ALPHAARG0: return "D3DTSS_ALPHAARG0"; + case D3DTSS_RESULTARG: return "D3DTSS_RESULTARG"; + default: return "UNKNOWN"; + } +} + +void DX8Wrapper::Get_DX8_Render_State_Value_Name(StringClass& name, D3DRENDERSTATETYPE state, unsigned value) +{ + switch (state) { + case D3DRS_ZENABLE: + name = Get_DX8_ZBuffer_Type_Name(value); + break; + + case D3DRS_FILLMODE: + name = Get_DX8_Fill_Mode_Name(value); + break; + + case D3DRS_SHADEMODE: + name = Get_DX8_Shade_Mode_Name(value); + break; + + case D3DRS_LINEPATTERN: + case D3DRS_FOGCOLOR: + case D3DRS_ALPHAREF: + case D3DRS_STENCILMASK: + case D3DRS_STENCILWRITEMASK: + case D3DRS_TEXTUREFACTOR: + case D3DRS_AMBIENT: + case D3DRS_CLIPPLANEENABLE: + case D3DRS_MULTISAMPLEMASK: + name.Format("0x%x", value); + break; + + case D3DRS_ZWRITEENABLE: + case D3DRS_ALPHATESTENABLE: + case D3DRS_LASTPIXEL: + case D3DRS_DITHERENABLE: + case D3DRS_ALPHABLENDENABLE: + case D3DRS_FOGENABLE: + case D3DRS_SPECULARENABLE: + case D3DRS_STENCILENABLE: + case D3DRS_RANGEFOGENABLE: + case D3DRS_EDGEANTIALIAS: + case D3DRS_CLIPPING: + case D3DRS_LIGHTING: + case D3DRS_COLORVERTEX: + case D3DRS_LOCALVIEWER: + case D3DRS_NORMALIZENORMALS: + case D3DRS_SOFTWAREVERTEXPROCESSING: + case D3DRS_POINTSPRITEENABLE: + case D3DRS_POINTSCALEENABLE: + case D3DRS_MULTISAMPLEANTIALIAS: + case D3DRS_INDEXEDVERTEXBLENDENABLE: + name = value ? "TRUE" : "FALSE"; + break; + + case D3DRS_SRCBLEND: + case D3DRS_DESTBLEND: + name = Get_DX8_Blend_Name(value); + break; + + case D3DRS_CULLMODE: + name = Get_DX8_Cull_Mode_Name(value); + break; + + case D3DRS_ZFUNC: + case D3DRS_ALPHAFUNC: + case D3DRS_STENCILFUNC: + name = Get_DX8_Cmp_Func_Name(value); + break; + + case D3DRS_ZVISIBLE: + name = "NOTSUPPORTED"; + break; + + case D3DRS_FOGTABLEMODE: + case D3DRS_FOGVERTEXMODE: + name = Get_DX8_Fog_Mode_Name(value); + break; + + case D3DRS_FOGSTART: + case D3DRS_FOGEND: + case D3DRS_FOGDENSITY: + case D3DRS_POINTSIZE: + case D3DRS_POINTSIZE_MIN: + case D3DRS_POINTSCALE_A: + case D3DRS_POINTSCALE_B: + case D3DRS_POINTSCALE_C: + case D3DRS_PATCHSEGMENTS: + case D3DRS_POINTSIZE_MAX: + case D3DRS_TWEENFACTOR: + name.Format("%f", *(float*)&value); + break; + + case D3DRS_ZBIAS: + case D3DRS_STENCILREF: + name.Format("%d", value); + break; + + case D3DRS_STENCILFAIL: + case D3DRS_STENCILZFAIL: + case D3DRS_STENCILPASS: + name = Get_DX8_Stencil_Op_Name(value); + break; + + case D3DRS_WRAP0: + case D3DRS_WRAP1: + case D3DRS_WRAP2: + case D3DRS_WRAP3: + case D3DRS_WRAP4: + case D3DRS_WRAP5: + case D3DRS_WRAP6: + case D3DRS_WRAP7: + name = "0"; + if (value & D3DWRAP_U) name += "|D3DWRAP_U"; + if (value & D3DWRAP_V) name += "|D3DWRAP_V"; + if (value & D3DWRAP_W) name += "|D3DWRAP_W"; + break; + + case D3DRS_DIFFUSEMATERIALSOURCE: + case D3DRS_SPECULARMATERIALSOURCE: + case D3DRS_AMBIENTMATERIALSOURCE: + case D3DRS_EMISSIVEMATERIALSOURCE: + name = Get_DX8_Material_Source_Name(value); + break; + + case D3DRS_VERTEXBLEND: + name = Get_DX8_Vertex_Blend_Flag_Name(value); + break; + + case D3DRS_PATCHEDGESTYLE: + name = Get_DX8_Patch_Edge_Style_Name(value); + break; + + case D3DRS_DEBUGMONITORTOKEN: + name = Get_DX8_Debug_Monitor_Token_Name(value); + break; + + case D3DRS_COLORWRITEENABLE: + name = "0"; + if (value & D3DCOLORWRITEENABLE_RED) name += "|D3DCOLORWRITEENABLE_RED"; + if (value & D3DCOLORWRITEENABLE_GREEN) name += "|D3DCOLORWRITEENABLE_GREEN"; + if (value & D3DCOLORWRITEENABLE_BLUE) name += "|D3DCOLORWRITEENABLE_BLUE"; + if (value & D3DCOLORWRITEENABLE_ALPHA) name += "|D3DCOLORWRITEENABLE_ALPHA"; + break; + case D3DRS_BLENDOP: + name = Get_DX8_Blend_Op_Name(value); + break; + default: + name.Format("UNKNOWN (%d)", value); + break; + } +} + +void DX8Wrapper::Get_DX8_Texture_Stage_State_Value_Name(StringClass& name, D3DTEXTURESTAGESTATETYPE state, unsigned value) +{ + switch (state) { + case D3DTSS_COLOROP: + case D3DTSS_ALPHAOP: + name = Get_DX8_Texture_Op_Name(value); + break; + + case D3DTSS_COLORARG0: + case D3DTSS_COLORARG1: + case D3DTSS_COLORARG2: + case D3DTSS_ALPHAARG0: + case D3DTSS_ALPHAARG1: + case D3DTSS_ALPHAARG2: + case D3DTSS_RESULTARG: + name = Get_DX8_Texture_Arg_Name(value); + break; + + case D3DTSS_ADDRESSU: + case D3DTSS_ADDRESSV: + case D3DTSS_ADDRESSW: + name = Get_DX8_Texture_Address_Name(value); + break; + + case D3DTSS_MAGFILTER: + case D3DTSS_MINFILTER: + case D3DTSS_MIPFILTER: + name = Get_DX8_Texture_Filter_Name(value); + break; + + case D3DTSS_TEXTURETRANSFORMFLAGS: + name = Get_DX8_Texture_Transform_Flag_Name(value); + break; + + // Floating point values + case D3DTSS_MIPMAPLODBIAS: + case D3DTSS_BUMPENVMAT00: + case D3DTSS_BUMPENVMAT01: + case D3DTSS_BUMPENVMAT10: + case D3DTSS_BUMPENVMAT11: + case D3DTSS_BUMPENVLSCALE: + case D3DTSS_BUMPENVLOFFSET: + name.Format("%f", *(float*)&value); + break; + + case D3DTSS_TEXCOORDINDEX: + if ((value & 0xffff0000) == D3DTSS_TCI_CAMERASPACENORMAL) { + name.Format("D3DTSS_TCI_CAMERASPACENORMAL|%d", value & 0xffff); + } + else if ((value & 0xffff0000) == D3DTSS_TCI_CAMERASPACEPOSITION) { + name.Format("D3DTSS_TCI_CAMERASPACEPOSITION|%d", value & 0xffff); + } + else if ((value & 0xffff0000) == D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR) { + name.Format("D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR|%d", value & 0xffff); + } + else { + name.Format("%d", value); + } + break; + + // Integer value + case D3DTSS_MAXMIPLEVEL: + case D3DTSS_MAXANISOTROPY: + name.Format("%d", value); + break; + // Hex values + case D3DTSS_BORDERCOLOR: + name.Format("0x%x", value); + break; + + default: + name.Format("UNKNOWN (%d)", value); + break; + } +} + +const char* DX8Wrapper::Get_DX8_Texture_Op_Name(unsigned value) +{ + switch (value) { + case D3DTOP_DISABLE: return "D3DTOP_DISABLE"; + case D3DTOP_SELECTARG1: return "D3DTOP_SELECTARG1"; + case D3DTOP_SELECTARG2: return "D3DTOP_SELECTARG2"; + case D3DTOP_MODULATE: return "D3DTOP_MODULATE"; + case D3DTOP_MODULATE2X: return "D3DTOP_MODULATE2X"; + case D3DTOP_MODULATE4X: return "D3DTOP_MODULATE4X"; + case D3DTOP_ADD: return "D3DTOP_ADD"; + case D3DTOP_ADDSIGNED: return "D3DTOP_ADDSIGNED"; + case D3DTOP_ADDSIGNED2X: return "D3DTOP_ADDSIGNED2X"; + case D3DTOP_SUBTRACT: return "D3DTOP_SUBTRACT"; + case D3DTOP_ADDSMOOTH: return "D3DTOP_ADDSMOOTH"; + case D3DTOP_BLENDDIFFUSEALPHA: return "D3DTOP_BLENDDIFFUSEALPHA"; + case D3DTOP_BLENDTEXTUREALPHA: return "D3DTOP_BLENDTEXTUREALPHA"; + case D3DTOP_BLENDFACTORALPHA: return "D3DTOP_BLENDFACTORALPHA"; + case D3DTOP_BLENDTEXTUREALPHAPM: return "D3DTOP_BLENDTEXTUREALPHAPM"; + case D3DTOP_BLENDCURRENTALPHA: return "D3DTOP_BLENDCURRENTALPHA"; + case D3DTOP_PREMODULATE: return "D3DTOP_PREMODULATE"; + case D3DTOP_MODULATEALPHA_ADDCOLOR: return "D3DTOP_MODULATEALPHA_ADDCOLOR"; + case D3DTOP_MODULATECOLOR_ADDALPHA: return "D3DTOP_MODULATECOLOR_ADDALPHA"; + case D3DTOP_MODULATEINVALPHA_ADDCOLOR: return "D3DTOP_MODULATEINVALPHA_ADDCOLOR"; + case D3DTOP_MODULATEINVCOLOR_ADDALPHA: return "D3DTOP_MODULATEINVCOLOR_ADDALPHA"; + case D3DTOP_BUMPENVMAP: return "D3DTOP_BUMPENVMAP"; + case D3DTOP_BUMPENVMAPLUMINANCE: return "D3DTOP_BUMPENVMAPLUMINANCE"; + case D3DTOP_DOTPRODUCT3: return "D3DTOP_DOTPRODUCT3"; + case D3DTOP_MULTIPLYADD: return "D3DTOP_MULTIPLYADD"; + case D3DTOP_LERP: return "D3DTOP_LERP"; + default: return "UNKNOWN"; + } +} + +const char* DX8Wrapper::Get_DX8_Texture_Arg_Name(unsigned value) +{ + switch (value) { + case D3DTA_CURRENT: return "D3DTA_CURRENT"; + case D3DTA_DIFFUSE: return "D3DTA_DIFFUSE"; + case D3DTA_SELECTMASK: return "D3DTA_SELECTMASK"; + case D3DTA_SPECULAR: return "D3DTA_SPECULAR"; + case D3DTA_TEMP: return "D3DTA_TEMP"; + case D3DTA_TEXTURE: return "D3DTA_TEXTURE"; + case D3DTA_TFACTOR: return "D3DTA_TFACTOR"; + case D3DTA_ALPHAREPLICATE: return "D3DTA_ALPHAREPLICATE"; + case D3DTA_COMPLEMENT: return "D3DTA_COMPLEMENT"; + default: return "UNKNOWN"; + } +} + +const char* DX8Wrapper::Get_DX8_Texture_Filter_Name(unsigned value) +{ + switch (value) { + case D3DTEXF_NONE: return "D3DTEXF_NONE"; + case D3DTEXF_POINT: return "D3DTEXF_POINT"; + case D3DTEXF_LINEAR: return "D3DTEXF_LINEAR"; + case D3DTEXF_ANISOTROPIC: return "D3DTEXF_ANISOTROPIC"; + case D3DTEXF_FLATCUBIC: return "D3DTEXF_FLATCUBIC"; + case D3DTEXF_GAUSSIANCUBIC: return "D3DTEXF_GAUSSIANCUBIC"; + default: return "UNKNOWN"; + } +} + +const char* DX8Wrapper::Get_DX8_Texture_Address_Name(unsigned value) +{ + switch (value) { + case D3DTADDRESS_WRAP: return "D3DTADDRESS_WRAP"; + case D3DTADDRESS_MIRROR: return "D3DTADDRESS_MIRROR"; + case D3DTADDRESS_CLAMP: return "D3DTADDRESS_CLAMP"; + case D3DTADDRESS_BORDER: return "D3DTADDRESS_BORDER"; + case D3DTADDRESS_MIRRORONCE: return "D3DTADDRESS_MIRRORONCE"; + default: return "UNKNOWN"; + } +} + +const char* DX8Wrapper::Get_DX8_Texture_Transform_Flag_Name(unsigned value) +{ + switch (value) { + case D3DTTFF_DISABLE: return "D3DTTFF_DISABLE"; + case D3DTTFF_COUNT1: return "D3DTTFF_COUNT1"; + case D3DTTFF_COUNT2: return "D3DTTFF_COUNT2"; + case D3DTTFF_COUNT3: return "D3DTTFF_COUNT3"; + case D3DTTFF_COUNT4: return "D3DTTFF_COUNT4"; + case D3DTTFF_PROJECTED: return "D3DTTFF_PROJECTED"; + default: return "UNKNOWN"; + } +} + +const char* DX8Wrapper::Get_DX8_ZBuffer_Type_Name(unsigned value) +{ + switch (value) { + case D3DZB_FALSE: return "D3DZB_FALSE"; + case D3DZB_TRUE: return "D3DZB_TRUE"; + case D3DZB_USEW: return "D3DZB_USEW"; + default: return "UNKNOWN"; + } +} + +const char* DX8Wrapper::Get_DX8_Fill_Mode_Name(unsigned value) +{ + switch (value) { + case D3DFILL_POINT: return "D3DFILL_POINT"; + case D3DFILL_WIREFRAME: return "D3DFILL_WIREFRAME"; + case D3DFILL_SOLID: return "D3DFILL_SOLID"; + default: return "UNKNOWN"; + } +} + +const char* DX8Wrapper::Get_DX8_Shade_Mode_Name(unsigned value) +{ + switch (value) { + case D3DSHADE_FLAT: return "D3DSHADE_FLAT"; + case D3DSHADE_GOURAUD: return "D3DSHADE_GOURAUD"; + case D3DSHADE_PHONG: return "D3DSHADE_PHONG"; + default: return "UNKNOWN"; + } +} + +const char* DX8Wrapper::Get_DX8_Blend_Name(unsigned value) +{ + switch (value) { + case D3DBLEND_ZERO: return "D3DBLEND_ZERO"; + case D3DBLEND_ONE: return "D3DBLEND_ONE"; + case D3DBLEND_SRCCOLOR: return "D3DBLEND_SRCCOLOR"; + case D3DBLEND_INVSRCCOLOR: return "D3DBLEND_INVSRCCOLOR"; + case D3DBLEND_SRCALPHA: return "D3DBLEND_SRCALPHA"; + case D3DBLEND_INVSRCALPHA: return "D3DBLEND_INVSRCALPHA"; + case D3DBLEND_DESTALPHA: return "D3DBLEND_DESTALPHA"; + case D3DBLEND_INVDESTALPHA: return "D3DBLEND_INVDESTALPHA"; + case D3DBLEND_DESTCOLOR: return "D3DBLEND_DESTCOLOR"; + case D3DBLEND_INVDESTCOLOR: return "D3DBLEND_INVDESTCOLOR"; + case D3DBLEND_SRCALPHASAT: return "D3DBLEND_SRCALPHASAT"; + case D3DBLEND_BOTHSRCALPHA: return "D3DBLEND_BOTHSRCALPHA"; + case D3DBLEND_BOTHINVSRCALPHA: return "D3DBLEND_BOTHINVSRCALPHA"; + default: return "UNKNOWN"; + } +} + +const char* DX8Wrapper::Get_DX8_Cull_Mode_Name(unsigned value) +{ + switch (value) { + case D3DCULL_NONE: return "D3DCULL_NONE"; + case D3DCULL_CW: return "D3DCULL_CW"; + case D3DCULL_CCW: return "D3DCULL_CCW"; + default: return "UNKNOWN"; + } +} + +const char* DX8Wrapper::Get_DX8_Cmp_Func_Name(unsigned value) +{ + switch (value) { + case D3DCMP_NEVER: return "D3DCMP_NEVER"; + case D3DCMP_LESS: return "D3DCMP_LESS"; + case D3DCMP_EQUAL: return "D3DCMP_EQUAL"; + case D3DCMP_LESSEQUAL: return "D3DCMP_LESSEQUAL"; + case D3DCMP_GREATER: return "D3DCMP_GREATER"; + case D3DCMP_NOTEQUAL: return "D3DCMP_NOTEQUAL"; + case D3DCMP_GREATEREQUAL: return "D3DCMP_GREATEREQUAL"; + case D3DCMP_ALWAYS: return "D3DCMP_ALWAYS"; + default: return "UNKNOWN"; + } +} + +const char* DX8Wrapper::Get_DX8_Fog_Mode_Name(unsigned value) +{ + switch (value) { + case D3DFOG_NONE: return "D3DFOG_NONE"; + case D3DFOG_EXP: return "D3DFOG_EXP"; + case D3DFOG_EXP2: return "D3DFOG_EXP2"; + case D3DFOG_LINEAR: return "D3DFOG_LINEAR"; + default: return "UNKNOWN"; + } +} + +const char* DX8Wrapper::Get_DX8_Stencil_Op_Name(unsigned value) +{ + switch (value) { + case D3DSTENCILOP_KEEP: return "D3DSTENCILOP_KEEP"; + case D3DSTENCILOP_ZERO: return "D3DSTENCILOP_ZERO"; + case D3DSTENCILOP_REPLACE: return "D3DSTENCILOP_REPLACE"; + case D3DSTENCILOP_INCRSAT: return "D3DSTENCILOP_INCRSAT"; + case D3DSTENCILOP_DECRSAT: return "D3DSTENCILOP_DECRSAT"; + case D3DSTENCILOP_INVERT: return "D3DSTENCILOP_INVERT"; + case D3DSTENCILOP_INCR: return "D3DSTENCILOP_INCR"; + case D3DSTENCILOP_DECR: return "D3DSTENCILOP_DECR"; + default: return "UNKNOWN"; + } +} + +const char* DX8Wrapper::Get_DX8_Material_Source_Name(unsigned value) +{ + switch (value) { + case D3DMCS_MATERIAL: return "D3DMCS_MATERIAL"; + case D3DMCS_COLOR1: return "D3DMCS_COLOR1"; + case D3DMCS_COLOR2: return "D3DMCS_COLOR2"; + default: return "UNKNOWN"; + } +} + +const char* DX8Wrapper::Get_DX8_Vertex_Blend_Flag_Name(unsigned value) +{ + switch (value) { + case D3DVBF_DISABLE: return "D3DVBF_DISABLE"; + case D3DVBF_1WEIGHTS: return "D3DVBF_1WEIGHTS"; + case D3DVBF_2WEIGHTS: return "D3DVBF_2WEIGHTS"; + case D3DVBF_3WEIGHTS: return "D3DVBF_3WEIGHTS"; + case D3DVBF_TWEENING: return "D3DVBF_TWEENING"; + case D3DVBF_0WEIGHTS: return "D3DVBF_0WEIGHTS"; + default: return "UNKNOWN"; + } +} + +const char* DX8Wrapper::Get_DX8_Patch_Edge_Style_Name(unsigned value) +{ + switch (value) { + case D3DPATCHEDGE_DISCRETE: return "D3DPATCHEDGE_DISCRETE"; + case D3DPATCHEDGE_CONTINUOUS:return "D3DPATCHEDGE_CONTINUOUS"; + default: return "UNKNOWN"; + } +} + +const char* DX8Wrapper::Get_DX8_Debug_Monitor_Token_Name(unsigned value) +{ + switch (value) { + case D3DDMT_ENABLE: return "D3DDMT_ENABLE"; + case D3DDMT_DISABLE: return "D3DDMT_DISABLE"; + default: return "UNKNOWN"; + } +} + +const char* DX8Wrapper::Get_DX8_Blend_Op_Name(unsigned value) +{ + switch (value) { + case D3DBLENDOP_ADD: return "D3DBLENDOP_ADD"; + case D3DBLENDOP_SUBTRACT: return "D3DBLENDOP_SUBTRACT"; + case D3DBLENDOP_REVSUBTRACT: return "D3DBLENDOP_REVSUBTRACT"; + case D3DBLENDOP_MIN: return "D3DBLENDOP_MIN"; + case D3DBLENDOP_MAX: return "D3DBLENDOP_MAX"; + default: return "UNKNOWN"; + } +} + + +//============================================================================ +// DX8Wrapper::getBackBufferFormat +//============================================================================ + +WW3DFormat DX8Wrapper::getBackBufferFormat(void) +{ + return D3DFormat_To_WW3DFormat(_PresentParameters.BackBufferFormat); +} +>>>>>>> 0122e54d (Setup proper linking) diff --git a/Core/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h b/Core/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h index 2c9291c9b6c..2a37598497f 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h +++ b/Core/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h @@ -1 +1,1520 @@ +<<<<<<< HEAD #include "../../Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_header_common.h" +======= +/* +** Command & Conquer Generals Zero Hour(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/dx8wrapper.h $* + * * + * Original Author:: Jani Penttinen * + * * + * Author : Kenny Mitchell * + * * + * $Modtime:: 08/05/02 2:40p $* + * * + * $Revision:: 92 $* + * * + * 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: * + * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +#if defined(_MSC_VER) +#pragma once +#endif + +#ifndef DX8_WRAPPER_H +#define DX8_WRAPPER_H + +#include "always.h" +#include "dllist.h" +#include "d3d8.h" +#include "matrix4.h" +#include "statistics.h" +#include "wwstring.h" +#include "lightenvironment.h" +#include "shader.h" +#include "vector4.h" +#include "cpudetect.h" +#include "dx8caps.h" + +#include "texture.h" +#include "dx8vertexbuffer.h" +#include "dx8indexbuffer.h" +#include "vertmaterial.h" + + /* + ** Registry value names + */ +#define VALUE_NAME_RENDER_DEVICE_NAME "RenderDeviceName" +#define VALUE_NAME_RENDER_DEVICE_WIDTH "RenderDeviceWidth" +#define VALUE_NAME_RENDER_DEVICE_HEIGHT "RenderDeviceHeight" +#define VALUE_NAME_RENDER_DEVICE_DEPTH "RenderDeviceDepth" +#define VALUE_NAME_RENDER_DEVICE_WINDOWED "RenderDeviceWindowed" +#define VALUE_NAME_RENDER_DEVICE_TEXTURE_DEPTH "RenderDeviceTextureDepth" + +const unsigned MAX_TEXTURE_STAGES = 8; +const unsigned MAX_VERTEX_STREAMS = 2; +const unsigned MAX_VERTEX_SHADER_CONSTANTS = 96; +const unsigned MAX_PIXEL_SHADER_CONSTANTS = 8; +const unsigned MAX_SHADOW_MAPS = 1; + +#define prevVer +#define nextVer + + +enum { + BUFFER_TYPE_DX8, + BUFFER_TYPE_SORTING, + BUFFER_TYPE_DYNAMIC_DX8, + BUFFER_TYPE_DYNAMIC_SORTING, + BUFFER_TYPE_INVALID +}; + +class VertexMaterialClass; +class CameraClass; +class LightEnvironmentClass; +class RenderDeviceDescClass; +class VertexBufferClass; +class DynamicVBAccessClass; +class IndexBufferClass; +class DynamicIBAccessClass; +class TextureClass; +class ZTextureClass; +class LightClass; +class SurfaceClass; +class DX8Caps; + +#define DX8_RECORD_MATRIX_CHANGE() matrix_changes++ +#define DX8_RECORD_MATERIAL_CHANGE() material_changes++ +#define DX8_RECORD_VERTEX_BUFFER_CHANGE() vertex_buffer_changes++ +#define DX8_RECORD_INDEX_BUFFER_CHANGE() index_buffer_changes++ +#define DX8_RECORD_LIGHT_CHANGE() light_changes++ +#define DX8_RECORD_TEXTURE_CHANGE() texture_changes++ +#define DX8_RECORD_RENDER_STATE_CHANGE() render_state_changes++ +#define DX8_RECORD_TEXTURE_STAGE_STATE_CHANGE() texture_stage_state_changes++ +#define DX8_RECORD_DRAW_CALLS() draw_calls++ + +extern unsigned number_of_DX8_calls; +extern bool _DX8SingleThreaded; + +void DX8_Assert(); +void Log_DX8_ErrorCode(unsigned res); + +WWINLINE void DX8_ErrorCode(unsigned res) +{ + if (res == D3D_OK) return; + Log_DX8_ErrorCode(res); +} + +#ifdef WWDEBUG +#define DX8CALL_HRES(x,res) DX8_Assert(); res = DX8Wrapper::_Get_D3D_Device8()->x; DX8_ErrorCode(res); number_of_DX8_calls++; +#define DX8CALL(x) DX8_Assert(); DX8_ErrorCode(DX8Wrapper::_Get_D3D_Device8()->x); number_of_DX8_calls++; +#define DX8CALL_D3D(x) DX8_Assert(); DX8_ErrorCode(DX8Wrapper::_Get_D3D8()->x); number_of_DX8_calls++; +#define DX8_THREAD_ASSERT() if (_DX8SingleThreaded) { WWASSERT_PRINT(DX8Wrapper::_Get_Main_Thread_ID()==ThreadClass::_Get_Current_Thread_ID(),"DX8Wrapper::DX8 calls must be called from the main thread!"); } +#else +#define DX8CALL_HRES(x,res) res = DX8Wrapper::_Get_D3D_Device8()->x; number_of_DX8_calls++; +#define DX8CALL(x) DX8Wrapper::_Get_D3D_Device8()->x; number_of_DX8_calls++; +#define DX8CALL_D3D(x) DX8Wrapper::_Get_D3D8()->x; number_of_DX8_calls++; +#define DX8_THREAD_ASSERT() ; +#endif + + +#define no_EXTENDED_STATS +// EXTENDED_STATS collects additional timing statistics by turning off parts +// of the 3D drawing system (terrain, objects, etc.) +#ifdef EXTENDED_STATS +class DX8_Stats +{ +public: + bool m_showingStats; + bool m_disableTerrain; + bool m_disableWater; + bool m_disableObjects; + bool m_disableOverhead; + bool m_disableConsole; + int m_debugLinesToShow; + int m_sleepTime; +public: + DX8_Stats::DX8_Stats(void) { + m_disableConsole = m_showingStats = m_disableTerrain = m_disableWater = m_disableOverhead = m_disableObjects = false; + m_sleepTime = 0; + m_debugLinesToShow = -1; // -1 means show all expected lines of output + } +}; +#endif + + +// This virtual interface was added for the Generals RTS. +// It is called before resetting the dx8 device to ensure +// that all dx8 resources are released. Otherwise reset fails. jba. +class DX8_CleanupHook +{ +public: + virtual void ReleaseResources(void) = 0; + virtual void ReAcquireResources(void) = 0; +}; + + +struct RenderStateStruct +{ + ShaderClass shader; + VertexMaterialClass* material; + TextureBaseClass* Textures[MAX_TEXTURE_STAGES]; + D3DLIGHT8 Lights[4]; + bool LightEnable[4]; + //unsigned lightsHash; + Matrix4x4 world; + Matrix4x4 view; + unsigned vertex_buffer_types[MAX_VERTEX_STREAMS]; + unsigned index_buffer_type; + unsigned short vba_offset; + unsigned short vba_count; + unsigned short iba_offset; + VertexBufferClass* vertex_buffers[MAX_VERTEX_STREAMS]; + IndexBufferClass* index_buffer; + unsigned short index_base_offset; + + RenderStateStruct(); + ~RenderStateStruct(); + + RenderStateStruct& operator= (const RenderStateStruct& src); +}; + +/** +** DX8Wrapper +** +** DX8 interface wrapper class. This encapsulates the DX8 interface; adding redundant state +** detection, stat tracking, etc etc. In general, we will wrap all DX8 calls with at least +** an WWINLINE function so that we can add stat tracking, etc if needed. Direct access to the +** D3D device will require "friend" status and should be granted only in extreme circumstances :-) +*/ +class DX8Wrapper +{ + enum ChangedStates { + WORLD_CHANGED = 1 << 0, + VIEW_CHANGED = 1 << 1, + LIGHT0_CHANGED = 1 << 2, + LIGHT1_CHANGED = 1 << 3, + LIGHT2_CHANGED = 1 << 4, + LIGHT3_CHANGED = 1 << 5, + TEXTURE0_CHANGED = 1 << 6, + TEXTURE1_CHANGED = 1 << 7, + TEXTURE2_CHANGED = 1 << 8, + TEXTURE3_CHANGED = 1 << 9, + MATERIAL_CHANGED = 1 << 14, + SHADER_CHANGED = 1 << 15, + VERTEX_BUFFER_CHANGED = 1 << 16, + INDEX_BUFFER_CHANGED = 1 << 17, + WORLD_IDENTITY = 1 << 18, + VIEW_IDENTITY = 1 << 19, + + TEXTURES_CHANGED = + TEXTURE0_CHANGED | TEXTURE1_CHANGED | TEXTURE2_CHANGED | TEXTURE3_CHANGED, + LIGHTS_CHANGED = + LIGHT0_CHANGED | LIGHT1_CHANGED | LIGHT2_CHANGED | LIGHT3_CHANGED, + }; + + static void Draw_Sorting_IB_VB( + unsigned primitive_type, + unsigned short start_index, + unsigned short polygon_count, + unsigned short min_vertex_index, + unsigned short vertex_count); + + static void Draw( + unsigned primitive_type, + unsigned short start_index, + unsigned short polygon_count, + unsigned short min_vertex_index = 0, + unsigned short vertex_count = 0); + +public: +#ifdef EXTENDED_STATS + static DX8_Stats stats; +#endif + + static bool Init(void* hwnd, bool lite = false); + static void Shutdown(void); + + static void SetCleanupHook(DX8_CleanupHook* pCleanupHook) { m_pCleanupHook = pCleanupHook; }; + /* + ** Some WW3D sub-systems need to be initialized after the device is created and shutdown + ** before the device is released. + */ + static void Do_Onetime_Device_Dependent_Inits(void); + static void Do_Onetime_Device_Dependent_Shutdowns(void); + + static bool Is_Device_Lost() { return IsDeviceLost; } + static bool Is_Initted(void) { return IsInitted; } + + static bool Has_Stencil(void); + static void Get_Format_Name(unsigned int format, StringClass* tex_format); + + /* + ** Rendering + */ + static void Begin_Scene(void); + static void End_Scene(bool flip_frame = true); + + // Flip until the primary buffer is visible. + static void Flip_To_Primary(void); + + static void Clear(bool clear_color, bool clear_z_stencil, const Vector3& color, float dest_alpha = 0.0f, float z = 1.0f, unsigned int stencil = 0); + + static void Set_Viewport(CONST D3DVIEWPORT8* pViewport); + + static void Set_Vertex_Buffer(const VertexBufferClass* vb, unsigned stream = 0); + static void Set_Vertex_Buffer(const DynamicVBAccessClass& vba); + static void Set_Index_Buffer(const IndexBufferClass* ib, unsigned short index_base_offset); + static void Set_Index_Buffer(const DynamicIBAccessClass& iba, unsigned short index_base_offset); + static void Set_Index_Buffer_Index_Offset(unsigned offset); + + static void Get_Render_State(RenderStateStruct& state); + static void Set_Render_State(const RenderStateStruct& state); + static void Release_Render_State(); + + static void Set_DX8_Material(const D3DMATERIAL8* mat); + + static void Set_Gamma(float gamma, float bright, float contrast, bool calibrate = true, bool uselimit = true); + + // Set_ and Get_Transform() functions take the matrix in Westwood convention format. + + static void Set_DX8_ZBias(int zbias); + static void Set_Projection_Transform_With_Z_Bias(const Matrix4x4& matrix, float znear, float zfar); // pointer to 16 matrices + + static void Set_Transform(D3DTRANSFORMSTATETYPE transform, const Matrix4x4& m); + static void Set_Transform(D3DTRANSFORMSTATETYPE transform, const Matrix3D& m); + static void Get_Transform(D3DTRANSFORMSTATETYPE transform, Matrix4x4& m); + static void Set_World_Identity(); + static void Set_View_Identity(); + static bool Is_World_Identity(); + static bool Is_View_Identity(); + + // Note that *_DX8_Transform() functions take the matrix in DX8 format - transposed from Westwood convention. + + static void _Set_DX8_Transform(D3DTRANSFORMSTATETYPE transform, const Matrix4x4& m); + static void _Set_DX8_Transform(D3DTRANSFORMSTATETYPE transform, const Matrix3D& m); + static void _Get_DX8_Transform(D3DTRANSFORMSTATETYPE transform, Matrix4x4& m); + + static void Set_DX8_Light(int index, D3DLIGHT8* light); + static void Set_DX8_Render_State(D3DRENDERSTATETYPE state, unsigned value); + static void Set_DX8_Clip_Plane(DWORD Index, CONST float* pPlane); + static void Set_DX8_Texture_Stage_State(unsigned stage, D3DTEXTURESTAGESTATETYPE state, unsigned value); + static void Set_DX8_Texture(unsigned int stage, IDirect3DBaseTexture8* texture); + static void Set_Light_Environment(LightEnvironmentClass* light_env); + static LightEnvironmentClass* Get_Light_Environment() { return Light_Environment; } + static void Set_Fog(bool enable, const Vector3& color, float start, float end); + + static WWINLINE const D3DLIGHT8& Peek_Light(unsigned index); + static WWINLINE bool Is_Light_Enabled(unsigned index); + + static bool Validate_Device(void); + + // Deferred + + static void Set_Shader(const ShaderClass& shader); + static void Get_Shader(ShaderClass& shader); + static void Set_Texture(unsigned stage, TextureBaseClass* texture); + static void Set_Material(const VertexMaterialClass* material); + static void Set_Light(unsigned index, const D3DLIGHT8* light); + static void Set_Light(unsigned index, const LightClass& light); + + static void Apply_Render_State_Changes(); // Apply deferred render state changes (will be called automatically by Draw...) + + static void Draw_Triangles( + unsigned buffer_type, + unsigned short start_index, + unsigned short polygon_count, + unsigned short min_vertex_index, + unsigned short vertex_count); + static void Draw_Triangles( + unsigned short start_index, + unsigned short polygon_count, + unsigned short min_vertex_index, + unsigned short vertex_count); + static void Draw_Strip( + unsigned short start_index, + unsigned short index_count, + unsigned short min_vertex_index, + unsigned short vertex_count); + + /* + ** 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, + unsigned int height, + WW3DFormat format, + MipCountType mip_level_count, + D3DPOOL pool = D3DPOOL_MANAGED, + bool rendertarget = false + ); + static IDirect3DTexture8* _Create_DX8_Texture(const char* filename, MipCountType mip_level_count); + static IDirect3DTexture8* _Create_DX8_Texture(IDirect3DSurface8* surface, MipCountType mip_level_count); + + static IDirect3DSurface8* _Create_DX8_Surface(unsigned int width, unsigned int height, WW3DFormat format); + static IDirect3DSurface8* _Create_DX8_Surface(const char* filename); + static IDirect3DSurface8* _Get_DX8_Front_Buffer(); + static SurfaceClass* _Get_DX8_Back_Buffer(unsigned int num = 0); + + static void _Copy_DX8_Rects( + IDirect3DSurface8* pSourceSurface, + CONST RECT* pSourceRectsArray, + UINT cRects, + IDirect3DSurface8* pDestinationSurface, + CONST POINT* pDestPointsArray + ); + + static void _Update_Texture(TextureClass* system, TextureClass* video); + static void Flush_DX8_Resource_Manager(unsigned int bytes = 0); + static unsigned int Get_Free_Texture_RAM(); + + static unsigned _Get_Main_Thread_ID() { return _MainThreadID; } + static const D3DADAPTER_IDENTIFIER8& Get_Current_Adapter_Identifier() { return CurrentAdapterIdentifier; } + + /* + ** Statistics + */ + static void Begin_Statistics(); + static void End_Statistics(); + static unsigned Get_Last_Frame_Matrix_Changes(); + static unsigned Get_Last_Frame_Material_Changes(); + static unsigned Get_Last_Frame_Vertex_Buffer_Changes(); + static unsigned Get_Last_Frame_Index_Buffer_Changes(); + static unsigned Get_Last_Frame_Light_Changes(); + static unsigned Get_Last_Frame_Texture_Changes(); + static unsigned Get_Last_Frame_Render_State_Changes(); + static unsigned Get_Last_Frame_Texture_Stage_State_Changes(); + static unsigned Get_Last_Frame_DX8_Calls(); + static unsigned Get_Last_Frame_Draw_Calls(); + + static unsigned long Get_FrameCount(void); + + // Needed by shader class + static bool Get_Fog_Enable() { return FogEnable; } + static D3DCOLOR Get_Fog_Color() { return FogColor; } + + // Utilities + static Vector4 Convert_Color(unsigned color); + static unsigned int Convert_Color(const Vector4& color); + static unsigned int Convert_Color(const Vector3& color, const float alpha); + static void Clamp_Color(Vector4& color); + static unsigned int Convert_Color_Clamp(const Vector4& color); + + static void Set_Alpha(const float alpha, unsigned int& color); + + static void _Enable_Triangle_Draw(bool enable) { _EnableTriangleDraw = enable; } + static bool _Is_Triangle_Draw_Enabled() { return _EnableTriangleDraw; } + + /* + ** Additional swap chain interface + ** + ** Use this interface to render to multiple windows (in windowed mode). + ** To render to an additional window, the sequence of calls should look + ** something like this: + ** + ** DX8Wrapper::Set_Render_Target (swap_chain_ptr); + ** + ** WW3D::Begin_Render (true, true, Vector3 (0, 0, 0)); + ** WW3D::Render (scene, camera, FALSE, FALSE); + ** WW3D::End_Render (); + ** + ** swap_chain_ptr->Present (NULL, NULL, NULL, NULL); + ** + ** DX8Wrapper::Set_Render_Target ((IDirect3DSurface8 *)NULL); + ** + */ + static IDirect3DSwapChain8* Create_Additional_Swap_Chain(HWND render_window); + + /* + ** 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, 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(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(); + + static void Set_Vertex_Shader(DWORD vertex_shader); + static void Set_Pixel_Shader(DWORD pixel_shader); + + static void Set_Vertex_Shader_Constant(int reg, const void* data, int count); + static void Set_Pixel_Shader_Constant(int reg, const void* data, int count); + + static DWORD Get_Vertex_Processing_Behavior() { return Vertex_Processing_Behavior; } + + // Needed by scene lighting class + static void Set_Ambient(const Vector3& color); + static const Vector3& Get_Ambient() { return Ambient_Color; } + // shader system updates KJM ^ + + + + + static IDirect3DDevice8* _Get_D3D_Device8() { return D3DDevice; } + static IDirect3D8* _Get_D3D8() { return D3DInterface; } + /// Returns the display format - added by TR for video playback - not part of W3D + static WW3DFormat getBackBufferFormat(void); + static bool Reset_Device(bool reload_assets = true); + + static const DX8Caps* Get_Current_Caps() { WWASSERT(CurrentCaps); return CurrentCaps; } + + static bool Registry_Save_Render_Device(const char* sub_key); + static bool Registry_Load_Render_Device(const char* sub_key, bool resize_window); + + static const char* Get_DX8_Render_State_Name(D3DRENDERSTATETYPE state); + static const char* Get_DX8_Texture_Stage_State_Name(D3DTEXTURESTAGESTATETYPE state); + static unsigned Get_DX8_Render_State(D3DRENDERSTATETYPE state) { return RenderStates[state]; } + + // Names of the specific values of render states and texture stage states + static void Get_DX8_Texture_Stage_State_Value_Name(StringClass& name, D3DTEXTURESTAGESTATETYPE state, unsigned value); + static void Get_DX8_Render_State_Value_Name(StringClass& name, D3DRENDERSTATETYPE state, unsigned value); + + static const char* Get_DX8_Texture_Address_Name(unsigned value); + static const char* Get_DX8_Texture_Filter_Name(unsigned value); + static const char* Get_DX8_Texture_Arg_Name(unsigned value); + static const char* Get_DX8_Texture_Op_Name(unsigned value); + static const char* Get_DX8_Texture_Transform_Flag_Name(unsigned value); + static const char* Get_DX8_ZBuffer_Type_Name(unsigned value); + static const char* Get_DX8_Fill_Mode_Name(unsigned value); + static const char* Get_DX8_Shade_Mode_Name(unsigned value); + static const char* Get_DX8_Blend_Name(unsigned value); + static const char* Get_DX8_Cull_Mode_Name(unsigned value); + static const char* Get_DX8_Cmp_Func_Name(unsigned value); + static const char* Get_DX8_Fog_Mode_Name(unsigned value); + static const char* Get_DX8_Stencil_Op_Name(unsigned value); + static const char* Get_DX8_Material_Source_Name(unsigned value); + static const char* Get_DX8_Vertex_Blend_Flag_Name(unsigned value); + static const char* Get_DX8_Patch_Edge_Style_Name(unsigned value); + static const char* Get_DX8_Debug_Monitor_Token_Name(unsigned value); + static const char* Get_DX8_Blend_Op_Name(unsigned value); + + static void Invalidate_Cached_Render_States(void); + + static void Set_Draw_Polygon_Low_Bound_Limit(unsigned n) { DrawPolygonLowBoundLimit = n; } + +protected: + + static bool Create_Device(void); + static void Release_Device(void); + + static void Reset_Statistics(); + static void Enumerate_Devices(); + static void Set_Default_Global_Render_States(void); + + /* + ** Device Selection Code. + ** For backward compatibility, the public interface for these functions is in the ww3d. + ** header file. These functions are protected so that we aren't exposing two interfaces. + */ + static bool Set_Any_Render_Device(void); + static bool Set_Render_Device(const char* dev_name, int width = -1, int height = -1, int bits = -1, int windowed = -1, bool resize_window = false); + static bool Set_Render_Device(int dev = -1, int resx = -1, int resy = -1, int bits = -1, int windowed = -1, bool resize_window = false, bool reset_device = false, bool restore_assets = true); + static bool Set_Next_Render_Device(void); + static bool Toggle_Windowed(void); + + static int Get_Render_Device_Count(void); + static int Get_Render_Device(void); + static const RenderDeviceDescClass& Get_Render_Device_Desc(int deviceidx); + static const char* Get_Render_Device_Name(int device_index); + static bool Set_Device_Resolution(int width = -1, int height = -1, int bits = -1, int windowed = -1, bool resize_window = false); + static void Get_Device_Resolution(int& set_w, int& set_h, int& set_bits, bool& set_windowed); + static void Get_Render_Target_Resolution(int& set_w, int& set_h, int& set_bits, bool& set_windowed); + static int Get_Device_Resolution_Width(void) { return ResolutionWidth; } + static int Get_Device_Resolution_Height(void) { return ResolutionHeight; } + + static bool Registry_Save_Render_Device(const char* sub_key, int device, int width, int height, int depth, bool windowed, int texture_depth); + static bool Registry_Load_Render_Device(const char* sub_key, char* device, int device_len, int& width, int& height, int& depth, int& windowed, int& texture_depth); + static bool Is_Windowed(void) { return IsWindowed; } + + static void Set_Texture_Bitdepth(int depth) { WWASSERT(depth == 16 || depth == 32); TextureBitDepth = depth; } + static int Get_Texture_Bitdepth(void) { return TextureBitDepth; } + + static void Set_Swap_Interval(int swap); + static int Get_Swap_Interval(void); + static void Set_Polygon_Mode(int mode); + + /* + ** Internal functions + */ + static void Resize_And_Position_Window(); + static bool Find_Color_And_Z_Mode(int resx, int resy, int bitdepth, D3DFORMAT* set_colorbuffer, D3DFORMAT* set_backbuffer, D3DFORMAT* set_zmode); + static bool Find_Color_Mode(D3DFORMAT colorbuffer, int resx, int resy, UINT* mode); + static bool Find_Z_Mode(D3DFORMAT colorbuffer, D3DFORMAT backbuffer, D3DFORMAT* zmode); + static bool Test_Z_Mode(D3DFORMAT colorbuffer, D3DFORMAT backbuffer, D3DFORMAT zmode); + static void Compute_Caps(WW3DFormat display_format); + + /* + ** Protected Member Variables + */ + + static DX8_CleanupHook* m_pCleanupHook; + + static RenderStateStruct render_state; + static unsigned render_state_changed; + static Matrix4x4 DX8Transforms[D3DTS_WORLD + 1]; + + static bool IsInitted; + static bool IsDeviceLost; + static void* Hwnd; + static unsigned _MainThreadID; + + static bool _EnableTriangleDraw; + + static int CurRenderDevice; + static int ResolutionWidth; + static int ResolutionHeight; + static int BitDepth; + static int TextureBitDepth; + static bool IsWindowed; + static D3DFORMAT DisplayFormat; + + static D3DMATRIX old_world; + static D3DMATRIX old_view; + static D3DMATRIX old_prj; + + // shader system updates KJM v + static DWORD Vertex_Shader; + static DWORD Pixel_Shader; + + static Vector4 Vertex_Shader_Constants[MAX_VERTEX_SHADER_CONSTANTS]; + static Vector4 Pixel_Shader_Constants[MAX_PIXEL_SHADER_CONSTANTS]; + + static LightEnvironmentClass* Light_Environment; + static RenderInfoClass* Render_Info; + + static DWORD Vertex_Processing_Behavior; + + static ZTextureClass* Shadow_Map[MAX_SHADOW_MAPS]; + + static Vector3 Ambient_Color; + // shader system updates KJM ^ + + static bool world_identity; + static unsigned RenderStates[256]; + static unsigned TextureStageStates[MAX_TEXTURE_STAGES][32]; + static IDirect3DBaseTexture8* Textures[MAX_TEXTURE_STAGES]; + + // These fog settings are constant for all objects in a given scene, + // unlike the matching renderstates which vary based on shader settings. + static bool FogEnable; + static D3DCOLOR FogColor; + + static unsigned matrix_changes; + static unsigned material_changes; + static unsigned vertex_buffer_changes; + static unsigned index_buffer_changes; + static unsigned light_changes; + static unsigned texture_changes; + static unsigned render_state_changes; + static unsigned texture_stage_state_changes; + static unsigned draw_calls; + static bool CurrentDX8LightEnables[4]; + + static unsigned long FrameCount; + + static DX8Caps* CurrentCaps; + + static D3DADAPTER_IDENTIFIER8 CurrentAdapterIdentifier; + + static IDirect3D8* D3DInterface; //d3d8; + static IDirect3DDevice8* D3DDevice; //d3ddevice8; + + static IDirect3DSurface8* CurrentRenderTarget; + static IDirect3DSurface8* CurrentDepthBuffer; + static IDirect3DSurface8* DefaultRenderTarget; + static IDirect3DSurface8* DefaultDepthBuffer; + + static unsigned DrawPolygonLowBoundLimit; + + static bool IsRenderToTexture; + + static int ZBias; + static float ZNear; + static float ZFar; + static Matrix4x4 ProjectionMatrix; + + friend void DX8_Assert(); + friend class WW3D; + friend class DX8IndexBufferClass; + friend class DX8VertexBufferClass; +}; + +// shader system updates KJM v +WWINLINE void DX8Wrapper::Set_Vertex_Shader(DWORD vertex_shader) +{ +#if 0 //(gth) some code is bypassing this acessor function so we can't count on this variable... + // may be incorrect if shaders are created and destroyed dynamically + if (Vertex_Shader == vertex_shader) return; +#endif + + Vertex_Shader = vertex_shader; + DX8CALL(SetVertexShader(Vertex_Shader)); +} + +WWINLINE void DX8Wrapper::Set_Pixel_Shader(DWORD pixel_shader) +{ + // may be incorrect if shaders are created and destroyed dynamically + if (Pixel_Shader == pixel_shader) return; + + Pixel_Shader = pixel_shader; + DX8CALL(SetPixelShader(Pixel_Shader)); +} + +WWINLINE void DX8Wrapper::Set_Vertex_Shader_Constant(int reg, const void* data, int count) +{ + int memsize = sizeof(Vector4) * count; + + // may be incorrect if shaders are created and destroyed dynamically + if (memcmp(data, &Vertex_Shader_Constants[reg], memsize) == 0) return; + + memcpy(&Vertex_Shader_Constants[reg], data, memsize); + DX8CALL(SetVertexShaderConstant(reg, data, count)); +} + +WWINLINE void DX8Wrapper::Set_Pixel_Shader_Constant(int reg, const void* data, int count) +{ + int memsize = sizeof(Vector4) * count; + + // may be incorrect if shaders are created and destroyed dynamically + if (memcmp(data, &Pixel_Shader_Constants[reg], memsize) == 0) return; + + memcpy(&Pixel_Shader_Constants[reg], data, memsize); + DX8CALL(SetPixelShaderConstant(reg, data, count)); +} +// shader system updates KJM ^ + + +WWINLINE void DX8Wrapper::_Set_DX8_Transform(D3DTRANSFORMSTATETYPE transform, const Matrix4x4& m) +{ + WWASSERT(transform <= D3DTS_WORLD); +#if 0 // (gth) this optimization is breaking generals because they set the transform behind our backs. + if (m != DX8Transforms[transform]) +#endif + { + DX8Transforms[transform] = m; + SNAPSHOT_SAY(("DX8 - SetTransform %d [%f,%f,%f,%f][%f,%f,%f,%f][%f,%f,%f,%f][%f,%f,%f,%f]", transform, m[0][0], m[0][1], m[0][2], m[0][3], m[1][0], m[1][1], m[1][2], m[1][3], m[2][0], m[2][1], m[2][2], m[2][3], m[3][0], m[3][1], m[3][2], m[3][3])); + DX8_RECORD_MATRIX_CHANGE(); + DX8CALL(SetTransform(transform, (D3DMATRIX*)&m)); + } +} + + +WWINLINE void DX8Wrapper::_Set_DX8_Transform(D3DTRANSFORMSTATETYPE transform, const Matrix3D& m) +{ + WWASSERT(transform <= D3DTS_WORLD); + Matrix4x4 mtx(m); +#if 0 // (gth) this optimization is breaking generals because they set the transform behind our backs. + if (mtx != DX8Transforms[transform]) +#endif + { + DX8Transforms[transform] = mtx; + SNAPSHOT_SAY(("DX8 - SetTransform %d [%f,%f,%f,%f][%f,%f,%f,%f][%f,%f,%f,%f]", transform, m[0][0], m[0][1], m[0][2], m[0][3], m[1][0], m[1][1], m[1][2], m[1][3], m[2][0], m[2][1], m[2][2], m[2][3])); + DX8_RECORD_MATRIX_CHANGE(); + DX8CALL(SetTransform(transform, (D3DMATRIX*)&m)); + } +} + +WWINLINE void DX8Wrapper::_Get_DX8_Transform(D3DTRANSFORMSTATETYPE transform, Matrix4x4& m) +{ + DX8CALL(GetTransform(transform, (D3DMATRIX*)&m)); +} + +// ---------------------------------------------------------------------------- +// +// Set the index offset for the current index buffer +// +// ---------------------------------------------------------------------------- + +WWINLINE void DX8Wrapper::Set_Index_Buffer_Index_Offset(unsigned offset) +{ + if (render_state.index_base_offset == offset) return; + render_state.index_base_offset = offset; + render_state_changed |= INDEX_BUFFER_CHANGED; +} + +// ---------------------------------------------------------------------------- +// Set the fog settings. This function should be used, rather than setting the +// appropriate renderstates directly, because the shader sets some of the +// renderstates on a per-mesh / per-pass basis depending on global fog states +// (stored in the wrapper) as well as the shader settings. +// This function should be called rarely - once per scene would be appropriate. +// ---------------------------------------------------------------------------- + +WWINLINE void DX8Wrapper::Set_Fog(bool enable, const Vector3& color, float start, float end) +{ + // Set global states + FogEnable = enable; + FogColor = Convert_Color(color, 0.0f); + + // Invalidate the current shader (since the renderstates set by the shader + // depend on the global fog settings as well as the actual shader settings) + ShaderClass::Invalidate(); + + // Set renderstates which are not affected by the shader + Set_DX8_Render_State(D3DRS_FOGSTART, *(DWORD*)(&start)); + Set_DX8_Render_State(D3DRS_FOGEND, *(DWORD*)(&end)); +} + + +WWINLINE void DX8Wrapper::Set_Ambient(const Vector3& color) +{ + Ambient_Color = color; + Set_DX8_Render_State(D3DRS_AMBIENT, DX8Wrapper::Convert_Color(color, 0.0f)); +} + +// ---------------------------------------------------------------------------- +// +// Set vertex buffer to be used in the subsequent render calls. If there was +// a vertex buffer being used earlier, release the reference to it. Passing +// NULL just will release the vertex buffer. +// +// ---------------------------------------------------------------------------- + +WWINLINE void DX8Wrapper::Set_DX8_Material(const D3DMATERIAL8* mat) +{ + DX8_RECORD_MATERIAL_CHANGE(); + WWASSERT(mat); + SNAPSHOT_SAY(("DX8 - SetMaterial")); + DX8CALL(SetMaterial(mat)); +} + +WWINLINE void DX8Wrapper::Set_DX8_Light(int index, D3DLIGHT8* light) +{ + if (light) { + DX8_RECORD_LIGHT_CHANGE(); + DX8CALL(SetLight(index, light)); + DX8CALL(LightEnable(index, TRUE)); + CurrentDX8LightEnables[index] = true; + SNAPSHOT_SAY(("DX8 - SetLight %d", index)); + } + else if (CurrentDX8LightEnables[index]) { + DX8_RECORD_LIGHT_CHANGE(); + CurrentDX8LightEnables[index] = false; + DX8CALL(LightEnable(index, FALSE)); + SNAPSHOT_SAY(("DX8 - DisableLight %d", index)); + } +} + +WWINLINE void DX8Wrapper::Set_DX8_Render_State(D3DRENDERSTATETYPE state, unsigned value) +{ + // Can't monitor state changes because setShader call to GERD may change the states! + if (RenderStates[state] == value) return; + +#ifdef MESH_RENDER_SNAPSHOT_ENABLED + if (WW3D::Is_Snapshot_Activated()) { + StringClass value_name(0, true); + Get_DX8_Render_State_Value_Name(value_name, state, value); + SNAPSHOT_SAY(("DX8 - SetRenderState(state: %s, value: %s)", + Get_DX8_Render_State_Name(state), + value_name.str())); + } +#endif + + RenderStates[state] = value; + DX8CALL(SetRenderState(state, value)); + DX8_RECORD_RENDER_STATE_CHANGE(); +} + +WWINLINE void DX8Wrapper::Set_DX8_Clip_Plane(DWORD Index, CONST float* pPlane) +{ + DX8CALL(SetClipPlane(Index, pPlane)); +} + +WWINLINE void DX8Wrapper::Set_DX8_Texture_Stage_State(unsigned stage, D3DTEXTURESTAGESTATETYPE state, unsigned value) +{ + if (stage >= MAX_TEXTURE_STAGES) + { + DX8CALL(SetTextureStageState(stage, state, value)); + return; + } + + // Can't monitor state changes because setShader call to GERD may change the states! + if (TextureStageStates[stage][(unsigned int)state] == value) return; +#ifdef MESH_RENDER_SNAPSHOT_ENABLED + if (WW3D::Is_Snapshot_Activated()) { + StringClass value_name(0, true); + Get_DX8_Texture_Stage_State_Value_Name(value_name, state, value); + SNAPSHOT_SAY(("DX8 - SetTextureStageState(stage: %d, state: %s, value: %s)", + stage, + Get_DX8_Texture_Stage_State_Name(state), + value_name.str())); + } +#endif + + TextureStageStates[stage][(unsigned int)state] = value; + DX8CALL(SetTextureStageState(stage, state, value)); + DX8_RECORD_TEXTURE_STAGE_STATE_CHANGE(); +} + +WWINLINE void DX8Wrapper::Set_DX8_Texture(unsigned int stage, IDirect3DBaseTexture8* texture) +{ + if (stage >= MAX_TEXTURE_STAGES) + { + DX8CALL(SetTexture(stage, texture)); + return; + } + + if (Textures[stage] == texture) return; + + SNAPSHOT_SAY(("DX8 - SetTexture(%x) ", texture)); + + if (Textures[stage]) Textures[stage]->Release(); + Textures[stage] = texture; + if (Textures[stage]) Textures[stage]->AddRef(); + DX8CALL(SetTexture(stage, texture)); + DX8_RECORD_TEXTURE_CHANGE(); +} + +WWINLINE void DX8Wrapper::_Copy_DX8_Rects( + IDirect3DSurface8* pSourceSurface, + CONST RECT* pSourceRectsArray, + UINT cRects, + IDirect3DSurface8* pDestinationSurface, + CONST POINT* pDestPointsArray +) +{ + DX8CALL(CopyRects( + pSourceSurface, + pSourceRectsArray, + cRects, + pDestinationSurface, + pDestPointsArray)); +} + +WWINLINE Vector4 DX8Wrapper::Convert_Color(unsigned color) +{ + Vector4 col; + col[3] = ((color & 0xff000000) >> 24) / 255.0f; + col[0] = ((color & 0xff0000) >> 16) / 255.0f; + col[1] = ((color & 0xff00) >> 8) / 255.0f; + col[2] = ((color & 0xff) >> 0) / 255.0f; + // col=Vector4(1.0f,1.0f,1.0f,1.0f); + return col; +} + +#if 0 +WWINLINE unsigned int DX8Wrapper::Convert_Color(const Vector3& color, const float alpha) +{ + WWASSERT(color.X <= 1.0f); + WWASSERT(color.Y <= 1.0f); + WWASSERT(color.Z <= 1.0f); + WWASSERT(alpha <= 1.0f); + WWASSERT(color.X >= 0.0f); + WWASSERT(color.Y >= 0.0f); + WWASSERT(color.Z >= 0.0f); + WWASSERT(alpha >= 0.0f); + + return D3DCOLOR_COLORVALUE(color.X, color.Y, color.Z, alpha); +} +WWINLINE unsigned int DX8Wrapper::Convert_Color(const Vector4& color) +{ + WWASSERT(color.X <= 1.0f); + WWASSERT(color.Y <= 1.0f); + WWASSERT(color.Z <= 1.0f); + WWASSERT(color.W <= 1.0f); + WWASSERT(color.X >= 0.0f); + WWASSERT(color.Y >= 0.0f); + WWASSERT(color.Z >= 0.0f); + WWASSERT(color.W >= 0.0f); + + return D3DCOLOR_COLORVALUE(color.X, color.Y, color.Z, color.W); +} +#else + +// ---------------------------------------------------------------------------- +// +// Convert RGBA color from float vector to 32 bit integer +// Note: Color vector needs to be clamped to [0...1] range! +// +// ---------------------------------------------------------------------------- + +WWINLINE unsigned int DX8Wrapper::Convert_Color(const Vector3& color, float alpha) +{ +#if defined(_MSC_VER) && _MSC_VER < 1300 + const float scale = 255.0; + unsigned int col; + + // Multiply r, g, b and a components (0.0,...,1.0) by 255 and convert to integer. Or the integer values togerher + // such that 32 bit ingeger has AAAAAAAARRRRRRRRGGGGGGGGBBBBBBBB. + __asm + { + sub esp, 20 // space for a, r, g and b float plus fpu rounding mode + + // Store the fpu rounding mode + + fwait + fstcw[esp + 16] // store control word to stack + mov eax, [esp + 16] // load it to eax + mov edi, eax // take copy + and eax, ~(1024 | 2048) // mask out certain bits + or eax, (1024 | 2048) // or with precision control value "truncate" + sub edi, eax // did it change? + jz skip // .. if not, skip + mov[esp], eax // .. change control word + fldcw[esp] + skip: + + // Convert the color + + mov esi, dword ptr color + fld dword ptr[scale] + + fld dword ptr[esi] // r + fld dword ptr[esi + 4] // g + fld dword ptr[esi + 8] // b + fld dword ptr[alpha] // a + fld st(4) + fmul st(4), st + fmul st(3), st + fmul st(2), st + fmulp st(1), st + fistp dword ptr[esp + 0] // a + fistp dword ptr[esp + 4] // b + fistp dword ptr[esp + 8] // g + fistp dword ptr[esp + 12] // r + mov ecx, [esp] // a + mov eax, [esp + 4] // b + mov edx, [esp + 8] // g + mov ebx, [esp + 12] // r + shl ecx, 24 // a << 24 + shl ebx, 16 // r << 16 + shl edx, 8 // g << 8 + or eax, ecx // (a << 24) | b + or eax, ebx // (a << 24) | (r << 16) | b + or eax, edx // (a << 24) | (r << 16) | (g << 8) | b + + fstp st(0) + + // Restore fpu rounding mode + + cmp edi, 0 // did we change the value? + je not_changed // nope... skip now... + fwait + fldcw[esp + 16]; + not_changed: + add esp, 20 + + mov col, eax + } + return col; +#else + return color.Convert_To_ARGB(alpha); +#endif // defined(_MSC_VER) && _MSC_VER < 1300 +} + +// ---------------------------------------------------------------------------- +// +// Clamp color vector to [0...1] range +// +// ---------------------------------------------------------------------------- + +WWINLINE void DX8Wrapper::Clamp_Color(Vector4& color) +{ +#if defined(_MSC_VER) && _MSC_VER < 1300 + if (CPUDetectClass::Has_CMOV_Instruction()) { + __asm + { + mov esi, dword ptr color + + mov edx, 0x3f800000 + + mov edi, dword ptr[esi] + mov ebx, edi + sar edi, 31 + not edi // mask is now zero if negative value + and edi, ebx + cmp edi, edx // if no less than 1.0 set to 1.0 + cmovnb edi, edx + mov dword ptr[esi], edi + + mov edi, dword ptr[esi + 4] + mov ebx, edi + sar edi, 31 + not edi // mask is now zero if negative value + and edi, ebx + cmp edi, edx // if no less than 1.0 set to 1.0 + cmovnb edi, edx + mov dword ptr[esi + 4], edi + + mov edi, dword ptr[esi + 8] + mov ebx, edi + sar edi, 31 + not edi // mask is now zero if negative value + and edi, ebx + cmp edi, edx // if no less than 1.0 set to 1.0 + cmovnb edi, edx + mov dword ptr[esi + 8], edi + + mov edi, dword ptr[esi + 12] + mov ebx, edi + sar edi, 31 + not edi // mask is now zero if negative value + and edi, ebx + cmp edi, edx // if no less than 1.0 set to 1.0 + cmovnb edi, edx + mov dword ptr[esi + 12], edi + } + return; + } +#endif // defined(_MSC_VER) && _MSC_VER < 1300 + + for (int i = 0; i < 4; ++i) { + float f = (color[i] < 0.0f) ? 0.0f : color[i]; + color[i] = (f > 1.0f) ? 1.0f : f; + } +} + +// ---------------------------------------------------------------------------- +// +// Convert RGBA color from float vector to 32 bit integer +// +// ---------------------------------------------------------------------------- + +WWINLINE unsigned int DX8Wrapper::Convert_Color(const Vector4& color) +{ + return Convert_Color(reinterpret_cast(color), color[3]); +} + +WWINLINE unsigned int DX8Wrapper::Convert_Color_Clamp(const Vector4& color) +{ + Vector4 clamped_color = color; + DX8Wrapper::Clamp_Color(clamped_color); + return Convert_Color(reinterpret_cast(clamped_color), clamped_color[3]); +} + +#endif + + +WWINLINE void DX8Wrapper::Set_Alpha(const float alpha, unsigned int& color) +{ + unsigned char* component = (unsigned char*)&color; + + component[3] = 255.0f * alpha; +} + +WWINLINE void DX8Wrapper::Get_Render_State(RenderStateStruct& state) +{ + state = render_state; +} + +WWINLINE void DX8Wrapper::Get_Shader(ShaderClass& shader) +{ + shader = render_state.shader; +} + +WWINLINE void DX8Wrapper::Set_Texture(unsigned stage, TextureBaseClass* texture) +{ + WWASSERT(stage < (unsigned int)CurrentCaps->Get_Max_Textures_Per_Pass()); + if (texture == render_state.Textures[stage]) return; + REF_PTR_SET(render_state.Textures[stage], texture); + render_state_changed |= (TEXTURE0_CHANGED << stage); +} + +WWINLINE void DX8Wrapper::Set_Material(const VertexMaterialClass* material) +{ + /* if (material && render_state.material && + // !stricmp(material->Get_Name(),render_state.material->Get_Name())) { + material->Get_CRC()!=render_state.material->Get_CRC()) { + return; + } + */ + // if (material==render_state.material) { + // return; + // } + REF_PTR_SET(render_state.material, const_cast(material)); + render_state_changed |= MATERIAL_CHANGED; + SNAPSHOT_SAY(("DX8Wrapper::Set_Material(%s)", material ? material->Get_Name() : "NULL")); +} + +WWINLINE void DX8Wrapper::Set_Shader(const ShaderClass& shader) +{ + if (!ShaderClass::ShaderDirty && ((unsigned&)shader == (unsigned&)render_state.shader)) { + return; + } + render_state.shader = shader; + render_state_changed |= SHADER_CHANGED; +#ifdef MESH_RENDER_SNAPSHOT_ENABLED + StringClass str; +#endif + SNAPSHOT_SAY(("DX8Wrapper::Set_Shader(%s)", shader.Get_Description(str).str())); +} + +WWINLINE void DX8Wrapper::Set_Projection_Transform_With_Z_Bias(const Matrix4x4& matrix, float znear, float zfar) +{ + ZFar = zfar; + ZNear = znear; + ProjectionMatrix = matrix.Transpose(); + + if (!Get_Current_Caps()->Support_ZBias() && ZNear != ZFar) { + Matrix4x4 tmp = ProjectionMatrix; + float tmp_zbias = ZBias; + tmp_zbias *= (1.0f / 16.0f); + tmp_zbias *= 1.0f / (ZFar - ZNear); + tmp[2][2] -= tmp_zbias * tmp[3][2]; + DX8CALL(SetTransform(D3DTS_PROJECTION, (D3DMATRIX*)&tmp)); + } + else { + DX8CALL(SetTransform(D3DTS_PROJECTION, (D3DMATRIX*)&ProjectionMatrix)); + } +} + +WWINLINE void DX8Wrapper::Set_DX8_ZBias(int zbias) +{ + if (zbias == ZBias) return; + if (zbias > 15) zbias = 15; + if (zbias < 0) zbias = 0; + ZBias = zbias; + + if (!Get_Current_Caps()->Support_ZBias() && ZNear != ZFar) { + Matrix4x4 tmp = ProjectionMatrix; + float tmp_zbias = ZBias; + tmp_zbias *= (1.0f / 16.0f); + tmp_zbias *= 1.0f / (ZFar - ZNear); + tmp[2][2] -= tmp_zbias * tmp[3][2]; + DX8CALL(SetTransform(D3DTS_PROJECTION, (D3DMATRIX*)&tmp)); + } + else { + Set_DX8_Render_State(D3DRS_ZBIAS, ZBias); + } +} + +WWINLINE void DX8Wrapper::Set_Transform(D3DTRANSFORMSTATETYPE transform, const Matrix4x4& m) +{ + switch ((int)transform) { + case D3DTS_WORLD: + render_state.world = m.Transpose(); + render_state_changed |= (unsigned)WORLD_CHANGED; + render_state_changed &= ~(unsigned)WORLD_IDENTITY; + break; + case D3DTS_VIEW: + render_state.view = m.Transpose(); + render_state_changed |= (unsigned)VIEW_CHANGED; + render_state_changed &= ~(unsigned)VIEW_IDENTITY; + break; + case D3DTS_PROJECTION: + { + Matrix4x4 ProjectionMatrix = m.Transpose(); + ZFar = 0.0f; + ZNear = 0.0f; + DX8CALL(SetTransform(D3DTS_PROJECTION, (D3DMATRIX*)&ProjectionMatrix)); + } + break; + default: + DX8_RECORD_MATRIX_CHANGE(); + Matrix4x4 m2 = m.Transpose(); + DX8CALL(SetTransform(transform, (D3DMATRIX*)&m2)); + break; + } +} + +WWINLINE void DX8Wrapper::Set_Transform(D3DTRANSFORMSTATETYPE transform, const Matrix3D& m) +{ + Matrix4x4 m2(m); + switch ((int)transform) { + case D3DTS_WORLD: + render_state.world = m2.Transpose(); + render_state_changed |= (unsigned)WORLD_CHANGED; + render_state_changed &= ~(unsigned)WORLD_IDENTITY; + break; + case D3DTS_VIEW: + render_state.view = m2.Transpose(); + render_state_changed |= (unsigned)VIEW_CHANGED; + render_state_changed &= ~(unsigned)VIEW_IDENTITY; + break; + default: + DX8_RECORD_MATRIX_CHANGE(); + m2 = m2.Transpose(); + DX8CALL(SetTransform(transform, (D3DMATRIX*)&m2)); + break; + } +} + +WWINLINE void DX8Wrapper::Set_World_Identity() +{ + if (render_state_changed & (unsigned)WORLD_IDENTITY) return; + render_state.world.Make_Identity(); + render_state_changed |= (unsigned)WORLD_CHANGED | (unsigned)WORLD_IDENTITY; +} + +WWINLINE void DX8Wrapper::Set_View_Identity() +{ + if (render_state_changed & (unsigned)VIEW_IDENTITY) return; + render_state.view.Make_Identity(); + render_state_changed |= (unsigned)VIEW_CHANGED | (unsigned)VIEW_IDENTITY; +} + +WWINLINE bool DX8Wrapper::Is_World_Identity() +{ + return !!(render_state_changed & (unsigned)WORLD_IDENTITY); +} + +WWINLINE bool DX8Wrapper::Is_View_Identity() +{ + return !!(render_state_changed & (unsigned)VIEW_IDENTITY); +} + +WWINLINE void DX8Wrapper::Get_Transform(D3DTRANSFORMSTATETYPE transform, Matrix4x4& m) +{ + D3DMATRIX mat; + + switch ((int)transform) { + case D3DTS_WORLD: + if (render_state_changed & WORLD_IDENTITY) m.Make_Identity(); + else m = render_state.world.Transpose(); + break; + case D3DTS_VIEW: + if (render_state_changed & VIEW_IDENTITY) m.Make_Identity(); + else m = render_state.view.Transpose(); + break; + default: + DX8CALL(GetTransform(transform, &mat)); + m = *(Matrix4x4*)&mat; + m = m.Transpose(); + break; + } +} + +WWINLINE const D3DLIGHT8& DX8Wrapper::Peek_Light(unsigned index) +{ + return render_state.Lights[index];; +} + +WWINLINE bool DX8Wrapper::Is_Light_Enabled(unsigned index) +{ + return render_state.LightEnable[index]; +} + + +WWINLINE void DX8Wrapper::Set_Render_State(const RenderStateStruct& state) +{ + int i; + + if (render_state.index_buffer) { + render_state.index_buffer->Release_Engine_Ref(); + } + + for (i = 0; i < MAX_VERTEX_STREAMS; ++i) + { + if (render_state.vertex_buffers[i]) + { + render_state.vertex_buffers[i]->Release_Engine_Ref(); + } + } + + render_state = state; + render_state_changed = 0xffffffff; + + if (render_state.index_buffer) { + render_state.index_buffer->Add_Engine_Ref(); + } + + for (i = 0; i < MAX_VERTEX_STREAMS; ++i) + { + if (render_state.vertex_buffers[i]) + { + render_state.vertex_buffers[i]->Add_Engine_Ref(); + } + } +} + +WWINLINE void DX8Wrapper::Release_Render_State() +{ + int i; + + if (render_state.index_buffer) { + render_state.index_buffer->Release_Engine_Ref(); + } + + for (i = 0; i < MAX_VERTEX_STREAMS; ++i) { + if (render_state.vertex_buffers[i]) { + render_state.vertex_buffers[i]->Release_Engine_Ref(); + } + } + + for (i = 0; i < MAX_VERTEX_STREAMS; ++i) { + REF_PTR_RELEASE(render_state.vertex_buffers[i]); + } + REF_PTR_RELEASE(render_state.index_buffer); + REF_PTR_RELEASE(render_state.material); + + + for (i = 0; i < MAX_TEXTURE_STAGES; ++i) + { + REF_PTR_RELEASE(render_state.Textures[i]); + } +} + + +WWINLINE RenderStateStruct::RenderStateStruct() + : + material(0), + index_buffer(0) +{ + unsigned i; + for (i = 0; i < MAX_VERTEX_STREAMS; ++i) vertex_buffers[i] = 0; + for (i = 0; i < MAX_TEXTURE_STAGES; ++i) Textures[i] = 0; + //lightsHash = (unsigned)this; +} + +WWINLINE RenderStateStruct::~RenderStateStruct() +{ + unsigned i; + REF_PTR_RELEASE(material); + for (i = 0; i < MAX_VERTEX_STREAMS; ++i) { + REF_PTR_RELEASE(vertex_buffers[i]); + } + REF_PTR_RELEASE(index_buffer); + + for (i = 0; i < MAX_TEXTURE_STAGES; ++i) + { + REF_PTR_RELEASE(Textures[i]); + } +} + + +WWINLINE unsigned flimby(char* name, unsigned crib) +{ + unsigned lnt prevVer = 0x00000000; + unsigned D3D2_BASE_VEC nextVer = 0; + for (unsigned t = 0; t < crib; ++t) + { + (D3D2_BASE_VEC)nextVer += name[t]; + (D3D2_BASE_VEC)nextVer %= 32; + (D3D2_BASE_VEC)nextVer--; + (lnt)prevVer ^= (1 << (D3D2_BASE_VEC)prevVer); + } + return (lnt)prevVer; +} + +WWINLINE RenderStateStruct& RenderStateStruct::operator= (const RenderStateStruct& src) +{ + unsigned i; + REF_PTR_SET(material, src.material); + for (i = 0; i < MAX_VERTEX_STREAMS; ++i) { + REF_PTR_SET(vertex_buffers[i], src.vertex_buffers[i]); + } + REF_PTR_SET(index_buffer, src.index_buffer); + + for (i = 0; i < MAX_TEXTURE_STAGES; ++i) + { + REF_PTR_SET(Textures[i], src.Textures[i]); + } + + LightEnable[0] = src.LightEnable[0]; + LightEnable[1] = src.LightEnable[1]; + LightEnable[2] = src.LightEnable[2]; + LightEnable[3] = src.LightEnable[3]; + if (LightEnable[0]) { + Lights[0] = src.Lights[0]; + if (LightEnable[1]) { + Lights[1] = src.Lights[1]; + if (LightEnable[2]) { + Lights[2] = src.Lights[2]; + if (LightEnable[3]) { + Lights[3] = src.Lights[3]; + } + } + } + + + //lightsHash = flimby((char*)(&Lights[0]), sizeof(D3DLIGHT8)-1 ); + + } + + shader = src.shader; + world = src.world; + view = src.view; + for (i = 0; i < MAX_VERTEX_STREAMS; ++i) { + vertex_buffer_types[i] = src.vertex_buffer_types[i]; + } + index_buffer_type = src.index_buffer_type; + vba_offset = src.vba_offset; + vba_count = src.vba_count; + iba_offset = src.iba_offset; + index_base_offset = src.index_base_offset; + + return *this; +} + + +#endif +>>>>>>> 0122e54d (Setup proper linking) diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt b/Generals/Code/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt index e4e14e3d9a8..aabf6bf5bee 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt @@ -60,8 +60,8 @@ set(WW3D2_SRC dx8vertexbuffer.h #dx8webbrowser.cpp #dx8webbrowser.h - dx8wrapper.cpp - dx8wrapper.h + #dx8wrapper.cpp + #dx8wrapper.h #dynamesh.cpp #dynamesh.h #font3d.cpp diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp deleted file mode 100644 index 56e5bdf2496..00000000000 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "../../Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h" diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h deleted file mode 100644 index 2c9291c9b6c..00000000000 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h +++ /dev/null @@ -1 +0,0 @@ -#include "../../Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_header_common.h" diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt index b1a98488375..7d54e30ca33 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt @@ -62,8 +62,8 @@ set(WW3D2_SRC dx8vertexbuffer.h #dx8webbrowser.cpp #dx8webbrowser.h - dx8wrapper.cpp - dx8wrapper.h + #dx8wrapper.cpp + #dx8wrapper.h #dynamesh.cpp #dynamesh.h #font3d.cpp From 6c1ef9c6badabcfd7d10b39da269da1298cfdf72 Mon Sep 17 00:00:00 2001 From: ryan-de-boer Date: Fri, 1 Aug 2025 22:42:32 +0800 Subject: [PATCH 19/20] Fix merge --- Core/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp | 4 ---- Core/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h | 4 ---- 2 files changed, 8 deletions(-) diff --git a/Core/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/Core/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index eb8909661d2..2a709b21173 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/Core/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -1,6 +1,3 @@ -<<<<<<< HEAD -#include "../../Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_common.h" -======= /* ** Command & Conquer Generals Zero Hour(tm) ** Copyright 2025 Electronic Arts Inc. @@ -4498,4 +4495,3 @@ WW3DFormat DX8Wrapper::getBackBufferFormat(void) { return D3DFormat_To_WW3DFormat(_PresentParameters.BackBufferFormat); } ->>>>>>> 0122e54d (Setup proper linking) diff --git a/Core/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h b/Core/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h index 2a37598497f..414256e15a6 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h +++ b/Core/Libraries/Source/WWVegas/WW3D2/dx8wrapper.h @@ -1,6 +1,3 @@ -<<<<<<< HEAD -#include "../../Core/GameEngine/Source/Common/Graphics/DX8/dx8wrapper_header_common.h" -======= /* ** Command & Conquer Generals Zero Hour(tm) ** Copyright 2025 Electronic Arts Inc. @@ -1517,4 +1514,3 @@ WWINLINE RenderStateStruct& RenderStateStruct::operator= (const RenderStateStruc #endif ->>>>>>> 0122e54d (Setup proper linking) From 2ba4d169853e2ff03eebb5c4f2578538331281e2 Mon Sep 17 00:00:00 2001 From: ryan-de-boer Date: Fri, 1 Aug 2025 23:10:54 +0800 Subject: [PATCH 20/20] Clean code --- CMakeLists.txt | 2 +- CMakePresets.json | 137 +++++++++++++++++- Generals/CMakeLists.txt | 2 +- .../GameEngine/Source/Common/System/Debug.cpp | 4 +- .../GameEngine/Source/GameClient/GameText.cpp | 1 - .../Source/WWVegas/WW3D2/assetmgr.cpp | 42 ------ .../Libraries/Source/WWVegas/WW3D2/assetmgr.h | 3 - GeneralsMD/CMakeLists.txt | 2 +- .../GameEngine/Source/Common/System/Debug.cpp | 4 +- 9 files changed, 141 insertions(+), 56 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ab485d0d47..d2b41feab51 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.24) +cmake_minimum_required(VERSION 3.25) # Use packagename_ROOT for FindPackage. if(POLICY CMP0074) diff --git a/CMakePresets.json b/CMakePresets.json index 3f69d2c556f..51610bf95ca 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -1,8 +1,8 @@ { - "version": 4, + "version": 6, "cmakeMinimumRequired": { "major": 3, - "minor": 24, + "minor": 25, "patch": 0 }, "configurePresets": [ @@ -212,6 +212,137 @@ "description": "Build Unix 32bit VCPKG Release", "configuration": "Release" } + ], + "workflowPresets": [ + { + "name": "vc6", + "steps": [ + { + "type": "configure", + "name": "vc6" + }, + { + "type": "build", + "name": "vc6" + } + ] + }, + { + "name": "vc6-debug", + "steps": [ + { + "type": "configure", + "name": "vc6-debug" + }, + { + "type": "build", + "name": "vc6-debug" + } + ] + }, + { + "name": "vc6-profile", + "steps": [ + { + "type": "configure", + "name": "vc6-profile" + }, + { + "type": "build", + "name": "vc6-profile" + } + ] + }, + { + "name": "win32", + "steps": [ + { + "type": "configure", + "name": "win32" + }, + { + "type": "build", + "name": "win32" + } + ] + }, + { + "name": "win32-profile", + "steps": [ + { + "type": "configure", + "name": "win32-profile" + }, + { + "type": "build", + "name": "win32-profile" + } + ] + }, + { + "name": "win32-debug", + "steps": [ + { + "type": "configure", + "name": "win32-debug" + }, + { + "type": "build", + "name": "win32-debug" + } + ] + }, + { + "name": "win32-vcpkg", + "steps": [ + { + "type": "configure", + "name": "win32-vcpkg" + }, + { + "type": "build", + "name": "win32-vcpkg" + } + ] + }, + { + "name": "win32-vcpkg-profile", + "steps": [ + { + "type": "configure", + "name": "win32-vcpkg-profile" + }, + { + "type": "build", + "name": "win32-vcpkg-profile" + } + ] + }, + { + "name": "win32-vcpkg-debug", + "steps": [ + { + "type": "configure", + "name": "win32-vcpkg-debug" + }, + { + "type": "build", + "name": "win32-vcpkg-debug" + } + ] + }, + { + "name": "unix", + "steps": [ + { + "type": "configure", + "name": "unix" + }, + { + "type": "build", + "name": "unix" + } + ] + } ] - } \ No newline at end of file diff --git a/Generals/CMakeLists.txt b/Generals/CMakeLists.txt index 785a9aa1a6d..7953714f5a9 100644 --- a/Generals/CMakeLists.txt +++ b/Generals/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.24) +cmake_minimum_required(VERSION 3.25) project(g_generals LANGUAGES C CXX) diff --git a/Generals/Code/GameEngine/Source/Common/System/Debug.cpp b/Generals/Code/GameEngine/Source/Common/System/Debug.cpp index ba6ebbffe86..ee67d5b7089 100644 --- a/Generals/Code/GameEngine/Source/Common/System/Debug.cpp +++ b/Generals/Code/GameEngine/Source/Common/System/Debug.cpp @@ -427,8 +427,8 @@ void DebugLog(const char *format, ...) ScopedCriticalSection scopedCriticalSection(TheDebugLogCriticalSection); #endif -// if (theDebugFlags == 0) -// MessageBoxWrapper("DebugLog - Debug not inited properly", "", MB_OK|MB_TASKMODAL); + if (theDebugFlags == 0) + MessageBoxWrapper("DebugLog - Debug not inited properly", "", MB_OK|MB_TASKMODAL); prepBuffer(theBuffer); diff --git a/Generals/Code/GameEngine/Source/GameClient/GameText.cpp b/Generals/Code/GameEngine/Source/GameClient/GameText.cpp index 226a1bb0c74..d3e91019cc9 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GameText.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GameText.cpp @@ -1475,7 +1475,6 @@ Char GameTextManager::readChar( File *file ) void GameTextManager::updateWindowTitle() { // TheSuperHackers @tweak Now prints product and version information in the Window title. - return; DEBUG_ASSERTCRASH(TheVersion != NULL, ("TheVersion is NULL")); diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/assetmgr.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/assetmgr.cpp index 4a31e6a0f74..5f9b8ca0530 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/assetmgr.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/assetmgr.cpp @@ -1044,48 +1044,6 @@ HTreeClass * WW3DAssetManager::Get_HTree(const char * name) return htree; } -//doesn't exist in ZH - -/*********************************************************************************************** - * 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 * * * diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/assetmgr.h b/Generals/Code/Libraries/Source/WWVegas/WW3D2/assetmgr.h index 06fab701a75..db7d3a3c3df 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/assetmgr.h +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/assetmgr.h @@ -272,9 +272,6 @@ class WW3DAssetManager bool allow_reduction=true ); - //doesn't exist in ZH - //TextureClass* Get_Bumpmap_Based_On_Texture(TextureClass* texture); - virtual void Release_All_Textures(void); virtual void Release_Unused_Textures(void); virtual void Release_Texture(TextureClass *); diff --git a/GeneralsMD/CMakeLists.txt b/GeneralsMD/CMakeLists.txt index cb8e5ef4bbf..d7d20ea93a6 100644 --- a/GeneralsMD/CMakeLists.txt +++ b/GeneralsMD/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.24) +cmake_minimum_required(VERSION 3.25) project(z_generals LANGUAGES C CXX) diff --git a/GeneralsMD/Code/GameEngine/Source/Common/System/Debug.cpp b/GeneralsMD/Code/GameEngine/Source/Common/System/Debug.cpp index 310f8ab51bd..df047cdce45 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/System/Debug.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/System/Debug.cpp @@ -428,8 +428,8 @@ void DebugLog(const char *format, ...) ScopedCriticalSection scopedCriticalSection(TheDebugLogCriticalSection); #endif -// if (theDebugFlags == 0) -// MessageBoxWrapper("DebugLog - Debug not inited properly", "", MB_OK|MB_TASKMODAL); + if (theDebugFlags == 0) + MessageBoxWrapper("DebugLog - Debug not inited properly", "", MB_OK|MB_TASKMODAL); prepBuffer(theBuffer);