From 58e61a3bea8ed6fe95509a6466e7ca1f1d09fe99 Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Sun, 2 Nov 2025 12:32:17 -0500 Subject: [PATCH 1/6] feat(video): add brightness post-processing filter infrastructure --- Generals/Code/GameEngineDevice/CMakeLists.txt | 1 + .../GameClient/W3DBrightnessFilter.h | 82 ++++ .../GameClient/W3DBrightnessFilter.cpp | 414 +++++++++++++++++ .../Code/GameEngineDevice/CMakeLists.txt | 1 + .../GameClient/W3DBrightnessFilter.h | 82 ++++ .../GameClient/W3DBrightnessFilter.cpp | 415 ++++++++++++++++++ 6 files changed, 995 insertions(+) create mode 100644 Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DBrightnessFilter.h create mode 100644 Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DBrightnessFilter.cpp create mode 100644 GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DBrightnessFilter.h create mode 100644 GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DBrightnessFilter.cpp diff --git a/Generals/Code/GameEngineDevice/CMakeLists.txt b/Generals/Code/GameEngineDevice/CMakeLists.txt index 63a78b15a4..834bb1e09a 100644 --- a/Generals/Code/GameEngineDevice/CMakeLists.txt +++ b/Generals/Code/GameEngineDevice/CMakeLists.txt @@ -151,6 +151,7 @@ set(GAMEENGINEDEVICE_SRC Source/W3DDevice/GameClient/W3DPoly.cpp Source/W3DDevice/GameClient/W3DRoadBuffer.cpp Source/W3DDevice/GameClient/W3DScene.cpp + Source/W3DDevice/GameClient/W3DBrightnessFilter.cpp Source/W3DDevice/GameClient/W3DShaderManager.cpp Source/W3DDevice/GameClient/W3DShroud.cpp Source/W3DDevice/GameClient/W3DStatusCircle.cpp diff --git a/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DBrightnessFilter.h b/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DBrightnessFilter.h new file mode 100644 index 0000000000..579fc7a27b --- /dev/null +++ b/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DBrightnessFilter.h @@ -0,0 +1,82 @@ +/* +** 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) 2025 // +// // +//////////////////////////////////////////////////////////////////////////////// + +// FILE: W3DBrightnessFilter.h ///////////////////////////////////////////////// +// +// Brightness adjustment post-processing filter +// Implements GenTool-style brightness control (-128 to +256 range) +// - Range 1-128: lifts black level linearly +// - Range 129-256: lifts brightness while preserving black level +// +// Author: @bobtista, November 2025 +// +/////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "W3DShaderManager.h" + +/*========= ScreenBrightnessFilter =============================================================*/ +/// Applies brightness/gamma adjustment to the viewport using pixel shaders +class ScreenBrightnessFilter : public W3DFilterInterface +{ +public: + virtual Int set(FilterModes mode); ///. +*/ + +//////////////////////////////////////////////////////////////////////////////// +// // +// (c) 2025 // +// // +//////////////////////////////////////////////////////////////////////////////// + +// FILE: W3DBrightnessFilter.cpp /////////////////////////////////////////////// +// +// Brightness adjustment post-processing filter implementation +// +// Author: @bobtista, November 2025 +// +/////////////////////////////////////////////////////////////////////////////// + +#include "W3DDevice/GameClient/W3DBrightnessFilter.h" +#include "W3DDevice/GameClient/W3DShaderManager.h" +#include "GameClient/Display.h" +#include "GameClient/View.h" +#include "Common/GameLOD.h" +#include "WW3D2/dx8wrapper.h" +#include "WW3D2/dx8caps.h" +#include "WW3D2/shader.h" +#include "WW3D2/vertmaterial.h" +#include + +/*===========================================================================================*/ +/*========= Pixel Shader Version =============*/ +/*===========================================================================================*/ + +DWORD ScreenBrightnessFilter::m_pixelShaderHandle = NULL; +Int ScreenBrightnessFilter::m_brightnessValue = 0; +Bool ScreenBrightnessFilter::m_isEnabled = false; + +Int ScreenBrightnessFilter::init(void) +{ + m_pixelShaderHandle = NULL; + m_brightnessValue = 0; + m_isEnabled = false; + + if (!W3DShaderManager::canRenderToTexture()) { + // Have to be able to render to texture. + return false; + } + + Int chipset = W3DShaderManager::getChipset(); + if (chipset >= DC_GENERIC_PIXEL_SHADER_1_1) + { + //shader declaration + DWORD Declaration[] = + { + (D3DVSD_STREAM(0)), + (D3DVSD_REG(0, D3DVSDT_FLOAT3)), // Position + (D3DVSD_REG(1, D3DVSDT_D3DCOLOR)), // Diffuse + (D3DVSD_REG(2, D3DVSDT_FLOAT2)), // Texture Coordinates + (D3DVSD_END()) + }; + + //Brightness adjustment pixel shader + HRESULT hr = W3DShaderManager::LoadAndCreateD3DShader("shaders\\brightness.pso", &Declaration[0], 0, false, &m_pixelShaderHandle); + if (FAILED(hr)) + return FALSE; + + return TRUE; + } + return FALSE; +} + +Int ScreenBrightnessFilter::shutdown(void) +{ + if (m_pixelShaderHandle) + { + DX8Wrapper::_Get_D3D_Device8()->DeletePixelShader(m_pixelShaderHandle); + m_pixelShaderHandle = NULL; + } + return TRUE; +} + +void ScreenBrightnessFilter::reset(void) +{ + // Reset to default state + ShaderClass::Invalidate(); + DX8Wrapper::_Get_D3D_Device8()->SetTexture(0, NULL); + DX8Wrapper::_Get_D3D_Device8()->SetPixelShader(0); +} + +Bool ScreenBrightnessFilter::preRender(Bool &skipRender, CustomScenePassModes &scenePassMode) +{ + // Only enable if brightness is non-zero + if (m_brightnessValue == 0) + { + skipRender = false; + return false; + } + + skipRender = false; + W3DShaderManager::startRenderToTexture(); + return true; +} + +Bool ScreenBrightnessFilter::postRender(FilterModes mode, Coord2D &scrollDelta, Bool &doExtraRender) +{ + // If brightness is zero, no adjustment needed + if (m_brightnessValue == 0) + { + return false; + } + + IDirect3DTexture8 * tex = W3DShaderManager::endRenderToTexture(); + DEBUG_ASSERTCRASH(tex, ("Require rendered texture.")); + if (!tex) return false; + if (!set(mode)) return false; + + LPDIRECT3DDEVICE8 pDev = DX8Wrapper::_Get_D3D_Device8(); + + struct _TRANS_LIT_TEX_VERTEX { + D3DXVECTOR4 p; + DWORD color; // diffuse color + float u; + float v; + } v[4]; + + Int xpos, ypos, width, height; + + pDev->SetTexture(0, tex); // previously rendered frame inside this texture + TheTacticalView->getOrigin(&xpos, &ypos); + width = TheTacticalView->getWidth(); + height = TheTacticalView->getHeight(); + + // Create fullscreen quad + // bottom right + v[0].p = D3DXVECTOR4(xpos + width - 0.5f, ypos + height - 0.5f, 0.0f, 1.0f); + v[0].u = (Real)(xpos + width) / (Real)TheDisplay->getWidth(); v[0].v = (Real)(ypos + height) / (Real)TheDisplay->getHeight(); + // top right + v[1].p = D3DXVECTOR4(xpos + width - 0.5f, ypos - 0.5f, 0.0f, 1.0f); + v[1].u = (Real)(xpos + width) / (Real)TheDisplay->getWidth(); v[1].v = (Real)(ypos) / (Real)TheDisplay->getHeight(); + // bottom left + v[2].p = D3DXVECTOR4(xpos - 0.5f, ypos + height - 0.5f, 0.0f, 1.0f); + v[2].u = (Real)(xpos) / (Real)TheDisplay->getWidth(); v[2].v = (Real)(ypos + height) / (Real)TheDisplay->getHeight(); + // top left + v[3].p = D3DXVECTOR4(xpos - 0.5f, ypos - 0.5f, 0.0f, 1.0f); + v[3].u = (Real)(xpos) / (Real)TheDisplay->getWidth(); v[3].v = (Real)(ypos) / (Real)TheDisplay->getHeight(); + v[0].color = 0xffffffff; + v[1].color = 0xffffffff; + v[2].color = 0xffffffff; + v[3].color = 0xffffffff; + + pDev->SetVertexShader(D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1); + pDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, v, sizeof(_TRANS_LIT_TEX_VERTEX)); + + reset(); + return true; +} + +Int ScreenBrightnessFilter::set(FilterModes mode) +{ + HRESULT hr; + + // Set up render states for fullscreen quad + VertexMaterialClass *vmat = VertexMaterialClass::Get_Preset(VertexMaterialClass::PRELIT_DIFFUSE); + DX8Wrapper::Set_Material(vmat); + REF_PTR_RELEASE(vmat); + DX8Wrapper::Set_Shader(ShaderClass::_PresetOpaqueShader); + DX8Wrapper::Set_Texture(0, NULL); + DX8Wrapper::Apply_Render_State_Changes(); + + DX8Wrapper::Set_DX8_Render_State(D3DRS_ZFUNC, D3DCMP_ALWAYS); + DX8Wrapper::Set_DX8_Render_State(D3DRS_ZWRITEENABLE, FALSE); + DX8Wrapper::Apply_Render_State_Changes(); + + LPDIRECT3DDEVICE8 pDev = DX8Wrapper::_Get_D3D_Device8(); + hr = pDev->SetPixelShader(m_pixelShaderHandle); + + // Calculate brightness parameters based on GenTool's algorithm + // Range: -128 to +256 + // -128 to 0: darken (lift black level down, reduce brightness) + // 0: neutral (no adjustment) + // 1 to 128: lift black level linearly + // 129 to 256: lift brightness while preserving black level (gamma adjustment) + + float blackLift = 0.0f; + float gammaAdjust = 1.0f; + float brightnessAdd = 0.0f; + + if (m_brightnessValue < 0) + { + // Darken: negative black lift + blackLift = (float)m_brightnessValue / 128.0f; // Range: -1.0 to 0.0 + } + else if (m_brightnessValue <= 128) + { + // Lift black level linearly + blackLift = (float)m_brightnessValue / 128.0f; // Range: 0.0 to 1.0 + } + else + { + // Lift brightness while preserving black level (gamma/brightness boost) + // Range 129-256 maps to brightness increase + float adjustAmount = (float)(m_brightnessValue - 128) / 128.0f; // 0.0 to 1.0 + gammaAdjust = 1.0f / (1.0f + adjustAmount); // Inverse gamma for brightening + } + + // Set pixel shader constants + // c0: (blackLift, gammaAdjust, brightnessAdd, unused) + DX8Wrapper::_Get_D3D_Device8()->SetPixelShaderConstant(0, D3DXVECTOR4(blackLift, gammaAdjust, brightnessAdd, 1.0f), 1); + + return TRUE; +} + +Bool ScreenBrightnessFilter::setup(FilterModes mode) +{ + // Brightness filter doesn't need special setup + return true; +} + +void ScreenBrightnessFilter::setBrightnessValue(Int value) +{ + // Clamp to GenTool's range + if (value < -128) value = -128; + if (value > 256) value = 256; + + m_brightnessValue = value; + m_isEnabled = (value != 0); +} + +Int ScreenBrightnessFilter::getBrightnessValue() +{ + return m_brightnessValue; +} + +/*===========================================================================================*/ +/*========= Fixed-Function Version =============*/ +/*===========================================================================================*/ + +Int ScreenBrightnessFilterFixedFunction::m_brightnessValue = 0; +Bool ScreenBrightnessFilterFixedFunction::m_isEnabled = false; + +Int ScreenBrightnessFilterFixedFunction::init(void) +{ + m_brightnessValue = 0; + m_isEnabled = false; + + if (!W3DShaderManager::canRenderToTexture()) { + return false; + } + + // Fixed-function always supported on DirectX 8 hardware + return TRUE; +} + +Int ScreenBrightnessFilterFixedFunction::shutdown(void) +{ + return TRUE; +} + +void ScreenBrightnessFilterFixedFunction::reset(void) +{ + ShaderClass::Invalidate(); + DX8Wrapper::_Get_D3D_Device8()->SetTexture(0, NULL); +} + +Bool ScreenBrightnessFilterFixedFunction::preRender(Bool &skipRender, CustomScenePassModes &scenePassMode) +{ + if (m_brightnessValue == 0) + { + skipRender = false; + return false; + } + + skipRender = false; + W3DShaderManager::startRenderToTexture(); + return true; +} + +Bool ScreenBrightnessFilterFixedFunction::postRender(FilterModes mode, Coord2D &scrollDelta, Bool &doExtraRender) +{ + if (m_brightnessValue == 0) + { + return false; + } + + IDirect3DTexture8 * tex = W3DShaderManager::endRenderToTexture(); + DEBUG_ASSERTCRASH(tex, ("Require rendered texture.")); + if (!tex) return false; + if (!set(mode)) return false; + + LPDIRECT3DDEVICE8 pDev = DX8Wrapper::_Get_D3D_Device8(); + + struct _TRANS_LIT_TEX_VERTEX { + D3DXVECTOR4 p; + DWORD color; + float u; + float v; + } v[4]; + + Int xpos, ypos, width, height; + + pDev->SetTexture(0, tex); + TheTacticalView->getOrigin(&xpos, &ypos); + width = TheTacticalView->getWidth(); + height = TheTacticalView->getHeight(); + + // Create fullscreen quad + v[0].p = D3DXVECTOR4(xpos + width - 0.5f, ypos + height - 0.5f, 0.0f, 1.0f); + v[0].u = (Real)(xpos + width) / (Real)TheDisplay->getWidth(); v[0].v = (Real)(ypos + height) / (Real)TheDisplay->getHeight(); + v[1].p = D3DXVECTOR4(xpos + width - 0.5f, ypos - 0.5f, 0.0f, 1.0f); + v[1].u = (Real)(xpos + width) / (Real)TheDisplay->getWidth(); v[1].v = (Real)(ypos) / (Real)TheDisplay->getHeight(); + v[2].p = D3DXVECTOR4(xpos - 0.5f, ypos + height - 0.5f, 0.0f, 1.0f); + v[2].u = (Real)(xpos) / (Real)TheDisplay->getWidth(); v[2].v = (Real)(ypos + height) / (Real)TheDisplay->getHeight(); + v[3].p = D3DXVECTOR4(xpos - 0.5f, ypos - 0.5f, 0.0f, 1.0f); + v[3].u = (Real)(xpos) / (Real)TheDisplay->getWidth(); v[3].v = (Real)(ypos) / (Real)TheDisplay->getHeight(); + + // Calculate brightness modulation via vertex color + // This is a simpler approximation for cards without pixel shaders + DWORD colorMod = 0xff808080; // Default neutral gray + if (m_brightnessValue < 0) + { + // Darken + int val = 128 + m_brightnessValue; // 0-128 + colorMod = D3DCOLOR_RGBA(val, val, val, 255); + } + else if (m_brightnessValue <= 128) + { + // Brighten via additive + int val = 128 + (m_brightnessValue / 2); // 128-192 + colorMod = D3DCOLOR_RGBA(val, val, val, 255); + } + else + { + // Maximum brightness + colorMod = 0xffffffff; + } + + v[0].color = colorMod; + v[1].color = colorMod; + v[2].color = colorMod; + v[3].color = colorMod; + + pDev->SetVertexShader(D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1); + pDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, v, sizeof(_TRANS_LIT_TEX_VERTEX)); + + reset(); + return true; +} + +Int ScreenBrightnessFilterFixedFunction::set(FilterModes mode) +{ + // Set up render states for fullscreen quad + VertexMaterialClass *vmat = VertexMaterialClass::Get_Preset(VertexMaterialClass::PRELIT_DIFFUSE); + DX8Wrapper::Set_Material(vmat); + REF_PTR_RELEASE(vmat); + DX8Wrapper::Set_Shader(ShaderClass::_PresetOpaqueShader); + DX8Wrapper::Set_Texture(0, NULL); + DX8Wrapper::Apply_Render_State_Changes(); + + DX8Wrapper::Set_DX8_Render_State(D3DRS_ZFUNC, D3DCMP_ALWAYS); + DX8Wrapper::Set_DX8_Render_State(D3DRS_ZWRITEENABLE, FALSE); + DX8Wrapper::Apply_Render_State_Changes(); + + // Use texture stage states to modulate brightness + LPDIRECT3DDEVICE8 pDev = DX8Wrapper::_Get_D3D_Device8(); + pDev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + pDev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + pDev->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + pDev->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + pDev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + + return TRUE; +} + +Bool ScreenBrightnessFilterFixedFunction::setup(FilterModes mode) +{ + return true; +} + +void ScreenBrightnessFilterFixedFunction::setBrightnessValue(Int value) +{ + if (value < -128) value = -128; + if (value > 256) value = 256; + + m_brightnessValue = value; + m_isEnabled = (value != 0); +} + +Int ScreenBrightnessFilterFixedFunction::getBrightnessValue() +{ + return m_brightnessValue; +} + +// TheSuperHackers @feature bobtista 11/02/2025 Helper function to set brightness on both filter implementations +// This is called from OptionsMenu to update brightness for whichever filter is active +void setBrightnessFilterValue(Int value) +{ + ScreenBrightnessFilter::setBrightnessValue(value); + ScreenBrightnessFilterFixedFunction::setBrightnessValue(value); +} + diff --git a/GeneralsMD/Code/GameEngineDevice/CMakeLists.txt b/GeneralsMD/Code/GameEngineDevice/CMakeLists.txt index 82c1bb4259..dcf906d0b9 100644 --- a/GeneralsMD/Code/GameEngineDevice/CMakeLists.txt +++ b/GeneralsMD/Code/GameEngineDevice/CMakeLists.txt @@ -163,6 +163,7 @@ set(GAMEENGINEDEVICE_SRC Source/W3DDevice/GameClient/W3DPropBuffer.cpp Source/W3DDevice/GameClient/W3DRoadBuffer.cpp Source/W3DDevice/GameClient/W3DScene.cpp + Source/W3DDevice/GameClient/W3DBrightnessFilter.cpp Source/W3DDevice/GameClient/W3DShaderManager.cpp Source/W3DDevice/GameClient/W3DShroud.cpp Source/W3DDevice/GameClient/W3DSmudge.cpp diff --git a/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DBrightnessFilter.h b/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DBrightnessFilter.h new file mode 100644 index 0000000000..579fc7a27b --- /dev/null +++ b/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DBrightnessFilter.h @@ -0,0 +1,82 @@ +/* +** 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) 2025 // +// // +//////////////////////////////////////////////////////////////////////////////// + +// FILE: W3DBrightnessFilter.h ///////////////////////////////////////////////// +// +// Brightness adjustment post-processing filter +// Implements GenTool-style brightness control (-128 to +256 range) +// - Range 1-128: lifts black level linearly +// - Range 129-256: lifts brightness while preserving black level +// +// Author: @bobtista, November 2025 +// +/////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "W3DShaderManager.h" + +/*========= ScreenBrightnessFilter =============================================================*/ +/// Applies brightness/gamma adjustment to the viewport using pixel shaders +class ScreenBrightnessFilter : public W3DFilterInterface +{ +public: + virtual Int set(FilterModes mode); ///. +*/ + +//////////////////////////////////////////////////////////////////////////////// +// // +// (c) 2025 // +// // +//////////////////////////////////////////////////////////////////////////////// + +// FILE: W3DBrightnessFilter.cpp /////////////////////////////////////////////// +// +// Brightness adjustment post-processing filter implementation +// +// Author: @bobtista, November 2025 +// +/////////////////////////////////////////////////////////////////////////////// + +#include "W3DDevice/GameClient/W3DBrightnessFilter.h" +#include "W3DDevice/GameClient/W3DShaderManager.h" +#include "GameClient/Display.h" +#include "GameClient/View.h" +#include "Common/GameLOD.h" +#include "WW3D2/dx8wrapper.h" +#include "WW3D2/dx8caps.h" +#include "WW3D2/shader.h" +#include "WW3D2/vertmaterial.h" +#include + +/*===========================================================================================*/ +/*========= Pixel Shader Version =============*/ +/*===========================================================================================*/ + +DWORD ScreenBrightnessFilter::m_pixelShaderHandle = NULL; +Int ScreenBrightnessFilter::m_brightnessValue = 0; +Bool ScreenBrightnessFilter::m_isEnabled = false; + +Int ScreenBrightnessFilter::init(void) +{ + m_pixelShaderHandle = NULL; + m_brightnessValue = 0; + m_isEnabled = false; + + if (!W3DShaderManager::canRenderToTexture()) { + // Have to be able to render to texture. + return false; + } + + Int chipset = W3DShaderManager::getChipset(); + if (chipset >= DC_GENERIC_PIXEL_SHADER_1_1) + { + //shader declaration + DWORD Declaration[] = + { + (D3DVSD_STREAM(0)), + (D3DVSD_REG(0, D3DVSDT_FLOAT3)), // Position + (D3DVSD_REG(1, D3DVSDT_D3DCOLOR)), // Diffuse + (D3DVSD_REG(2, D3DVSDT_FLOAT2)), // Texture Coordinates + (D3DVSD_END()) + }; + + //Brightness adjustment pixel shader + HRESULT hr = W3DShaderManager::LoadAndCreateD3DShader("shaders\\brightness.pso", &Declaration[0], 0, false, &m_pixelShaderHandle); + if (FAILED(hr)) + return FALSE; + + return TRUE; + } + return FALSE; +} + +Int ScreenBrightnessFilter::shutdown(void) +{ + if (m_pixelShaderHandle) + { + DX8Wrapper::_Get_D3D_Device8()->DeletePixelShader(m_pixelShaderHandle); + m_pixelShaderHandle = NULL; + } + return TRUE; +} + +void ScreenBrightnessFilter::reset(void) +{ + // Reset to default state + ShaderClass::Invalidate(); + DX8Wrapper::_Get_D3D_Device8()->SetTexture(0, NULL); + DX8Wrapper::_Get_D3D_Device8()->SetPixelShader(0); +} + +Bool ScreenBrightnessFilter::preRender(Bool &skipRender, CustomScenePassModes &scenePassMode) +{ + // Only enable if brightness is non-zero + if (m_brightnessValue == 0) + { + skipRender = false; + return false; + } + + skipRender = false; + W3DShaderManager::startRenderToTexture(); + return true; +} + +Bool ScreenBrightnessFilter::postRender(FilterModes mode, Coord2D &scrollDelta, Bool &doExtraRender) +{ + // If brightness is zero, no adjustment needed + if (m_brightnessValue == 0) + { + return false; + } + + IDirect3DTexture8 * tex = W3DShaderManager::endRenderToTexture(); + DEBUG_ASSERTCRASH(tex, ("Require rendered texture.")); + if (!tex) return false; + if (!set(mode)) return false; + + LPDIRECT3DDEVICE8 pDev = DX8Wrapper::_Get_D3D_Device8(); + + struct _TRANS_LIT_TEX_VERTEX { + D3DXVECTOR4 p; + DWORD color; // diffuse color + float u; + float v; + } v[4]; + + Int xpos, ypos, width, height; + + pDev->SetTexture(0, tex); // previously rendered frame inside this texture + TheTacticalView->getOrigin(&xpos, &ypos); + width = TheTacticalView->getWidth(); + height = TheTacticalView->getHeight(); + + // Create fullscreen quad + // bottom right + v[0].p = D3DXVECTOR4(xpos + width - 0.5f, ypos + height - 0.5f, 0.0f, 1.0f); + v[0].u = (Real)(xpos + width) / (Real)TheDisplay->getWidth(); v[0].v = (Real)(ypos + height) / (Real)TheDisplay->getHeight(); + // top right + v[1].p = D3DXVECTOR4(xpos + width - 0.5f, ypos - 0.5f, 0.0f, 1.0f); + v[1].u = (Real)(xpos + width) / (Real)TheDisplay->getWidth(); v[1].v = (Real)(ypos) / (Real)TheDisplay->getHeight(); + // bottom left + v[2].p = D3DXVECTOR4(xpos - 0.5f, ypos + height - 0.5f, 0.0f, 1.0f); + v[2].u = (Real)(xpos) / (Real)TheDisplay->getWidth(); v[2].v = (Real)(ypos + height) / (Real)TheDisplay->getHeight(); + // top left + v[3].p = D3DXVECTOR4(xpos - 0.5f, ypos - 0.5f, 0.0f, 1.0f); + v[3].u = (Real)(xpos) / (Real)TheDisplay->getWidth(); v[3].v = (Real)(ypos) / (Real)TheDisplay->getHeight(); + v[0].color = 0xffffffff; + v[1].color = 0xffffffff; + v[2].color = 0xffffffff; + v[3].color = 0xffffffff; + + pDev->SetVertexShader(D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1); + pDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, v, sizeof(_TRANS_LIT_TEX_VERTEX)); + + reset(); + return true; +} + +Int ScreenBrightnessFilter::set(FilterModes mode) +{ + HRESULT hr; + + // Set up render states for fullscreen quad + VertexMaterialClass *vmat = VertexMaterialClass::Get_Preset(VertexMaterialClass::PRELIT_DIFFUSE); + DX8Wrapper::Set_Material(vmat); + REF_PTR_RELEASE(vmat); + DX8Wrapper::Set_Shader(ShaderClass::_PresetOpaqueShader); + DX8Wrapper::Set_Texture(0, NULL); + DX8Wrapper::Apply_Render_State_Changes(); + + DX8Wrapper::Set_DX8_Render_State(D3DRS_ZFUNC, D3DCMP_ALWAYS); + DX8Wrapper::Set_DX8_Render_State(D3DRS_ZWRITEENABLE, FALSE); + DX8Wrapper::Apply_Render_State_Changes(); + + LPDIRECT3DDEVICE8 pDev = DX8Wrapper::_Get_D3D_Device8(); + hr = pDev->SetPixelShader(m_pixelShaderHandle); + + // Calculate brightness parameters based on GenTool's algorithm + // Range: -128 to +256 + // -128 to 0: darken (lift black level down, reduce brightness) + // 0: neutral (no adjustment) + // 1 to 128: lift black level linearly + // 129 to 256: lift brightness while preserving black level (gamma adjustment) + + float blackLift = 0.0f; + float gammaAdjust = 1.0f; + float brightnessAdd = 0.0f; + + if (m_brightnessValue < 0) + { + // Darken: negative black lift + blackLift = (float)m_brightnessValue / 128.0f; // Range: -1.0 to 0.0 + } + else if (m_brightnessValue <= 128) + { + // Lift black level linearly + blackLift = (float)m_brightnessValue / 128.0f; // Range: 0.0 to 1.0 + } + else + { + // Lift brightness while preserving black level (gamma/brightness boost) + // Range 129-256 maps to brightness increase + float adjustAmount = (float)(m_brightnessValue - 128) / 128.0f; // 0.0 to 1.0 + gammaAdjust = 1.0f / (1.0f + adjustAmount); // Inverse gamma for brightening + } + + // Set pixel shader constants + // c0: (blackLift, gammaAdjust, brightnessAdd, unused) + DX8Wrapper::_Get_D3D_Device8()->SetPixelShaderConstant(0, D3DXVECTOR4(blackLift, gammaAdjust, brightnessAdd, 1.0f), 1); + + return TRUE; +} + +Bool ScreenBrightnessFilter::setup(FilterModes mode) +{ + // Brightness filter doesn't need special setup + return true; +} + +void ScreenBrightnessFilter::setBrightnessValue(Int value) +{ + // Clamp to GenTool's range + if (value < -128) value = -128; + if (value > 256) value = 256; + + m_brightnessValue = value; + m_isEnabled = (value != 0); +} + +Int ScreenBrightnessFilter::getBrightnessValue() +{ + return m_brightnessValue; +} + +/*===========================================================================================*/ +/*========= Fixed-Function Version =============*/ +/*===========================================================================================*/ + +Int ScreenBrightnessFilterFixedFunction::m_brightnessValue = 0; +Bool ScreenBrightnessFilterFixedFunction::m_isEnabled = false; + +Int ScreenBrightnessFilterFixedFunction::init(void) +{ + m_brightnessValue = 0; + m_isEnabled = false; + + if (!W3DShaderManager::canRenderToTexture()) { + return false; + } + + // Fixed-function always supported on DirectX 8 hardware + return TRUE; +} + +Int ScreenBrightnessFilterFixedFunction::shutdown(void) +{ + return TRUE; +} + +void ScreenBrightnessFilterFixedFunction::reset(void) +{ + ShaderClass::Invalidate(); + DX8Wrapper::_Get_D3D_Device8()->SetTexture(0, NULL); +} + +Bool ScreenBrightnessFilterFixedFunction::preRender(Bool &skipRender, CustomScenePassModes &scenePassMode) +{ + if (m_brightnessValue == 0) + { + skipRender = false; + return false; + } + + skipRender = false; + W3DShaderManager::startRenderToTexture(); + return true; +} + +Bool ScreenBrightnessFilterFixedFunction::postRender(FilterModes mode, Coord2D &scrollDelta, Bool &doExtraRender) +{ + if (m_brightnessValue == 0) + { + return false; + } + + IDirect3DTexture8 * tex = W3DShaderManager::endRenderToTexture(); + DEBUG_ASSERTCRASH(tex, ("Require rendered texture.")); + if (!tex) return false; + if (!set(mode)) return false; + + LPDIRECT3DDEVICE8 pDev = DX8Wrapper::_Get_D3D_Device8(); + + struct _TRANS_LIT_TEX_VERTEX { + D3DXVECTOR4 p; + DWORD color; + float u; + float v; + } v[4]; + + Int xpos, ypos, width, height; + + pDev->SetTexture(0, tex); + TheTacticalView->getOrigin(&xpos, &ypos); + width = TheTacticalView->getWidth(); + height = TheTacticalView->getHeight(); + + // Create fullscreen quad + v[0].p = D3DXVECTOR4(xpos + width - 0.5f, ypos + height - 0.5f, 0.0f, 1.0f); + v[0].u = (Real)(xpos + width) / (Real)TheDisplay->getWidth(); v[0].v = (Real)(ypos + height) / (Real)TheDisplay->getHeight(); + v[1].p = D3DXVECTOR4(xpos + width - 0.5f, ypos - 0.5f, 0.0f, 1.0f); + v[1].u = (Real)(xpos + width) / (Real)TheDisplay->getWidth(); v[1].v = (Real)(ypos) / (Real)TheDisplay->getHeight(); + v[2].p = D3DXVECTOR4(xpos - 0.5f, ypos + height - 0.5f, 0.0f, 1.0f); + v[2].u = (Real)(xpos) / (Real)TheDisplay->getWidth(); v[2].v = (Real)(ypos + height) / (Real)TheDisplay->getHeight(); + v[3].p = D3DXVECTOR4(xpos - 0.5f, ypos - 0.5f, 0.0f, 1.0f); + v[3].u = (Real)(xpos) / (Real)TheDisplay->getWidth(); v[3].v = (Real)(ypos) / (Real)TheDisplay->getHeight(); + + // Calculate brightness modulation via vertex color + // This is a simpler approximation for cards without pixel shaders + DWORD colorMod = 0xff808080; // Default neutral gray + if (m_brightnessValue < 0) + { + // Darken + int val = 128 + m_brightnessValue; // 0-128 + colorMod = D3DCOLOR_RGBA(val, val, val, 255); + } + else if (m_brightnessValue <= 128) + { + // Brighten via additive + int val = 128 + (m_brightnessValue / 2); // 128-192 + colorMod = D3DCOLOR_RGBA(val, val, val, 255); + } + else + { + // Maximum brightness + colorMod = 0xffffffff; + } + + v[0].color = colorMod; + v[1].color = colorMod; + v[2].color = colorMod; + v[3].color = colorMod; + + pDev->SetVertexShader(D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1); + pDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, v, sizeof(_TRANS_LIT_TEX_VERTEX)); + + reset(); + return true; +} + +Int ScreenBrightnessFilterFixedFunction::set(FilterModes mode) +{ + // Set up render states for fullscreen quad + VertexMaterialClass *vmat = VertexMaterialClass::Get_Preset(VertexMaterialClass::PRELIT_DIFFUSE); + DX8Wrapper::Set_Material(vmat); + REF_PTR_RELEASE(vmat); + DX8Wrapper::Set_Shader(ShaderClass::_PresetOpaqueShader); + DX8Wrapper::Set_Texture(0, NULL); + DX8Wrapper::Apply_Render_State_Changes(); + + DX8Wrapper::Set_DX8_Render_State(D3DRS_ZFUNC, D3DCMP_ALWAYS); + DX8Wrapper::Set_DX8_Render_State(D3DRS_ZWRITEENABLE, FALSE); + DX8Wrapper::Apply_Render_State_Changes(); + + // Use texture stage states to modulate brightness + LPDIRECT3DDEVICE8 pDev = DX8Wrapper::_Get_D3D_Device8(); + pDev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + pDev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + pDev->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + pDev->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + pDev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); + + return TRUE; +} + +Bool ScreenBrightnessFilterFixedFunction::setup(FilterModes mode) +{ + return true; +} + +void ScreenBrightnessFilterFixedFunction::setBrightnessValue(Int value) +{ + if (value < -128) value = -128; + if (value > 256) value = 256; + + m_brightnessValue = value; + m_isEnabled = (value != 0); +} + +Int ScreenBrightnessFilterFixedFunction::getBrightnessValue() +{ + return m_brightnessValue; +} + + +// TheSuperHackers @feature bobtista 11/02/2025 Helper function to set brightness on both filter implementations +// This is called from OptionsMenu to update brightness for whichever filter is active +void setBrightnessFilterValue(Int value) +{ + ScreenBrightnessFilter::setBrightnessValue(value); + ScreenBrightnessFilterFixedFunction::setBrightnessValue(value); +} + From f6e6a73c04852de9851c7117cb156af5ea39fdfd Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Sun, 2 Nov 2025 12:32:23 -0500 Subject: [PATCH 2/6] feat(video): add brightness adjustment pixel shader --- Generals/Run/shaders/brightness.pso | 30 +++++++++++++++++++++++++++ GeneralsMD/Run/shaders/brightness.pso | 30 +++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 Generals/Run/shaders/brightness.pso create mode 100644 GeneralsMD/Run/shaders/brightness.pso diff --git a/Generals/Run/shaders/brightness.pso b/Generals/Run/shaders/brightness.pso new file mode 100644 index 0000000000..509392f240 --- /dev/null +++ b/Generals/Run/shaders/brightness.pso @@ -0,0 +1,30 @@ +; Brightness Adjustment Pixel Shader +; For DirectX 8.1 Pixel Shader 1.1 +; Author: @bobtista, November 2025 +; +; Constants: +; c0.x = black lift amount (-1.0 to 1.0) +; c0.y = gamma adjustment (inverse gamma value) +; c0.z = brightness add amount +; c0.w = unused +; +; Registers: +; t0 = texture coordinates +; v0 = vertex color (currently unused, set to white) + +ps.1.1 + +; Sample the texture +tex t0 + +; Add black lift +; r0 = texture color + black lift +add r0, t0, c0.x + +; For basic brightness: +; Modulate with a brightness factor +; Since we can't do pow() in PS 1.1, we use a simpler linear adjustment +mul r0, r0, c0.y + +; Clamp to valid range (handled by hardware) + diff --git a/GeneralsMD/Run/shaders/brightness.pso b/GeneralsMD/Run/shaders/brightness.pso new file mode 100644 index 0000000000..509392f240 --- /dev/null +++ b/GeneralsMD/Run/shaders/brightness.pso @@ -0,0 +1,30 @@ +; Brightness Adjustment Pixel Shader +; For DirectX 8.1 Pixel Shader 1.1 +; Author: @bobtista, November 2025 +; +; Constants: +; c0.x = black lift amount (-1.0 to 1.0) +; c0.y = gamma adjustment (inverse gamma value) +; c0.z = brightness add amount +; c0.w = unused +; +; Registers: +; t0 = texture coordinates +; v0 = vertex color (currently unused, set to white) + +ps.1.1 + +; Sample the texture +tex t0 + +; Add black lift +; r0 = texture color + black lift +add r0, t0, c0.x + +; For basic brightness: +; Modulate with a brightness factor +; Since we can't do pow() in PS 1.1, we use a simpler linear adjustment +mul r0, r0, c0.y + +; Clamp to valid range (handled by hardware) + From c98afb40653e9a1ff96355b916fd7e1a93259d6a Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Sun, 2 Nov 2025 12:32:25 -0500 Subject: [PATCH 3/6] feat(video): add brightness filter to FilterTypes and FilterModes enums --- Generals/Code/GameEngine/Include/GameClient/CommandXlat.h | 4 +++- GeneralsMD/Code/GameEngine/Include/GameClient/CommandXlat.h | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Generals/Code/GameEngine/Include/GameClient/CommandXlat.h b/Generals/Code/GameEngine/Include/GameClient/CommandXlat.h index b7f5e88b5d..d2c79976e1 100644 --- a/Generals/Code/GameEngine/Include/GameClient/CommandXlat.h +++ b/Generals/Code/GameEngine/Include/GameClient/CommandXlat.h @@ -76,6 +76,7 @@ enum FilterTypes CPP_11(: Int) FT_VIEW_BW_FILTER, //filter to apply a black & white filter to the screen. FT_VIEW_MOTION_BLUR_FILTER, //filter to apply motion blur filter to screen. FT_VIEW_CROSSFADE, /// Date: Sun, 2 Nov 2025 12:32:27 -0500 Subject: [PATCH 4/6] feat(video): register brightness filter in W3DShaderManager --- .../W3DDevice/GameClient/W3DShaderManager.cpp | 16 ++++++++++++++++ .../W3DDevice/GameClient/W3DShaderManager.cpp | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DShaderManager.cpp b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DShaderManager.cpp index 2fedaa86ea..d4d2f0389d 100644 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DShaderManager.cpp +++ b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DShaderManager.cpp @@ -62,6 +62,7 @@ #include "W3DDevice/GameClient/W3DShroud.h" #include "W3DDevice/GameClient/HeightMap.h" #include "W3DDevice/GameClient/W3DCustomScene.h" +#include "W3DDevice/GameClient/W3DBrightnessFilter.h" #include "GameClient/View.h" #include "GameClient/CommandXlat.h" #include "GameClient/Display.h" @@ -129,6 +130,20 @@ W3DFilterInterface *ScreenBWFilterList[]= NULL }; +/*========= ScreenBrightnessFilter =============================================================*/ +///applies brightness/gamma adjustment to viewport. + +ScreenBrightnessFilter screenBrightnessFilter; +ScreenBrightnessFilterFixedFunction screenBrightnessFilterFixedFunction; //fallback version for cards without pixel shaders. + +///List of different Brightness shader implementations in order of preference +W3DFilterInterface *ScreenBrightnessFilterList[]= +{ + &screenBrightnessFilter, + &screenBrightnessFilterFixedFunction, //fallback version for cards without pixel shaders. + NULL +}; + Int ScreenBWFilter::init(void) { Int res; @@ -2304,6 +2319,7 @@ W3DFilterInterface **MasterFilterList[]= ScreenBWFilterList, ScreenMotionBlurFilterList, ScreenCrossFadeFilterList, + ScreenBrightnessFilterList, NULL }; diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DShaderManager.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DShaderManager.cpp index 5811dccd33..e2c724a46c 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DShaderManager.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DShaderManager.cpp @@ -63,6 +63,7 @@ #include "W3DDevice/GameClient/HeightMap.h" #include "W3DDevice/GameClient/W3DCustomScene.h" #include "W3DDevice/GameClient/W3DSmudge.h" +#include "W3DDevice/GameClient/W3DBrightnessFilter.h" #include "GameClient/View.h" #include "GameClient/CommandXlat.h" #include "GameClient/Display.h" @@ -140,6 +141,20 @@ W3DFilterInterface *ScreenDefaultFilterList[]= NULL }; +/*========= ScreenBrightnessFilter =============================================================*/ +///applies brightness/gamma adjustment to viewport. + +ScreenBrightnessFilter screenBrightnessFilter; +ScreenBrightnessFilterFixedFunction screenBrightnessFilterFixedFunction; //fallback version for cards without pixel shaders. + +///List of different Brightness shader implementations in order of preference +W3DFilterInterface *ScreenBrightnessFilterList[]= +{ + &screenBrightnessFilter, + &screenBrightnessFilterFixedFunction, //fallback version for cards without pixel shaders. + NULL +}; + Int ScreenDefaultFilter::init(void) { if (!W3DShaderManager::canRenderToTexture()) { @@ -2558,6 +2573,7 @@ W3DFilterInterface **MasterFilterList[]= ScreenBWFilterList, ScreenMotionBlurFilterList, ScreenCrossFadeFilterList, + ScreenBrightnessFilterList, NULL }; From b6aa0a93b7ff8b52916768b8a9606a24018d4f95 Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Sun, 2 Nov 2025 12:32:29 -0500 Subject: [PATCH 5/6] feat(video): wire options menu brightness slider to post-processing filter --- .../GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp | 11 +++++++++++ .../GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp | 11 +++++++++++ 2 files changed, 22 insertions(+) diff --git a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp index bd0e1eec75..f88b0f25da 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp @@ -1452,6 +1452,17 @@ static void saveOptions( void ) { TheWritableGlobalData->m_displayGamma = gammaval; TheDisplay->setGamma(TheGlobalData->m_displayGamma,0.0f, 1.0f, FALSE); } + + // TheSuperHackers @feature bobtista 11/02/2025 Map slider value to GenTool brightness range (-128 to +256) + // Slider: 0=darkest, 50=neutral, 100=brightest + // Formula: brightness = (val - 50) * 7.68, clamped to [-128, 256] + Int brightness = static_cast((val - 50) * 7.68f); + if (brightness < -128) brightness = -128; + if (brightness > 256) brightness = 256; + + // Apply brightness to post-processing filter + extern void setBrightnessFilterValue(Int value); // Forward declaration + setBrightnessFilterValue(brightness); } //------------------------------------------------------------------------------------------------- diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp index 3ca68e26b8..b537abe210 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp @@ -1512,6 +1512,17 @@ static void saveOptions( void ) { TheWritableGlobalData->m_displayGamma = gammaval; TheDisplay->setGamma(TheGlobalData->m_displayGamma,0.0f, 1.0f, FALSE); } + + // TheSuperHackers @feature bobtista 11/02/2025 Map slider value to GenTool brightness range (-128 to +256) + // Slider: 0=darkest, 50=neutral, 100=brightest + // Formula: brightness = (val - 50) * 7.68, clamped to [-128, 256] + Int brightness = static_cast((val - 50) * 7.68f); + if (brightness < -128) brightness = -128; + if (brightness > 256) brightness = 256; + + // Apply brightness to post-processing filter + extern void setBrightnessFilterValue(Int value); // Forward declaration + setBrightnessFilterValue(brightness); } //------------------------------------------------------------------------------------------------- From 5028ef72036480d495b5d6a30003af90ea3d6a4f Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Sun, 2 Nov 2025 12:32:30 -0500 Subject: [PATCH 6/6] feat(video): enable brightness filter and remove windowed mode restriction --- .../Source/W3DDevice/GameClient/W3DDisplay.cpp | 14 +++++++++++--- .../Source/W3DDevice/GameClient/W3DDisplay.cpp | 14 +++++++++++--- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp index e0ef98d9ae..027dc56cfd 100644 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp +++ b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp @@ -489,9 +489,9 @@ void W3DDisplay::getDisplayModeDescription(Int modeIndex, Int *xres, Int *yres, void W3DDisplay::setGamma(Real gamma, Real bright, Real contrast, Bool calibrate) { - if (m_windowed) - return; //we don't allow gamma to change in window because it would affect desktop. - + // TheSuperHackers @feature bobtista 11/02/2025 Brightness is now handled by post-processing filter + // Keep old gamma ramp code for backward compatibility, but it's no longer the primary method + // The windowed mode check is removed since the filter works in all modes DX8Wrapper::Set_Gamma(gamma,bright,contrast,calibrate, false); } @@ -763,6 +763,14 @@ void W3DDisplay::init( void ) init3DScene(); W3DShaderManager::init(); + // TheSuperHackers @feature bobtista 11/02/2025 Enable brightness post-processing filter + // The filter will only render when brightness is non-zero (checked in preRender()) + if (TheTacticalView) + { + TheTacticalView->setViewFilter(FT_VIEW_BRIGHTNESS_FILTER); + TheTacticalView->setViewFilterMode(FM_VIEW_BRIGHTNESS_ADJUST); + } + // Create and initialize the debug display m_nativeDebugDisplay = NEW W3DDebugDisplay(); m_debugDisplay = m_nativeDebugDisplay; diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp index 61a20797cf..3bd7138c0e 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp @@ -538,9 +538,9 @@ void W3DDisplay::getDisplayModeDescription(Int modeIndex, Int *xres, Int *yres, void W3DDisplay::setGamma(Real gamma, Real bright, Real contrast, Bool calibrate) { - if (m_windowed) - return; //we don't allow gamma to change in window because it would affect desktop. - + // TheSuperHackers @feature bobtista 11/02/2025 Brightness is now handled by post-processing filter + // Keep old gamma ramp code for backward compatibility, but it's no longer the primary method + // The windowed mode check is removed since the filter works in all modes DX8Wrapper::Set_Gamma(gamma,bright,contrast,calibrate, false); } @@ -813,6 +813,14 @@ void W3DDisplay::init( void ) init3DScene(); W3DShaderManager::init(); + // TheSuperHackers @feature bobtista 11/02/2025 Enable brightness post-processing filter + // The filter will only render when brightness is non-zero (checked in preRender()) + if (TheTacticalView) + { + TheTacticalView->setViewFilter(FT_VIEW_BRIGHTNESS_FILTER); + TheTacticalView->setViewFilterMode(FM_VIEW_BRIGHTNESS_ADJUST); + } + // Create and initialize the debug display m_nativeDebugDisplay = NEW W3DDebugDisplay(); m_debugDisplay = m_nativeDebugDisplay;