From 42f2aea4e15ba53784dd931a98cfb7002ccf0dcf Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Fri, 10 Apr 2026 14:42:32 -0400 Subject: [PATCH 1/4] feat(ww3d2): add IRenderBackend abstract interface --- .../Source/WWVegas/WW3D2/CMakeLists.txt | 1 + .../Source/WWVegas/WW3D2/IRenderBackend.h | 224 ++++++++++++++++++ 2 files changed, 225 insertions(+) create mode 100644 Core/Libraries/Source/WWVegas/WW3D2/IRenderBackend.h diff --git a/Core/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt b/Core/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt index 9ff4754aec9..7663d2eb968 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt +++ b/Core/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt @@ -90,6 +90,7 @@ set(WW3D2_SRC htree.h #htreemgr.cpp #htreemgr.h + IRenderBackend.h intersec.cpp intersec.h intersec.inl diff --git a/Core/Libraries/Source/WWVegas/WW3D2/IRenderBackend.h b/Core/Libraries/Source/WWVegas/WW3D2/IRenderBackend.h new file mode 100644 index 00000000000..2071d987b55 --- /dev/null +++ b/Core/Libraries/Source/WWVegas/WW3D2/IRenderBackend.h @@ -0,0 +1,224 @@ +/* +** 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 . +*/ + +// TheSuperHackers @refactor bobtista 10/04/2026 Introduce IRenderBackend +// abstract interface so WW3D2 rendering can be re-targeted to modern backends +// (bgfx, Diligent, etc.) while the existing DX8 path stays functional as the +// reference implementation. See Core/Libraries/Source/WWVegas/WW3D2/RENDER_BACKEND.md. + +#pragma once + +#include "ww3dformat.h" + +// ----------------------------------------------------------------------------- +// Forward declarations +// ----------------------------------------------------------------------------- +// +// Kept lightweight deliberately. IRenderBackend.h must be includable without +// dragging in the full WW3D2 header graph, so callers only pay for the types +// they actually use. +// +// All W3D classes passed through this interface are referenced by pointer or +// reference; none of them need a full definition in this header. + +class ShaderClass; +class VertexMaterialClass; +class TextureBaseClass; +class TextureClass; +class ZTextureClass; +class SurfaceClass; +class VertexBufferClass; +class IndexBufferClass; +class DynamicVBAccessClass; +class DynamicIBAccessClass; +class LightClass; +class LightEnvironmentClass; +class Matrix4x4; +class Matrix3D; +class Vector3; + +// ----------------------------------------------------------------------------- +// POD types owned by the interface +// ----------------------------------------------------------------------------- + +enum TransformKind +{ + // Values chosen so they can be mapped directly to D3DTS_* inside the + // DX8Backend without a branch. A modern backend ignores these indices + // and uses whichever matrix storage is convenient for it. + RB_TRANSFORM_VIEW = 2, // D3DTS_VIEW + RB_TRANSFORM_PROJECTION = 3, // D3DTS_PROJECTION + RB_TRANSFORM_WORLD = 256 // D3DTS_WORLD +}; + +struct RenderBackendViewport +{ + unsigned int x; + unsigned int y; + unsigned int width; + unsigned int height; + float min_z; + float max_z; +}; + +// ----------------------------------------------------------------------------- +// IRenderBackend — abstract W3D-facing rendering interface +// ----------------------------------------------------------------------------- +// +// This interface exposes the *high-level* subset of DX8Wrapper's public API: +// the calls that take and return W3D types (ShaderClass, TextureBaseClass, +// Matrix4x4, etc.) and are backend-neutral by construction. The low-level +// D3D8-specific entry points on DX8Wrapper (Set_DX8_Render_State, +// _Create_DX8_Texture, _Get_D3D_Device8, etc.) are NOT exposed here and +// remain reachable only through DX8Wrapper's static methods. Code that +// needs them is DX8-only and must be migrated during later phases. +// +// **Method names intentionally match the existing DX8Wrapper names** so +// that migrating callers is a mechanical `DX8Wrapper::X(...)` → +// `g_renderBackend->X(...)` rewrite with minimal diff noise. +// +// **This header is included from VC6-compiled translation units** (the +// DX8 reference path and the tools). Keep it C++98-compatible: +// - No , no , no or other STL in signatures +// - No `override`, `= default`, `= delete`, `auto`, `constexpr` +// - `nullptr` is OK (the project has a VC6 shim) +// - POD structs for parameter bundles +// - Forward-declare W3D types rather than including their headers +// +// Implementations (DX8Backend.cpp, future BgfxBackend.cpp, etc.) can use +// whatever C++ features the project's main build allows. + +class IRenderBackend +{ +public: + virtual ~IRenderBackend() {} + + // ------------------------------------------------------------------------- + // Device state queries + // ------------------------------------------------------------------------- + + virtual bool Is_Device_Lost() const = 0; + virtual bool Has_Stencil() = 0; + virtual WW3DFormat Get_Back_Buffer_Format() = 0; + virtual SurfaceClass * Get_Back_Buffer(unsigned int num) = 0; + virtual void Set_Gamma(float gamma, float bright, float contrast, bool calibrate, bool uselimit) = 0; + + // ------------------------------------------------------------------------- + // Frame lifecycle + // ------------------------------------------------------------------------- + + virtual void Begin_Scene() = 0; + virtual void End_Scene(bool flip_frame) = 0; + virtual void Flip_To_Primary() = 0; + virtual void Clear(bool clear_color, bool clear_z_stencil, + const Vector3 & color, + float dest_alpha, float z, unsigned int stencil) = 0; + virtual void Set_Viewport(const RenderBackendViewport & viewport) = 0; + + // ------------------------------------------------------------------------- + // Vertex / index buffers + // ------------------------------------------------------------------------- + + virtual void Set_Vertex_Buffer(const VertexBufferClass * vb, unsigned int stream) = 0; + virtual void Set_Vertex_Buffer(const DynamicVBAccessClass & vba) = 0; + virtual void Set_Index_Buffer(const IndexBufferClass * ib, unsigned short index_base_offset) = 0; + virtual void Set_Index_Buffer(const DynamicIBAccessClass & iba, unsigned short index_base_offset) = 0; + virtual void Set_Index_Buffer_Index_Offset(unsigned int offset) = 0; + + // ------------------------------------------------------------------------- + // State: shaders, materials, textures + // ------------------------------------------------------------------------- + + virtual void Set_Shader(const ShaderClass & shader) = 0; + virtual void Get_Shader(ShaderClass & shader) = 0; + virtual void Set_Material(const VertexMaterialClass * material) = 0; + virtual void Set_Texture(unsigned int stage, TextureBaseClass * texture) = 0; + + virtual void Apply_Render_State_Changes() = 0; + virtual void Apply_Default_State() = 0; + virtual void Invalidate_Cached_Render_States() = 0; + + // ------------------------------------------------------------------------- + // Transforms + // ------------------------------------------------------------------------- + + virtual void Set_Transform(TransformKind transform, const Matrix4x4 & m) = 0; + virtual void Set_Transform(TransformKind transform, const Matrix3D & m) = 0; + virtual void Get_Transform(TransformKind transform, Matrix4x4 & m) = 0; + virtual void Set_World_Identity() = 0; + virtual void Set_View_Identity() = 0; + virtual bool Is_World_Identity() = 0; + virtual bool Is_View_Identity() = 0; + virtual void Set_Projection_Transform_With_Z_Bias(const Matrix4x4 & matrix, + float znear, float zfar) = 0; + + // ------------------------------------------------------------------------- + // Lighting and fog + // ------------------------------------------------------------------------- + + virtual void Set_Light(unsigned int index, const LightClass & light) = 0; + virtual void Set_Ambient(const Vector3 & color) = 0; + virtual const Vector3 & Get_Ambient() const = 0; + virtual void Set_Fog(bool enable, const Vector3 & color, float start, float end) = 0; + virtual bool Get_Fog_Enable() const = 0; + virtual void Set_Light_Environment(LightEnvironmentClass * light_env) = 0; + virtual LightEnvironmentClass * Get_Light_Environment() const = 0; + + // ------------------------------------------------------------------------- + // Draw calls + // ------------------------------------------------------------------------- + + virtual void Draw_Triangles(unsigned short start_index, + unsigned short polygon_count, + unsigned short min_vertex_index, + unsigned short vertex_count) = 0; + + virtual void Draw_Triangles(unsigned int buffer_type, + unsigned short start_index, + unsigned short polygon_count, + unsigned short min_vertex_index, + unsigned short vertex_count) = 0; + + virtual void Draw_Strip(unsigned short start_index, + unsigned short index_count, + unsigned short min_vertex_index, + unsigned short vertex_count) = 0; + + // ------------------------------------------------------------------------- + // Programmable pipeline (GPU vertex / pixel shaders) + // ------------------------------------------------------------------------- + // + // These correspond to DX8's programmable shader slots. Modern backends + // will re-interpret the handles internally; the interface treats the + // shader id as an opaque unsigned long. + + virtual void Set_Vertex_Shader(unsigned long vertex_shader) = 0; + virtual void Set_Pixel_Shader(unsigned long pixel_shader) = 0; + virtual void Set_Vertex_Shader_Constant(int reg, const void * data, int count) = 0; + virtual void Set_Pixel_Shader_Constant(int reg, const void * data, int count) = 0; + + // ------------------------------------------------------------------------- + // Render targets + // ------------------------------------------------------------------------- + + virtual TextureClass * Create_Render_Target(int width, int height, WW3DFormat format) = 0; + virtual void Set_Render_Target_With_Z(TextureClass * texture, ZTextureClass * ztexture) = 0; + virtual bool Is_Render_To_Texture() = 0; + virtual void Set_Shadow_Map(int idx, ZTextureClass * ztex) = 0; + virtual ZTextureClass * Get_Shadow_Map(int idx) = 0; +}; From 97a23e419f6da92b000d66349d1fdc9b42e97e7f Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Fri, 10 Apr 2026 14:45:14 -0400 Subject: [PATCH 2/4] feat(ww3d2): add DX8Backend adapter forwarding to DX8Wrapper statics --- .../Source/WWVegas/WW3D2/CMakeLists.txt | 2 + .../Source/WWVegas/WW3D2/DX8Backend.cpp | 321 ++++++++++++++++++ .../Source/WWVegas/WW3D2/DX8Backend.h | 123 +++++++ 3 files changed, 446 insertions(+) create mode 100644 Core/Libraries/Source/WWVegas/WW3D2/DX8Backend.cpp create mode 100644 Core/Libraries/Source/WWVegas/WW3D2/DX8Backend.h diff --git a/Core/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt b/Core/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt index 7663d2eb968..8aaf960fa37 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt +++ b/Core/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt @@ -43,6 +43,8 @@ set(WW3D2_SRC distlod.cpp distlod.h dllist.h + DX8Backend.cpp + DX8Backend.h dx8caps.cpp dx8caps.h #dx8fvf.cpp diff --git a/Core/Libraries/Source/WWVegas/WW3D2/DX8Backend.cpp b/Core/Libraries/Source/WWVegas/WW3D2/DX8Backend.cpp new file mode 100644 index 00000000000..542a776a22d --- /dev/null +++ b/Core/Libraries/Source/WWVegas/WW3D2/DX8Backend.cpp @@ -0,0 +1,321 @@ +/* +** 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 . +*/ + +// TheSuperHackers @refactor bobtista 10/04/2026 DX8Backend forwarding adapter. +// Every method in this file is a one-line trampoline to the existing +// DX8Wrapper static API. Keep it that way — if behavior needs to change it +// should change in DX8Wrapper, not here. + +#include "DX8Backend.h" + +#include "dx8wrapper.h" +#include "vector3.h" +#include "matrix4.h" +#include "matrix3d.h" +#include "light.h" +#include "lightenvironment.h" + +DX8Backend::DX8Backend() +{ +} + +DX8Backend::~DX8Backend() +{ +} + +// -- Device state queries ---------------------------------------------------- + +bool DX8Backend::Is_Device_Lost() const +{ + return DX8Wrapper::Is_Device_Lost(); +} + +bool DX8Backend::Has_Stencil() +{ + return DX8Wrapper::Has_Stencil(); +} + +WW3DFormat DX8Backend::Get_Back_Buffer_Format() +{ + return DX8Wrapper::getBackBufferFormat(); +} + +SurfaceClass * DX8Backend::Get_Back_Buffer(unsigned int num) +{ + return DX8Wrapper::_Get_DX8_Back_Buffer(num); +} + +void DX8Backend::Set_Gamma(float gamma, float bright, float contrast, bool calibrate, bool uselimit) +{ + DX8Wrapper::Set_Gamma(gamma, bright, contrast, calibrate, uselimit); +} + +// -- Frame lifecycle --------------------------------------------------------- + +void DX8Backend::Begin_Scene() +{ + DX8Wrapper::Begin_Scene(); +} + +void DX8Backend::End_Scene(bool flip_frame) +{ + DX8Wrapper::End_Scene(flip_frame); +} + +void DX8Backend::Flip_To_Primary() +{ + DX8Wrapper::Flip_To_Primary(); +} + +void DX8Backend::Clear(bool clear_color, bool clear_z_stencil, + const Vector3 & color, + float dest_alpha, float z, unsigned int stencil) +{ + DX8Wrapper::Clear(clear_color, clear_z_stencil, color, dest_alpha, z, stencil); +} + +void DX8Backend::Set_Viewport(const RenderBackendViewport & viewport) +{ + D3DVIEWPORT8 vp; + vp.X = viewport.x; + vp.Y = viewport.y; + vp.Width = viewport.width; + vp.Height = viewport.height; + vp.MinZ = viewport.min_z; + vp.MaxZ = viewport.max_z; + DX8Wrapper::Set_Viewport(&vp); +} + +// -- Vertex / index buffers -------------------------------------------------- + +void DX8Backend::Set_Vertex_Buffer(const VertexBufferClass * vb, unsigned int stream) +{ + DX8Wrapper::Set_Vertex_Buffer(vb, stream); +} + +void DX8Backend::Set_Vertex_Buffer(const DynamicVBAccessClass & vba) +{ + DX8Wrapper::Set_Vertex_Buffer(vba); +} + +void DX8Backend::Set_Index_Buffer(const IndexBufferClass * ib, unsigned short index_base_offset) +{ + DX8Wrapper::Set_Index_Buffer(ib, index_base_offset); +} + +void DX8Backend::Set_Index_Buffer(const DynamicIBAccessClass & iba, unsigned short index_base_offset) +{ + DX8Wrapper::Set_Index_Buffer(iba, index_base_offset); +} + +void DX8Backend::Set_Index_Buffer_Index_Offset(unsigned int offset) +{ + DX8Wrapper::Set_Index_Buffer_Index_Offset(offset); +} + +// -- State: shaders, materials, textures ------------------------------------ + +void DX8Backend::Set_Shader(const ShaderClass & shader) +{ + DX8Wrapper::Set_Shader(shader); +} + +void DX8Backend::Get_Shader(ShaderClass & shader) +{ + DX8Wrapper::Get_Shader(shader); +} + +void DX8Backend::Set_Material(const VertexMaterialClass * material) +{ + DX8Wrapper::Set_Material(material); +} + +void DX8Backend::Set_Texture(unsigned int stage, TextureBaseClass * texture) +{ + DX8Wrapper::Set_Texture(stage, texture); +} + +void DX8Backend::Apply_Render_State_Changes() +{ + DX8Wrapper::Apply_Render_State_Changes(); +} + +void DX8Backend::Apply_Default_State() +{ + DX8Wrapper::Apply_Default_State(); +} + +void DX8Backend::Invalidate_Cached_Render_States() +{ + DX8Wrapper::Invalidate_Cached_Render_States(); +} + +// -- Transforms -------------------------------------------------------------- + +void DX8Backend::Set_Transform(TransformKind transform, const Matrix4x4 & m) +{ + DX8Wrapper::Set_Transform(static_cast(transform), m); +} + +void DX8Backend::Set_Transform(TransformKind transform, const Matrix3D & m) +{ + DX8Wrapper::Set_Transform(static_cast(transform), m); +} + +void DX8Backend::Get_Transform(TransformKind transform, Matrix4x4 & m) +{ + DX8Wrapper::Get_Transform(static_cast(transform), m); +} + +void DX8Backend::Set_World_Identity() +{ + DX8Wrapper::Set_World_Identity(); +} + +void DX8Backend::Set_View_Identity() +{ + DX8Wrapper::Set_View_Identity(); +} + +bool DX8Backend::Is_World_Identity() +{ + return DX8Wrapper::Is_World_Identity(); +} + +bool DX8Backend::Is_View_Identity() +{ + return DX8Wrapper::Is_View_Identity(); +} + +void DX8Backend::Set_Projection_Transform_With_Z_Bias(const Matrix4x4 & matrix, float znear, float zfar) +{ + DX8Wrapper::Set_Projection_Transform_With_Z_Bias(matrix, znear, zfar); +} + +// -- Lighting and fog -------------------------------------------------------- + +void DX8Backend::Set_Light(unsigned int index, const LightClass & light) +{ + DX8Wrapper::Set_Light(index, light); +} + +void DX8Backend::Set_Ambient(const Vector3 & color) +{ + DX8Wrapper::Set_Ambient(color); +} + +const Vector3 & DX8Backend::Get_Ambient() const +{ + return DX8Wrapper::Get_Ambient(); +} + +void DX8Backend::Set_Fog(bool enable, const Vector3 & color, float start, float end) +{ + DX8Wrapper::Set_Fog(enable, color, start, end); +} + +bool DX8Backend::Get_Fog_Enable() const +{ + return DX8Wrapper::Get_Fog_Enable(); +} + +void DX8Backend::Set_Light_Environment(LightEnvironmentClass * light_env) +{ + DX8Wrapper::Set_Light_Environment(light_env); +} + +LightEnvironmentClass * DX8Backend::Get_Light_Environment() const +{ + return DX8Wrapper::Get_Light_Environment(); +} + +// -- Draw calls -------------------------------------------------------------- + +void DX8Backend::Draw_Triangles(unsigned short start_index, + unsigned short polygon_count, + unsigned short min_vertex_index, + unsigned short vertex_count) +{ + DX8Wrapper::Draw_Triangles(start_index, polygon_count, min_vertex_index, vertex_count); +} + +void DX8Backend::Draw_Triangles(unsigned int buffer_type, + unsigned short start_index, + unsigned short polygon_count, + unsigned short min_vertex_index, + unsigned short vertex_count) +{ + DX8Wrapper::Draw_Triangles(buffer_type, start_index, polygon_count, min_vertex_index, vertex_count); +} + +void DX8Backend::Draw_Strip(unsigned short start_index, + unsigned short index_count, + unsigned short min_vertex_index, + unsigned short vertex_count) +{ + DX8Wrapper::Draw_Strip(start_index, index_count, min_vertex_index, vertex_count); +} + +// -- Programmable pipeline --------------------------------------------------- + +void DX8Backend::Set_Vertex_Shader(unsigned long vertex_shader) +{ + DX8Wrapper::Set_Vertex_Shader(static_cast(vertex_shader)); +} + +void DX8Backend::Set_Pixel_Shader(unsigned long pixel_shader) +{ + DX8Wrapper::Set_Pixel_Shader(static_cast(pixel_shader)); +} + +void DX8Backend::Set_Vertex_Shader_Constant(int reg, const void * data, int count) +{ + DX8Wrapper::Set_Vertex_Shader_Constant(reg, data, count); +} + +void DX8Backend::Set_Pixel_Shader_Constant(int reg, const void * data, int count) +{ + DX8Wrapper::Set_Pixel_Shader_Constant(reg, data, count); +} + +// -- Render targets ---------------------------------------------------------- + +TextureClass * DX8Backend::Create_Render_Target(int width, int height, WW3DFormat format) +{ + return DX8Wrapper::Create_Render_Target(width, height, format); +} + +void DX8Backend::Set_Render_Target_With_Z(TextureClass * texture, ZTextureClass * ztexture) +{ + DX8Wrapper::Set_Render_Target_With_Z(texture, ztexture); +} + +bool DX8Backend::Is_Render_To_Texture() +{ + return DX8Wrapper::Is_Render_To_Texture(); +} + +void DX8Backend::Set_Shadow_Map(int idx, ZTextureClass * ztex) +{ + DX8Wrapper::Set_Shadow_Map(idx, ztex); +} + +ZTextureClass * DX8Backend::Get_Shadow_Map(int idx) +{ + return DX8Wrapper::Get_Shadow_Map(idx); +} diff --git a/Core/Libraries/Source/WWVegas/WW3D2/DX8Backend.h b/Core/Libraries/Source/WWVegas/WW3D2/DX8Backend.h new file mode 100644 index 00000000000..a6a93299456 --- /dev/null +++ b/Core/Libraries/Source/WWVegas/WW3D2/DX8Backend.h @@ -0,0 +1,123 @@ +/* +** 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 . +*/ + +// TheSuperHackers @refactor bobtista 10/04/2026 DX8Backend is the reference +// implementation of IRenderBackend that forwards every virtual method to the +// existing DX8Wrapper static facade. It adds zero new rendering logic and +// performs zero behavior changes — it is pure adaptation so the rest of the +// engine can start talking to an IRenderBackend pointer while still running +// on the established DX8 path. See RENDER_BACKEND.md. + +#pragma once + +#include "IRenderBackend.h" + +class DX8Backend : public IRenderBackend +{ +public: + DX8Backend(); + virtual ~DX8Backend(); + + // -- Device state queries ------------------------------------------------- + + virtual bool Is_Device_Lost() const; + virtual bool Has_Stencil(); + virtual WW3DFormat Get_Back_Buffer_Format(); + virtual SurfaceClass * Get_Back_Buffer(unsigned int num); + virtual void Set_Gamma(float gamma, float bright, float contrast, bool calibrate, bool uselimit); + + // -- Frame lifecycle ------------------------------------------------------ + + virtual void Begin_Scene(); + virtual void End_Scene(bool flip_frame); + virtual void Flip_To_Primary(); + virtual void Clear(bool clear_color, bool clear_z_stencil, + const Vector3 & color, + float dest_alpha, float z, unsigned int stencil); + virtual void Set_Viewport(const RenderBackendViewport & viewport); + + // -- Vertex / index buffers ----------------------------------------------- + + virtual void Set_Vertex_Buffer(const VertexBufferClass * vb, unsigned int stream); + virtual void Set_Vertex_Buffer(const DynamicVBAccessClass & vba); + virtual void Set_Index_Buffer(const IndexBufferClass * ib, unsigned short index_base_offset); + virtual void Set_Index_Buffer(const DynamicIBAccessClass & iba, unsigned short index_base_offset); + virtual void Set_Index_Buffer_Index_Offset(unsigned int offset); + + // -- State: shaders, materials, textures --------------------------------- + + virtual void Set_Shader(const ShaderClass & shader); + virtual void Get_Shader(ShaderClass & shader); + virtual void Set_Material(const VertexMaterialClass * material); + virtual void Set_Texture(unsigned int stage, TextureBaseClass * texture); + virtual void Apply_Render_State_Changes(); + virtual void Apply_Default_State(); + virtual void Invalidate_Cached_Render_States(); + + // -- Transforms ----------------------------------------------------------- + + virtual void Set_Transform(TransformKind transform, const Matrix4x4 & m); + virtual void Set_Transform(TransformKind transform, const Matrix3D & m); + virtual void Get_Transform(TransformKind transform, Matrix4x4 & m); + virtual void Set_World_Identity(); + virtual void Set_View_Identity(); + virtual bool Is_World_Identity(); + virtual bool Is_View_Identity(); + virtual void Set_Projection_Transform_With_Z_Bias(const Matrix4x4 & matrix, float znear, float zfar); + + // -- Lighting and fog ----------------------------------------------------- + + virtual void Set_Light(unsigned int index, const LightClass & light); + virtual void Set_Ambient(const Vector3 & color); + virtual const Vector3 & Get_Ambient() const; + virtual void Set_Fog(bool enable, const Vector3 & color, float start, float end); + virtual bool Get_Fog_Enable() const; + virtual void Set_Light_Environment(LightEnvironmentClass * light_env); + virtual LightEnvironmentClass * Get_Light_Environment() const; + + // -- Draw calls ----------------------------------------------------------- + + virtual void Draw_Triangles(unsigned short start_index, + unsigned short polygon_count, + unsigned short min_vertex_index, + unsigned short vertex_count); + virtual void Draw_Triangles(unsigned int buffer_type, + unsigned short start_index, + unsigned short polygon_count, + unsigned short min_vertex_index, + unsigned short vertex_count); + virtual void Draw_Strip(unsigned short start_index, + unsigned short index_count, + unsigned short min_vertex_index, + unsigned short vertex_count); + + // -- Programmable pipeline ------------------------------------------------ + + virtual void Set_Vertex_Shader(unsigned long vertex_shader); + virtual void Set_Pixel_Shader(unsigned long pixel_shader); + virtual void Set_Vertex_Shader_Constant(int reg, const void * data, int count); + virtual void Set_Pixel_Shader_Constant(int reg, const void * data, int count); + + // -- Render targets ------------------------------------------------------- + + virtual TextureClass * Create_Render_Target(int width, int height, WW3DFormat format); + virtual void Set_Render_Target_With_Z(TextureClass * texture, ZTextureClass * ztexture); + virtual bool Is_Render_To_Texture(); + virtual void Set_Shadow_Map(int idx, ZTextureClass * ztex); + virtual ZTextureClass * Get_Shadow_Map(int idx); +}; From e648a3ebdeb3e9d4c0ac0cc1b078f2ac374ae4b4 Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Fri, 10 Apr 2026 14:48:34 -0400 Subject: [PATCH 3/4] feat(ww3d2): add global g_renderBackend pointer and lifecycle wiring --- .../Source/WWVegas/WW3D2/CMakeLists.txt | 2 + .../Source/WWVegas/WW3D2/RenderBackend.cpp | 48 +++++++++++++++++++ .../Source/WWVegas/WW3D2/RenderBackend.h | 42 ++++++++++++++++ .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 11 +++++ 4 files changed, 103 insertions(+) create mode 100644 Core/Libraries/Source/WWVegas/WW3D2/RenderBackend.cpp create mode 100644 Core/Libraries/Source/WWVegas/WW3D2/RenderBackend.h diff --git a/Core/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt b/Core/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt index 8aaf960fa37..dd4050fce15 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt +++ b/Core/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt @@ -158,6 +158,8 @@ set(WW3D2_SRC proto.h proxy.h rddesc.h + RenderBackend.cpp + RenderBackend.h #render2d.cpp #render2d.h render2dsentence.cpp diff --git a/Core/Libraries/Source/WWVegas/WW3D2/RenderBackend.cpp b/Core/Libraries/Source/WWVegas/WW3D2/RenderBackend.cpp new file mode 100644 index 00000000000..cf4535832f2 --- /dev/null +++ b/Core/Libraries/Source/WWVegas/WW3D2/RenderBackend.cpp @@ -0,0 +1,48 @@ +/* +** 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 . +*/ + +// TheSuperHackers @refactor bobtista 10/04/2026 Render backend global +// owner. Holds the single g_renderBackend pointer and constructs/destroys +// the concrete backend instance. See RENDER_BACKEND.md. + +#include "RenderBackend.h" +#include "DX8Backend.h" + +IRenderBackend * g_renderBackend = nullptr; + +void Init_Render_Backend() +{ + if (g_renderBackend != nullptr) + { + return; + } + + // Phase 1: the DX8 backend is the only option. Phase 2 will introduce + // a compile-time flag to pick between DX8, bgfx, and Diligent. + g_renderBackend = new DX8Backend(); +} + +void Shutdown_Render_Backend() +{ + if (g_renderBackend == nullptr) + { + return; + } + delete g_renderBackend; + g_renderBackend = nullptr; +} diff --git a/Core/Libraries/Source/WWVegas/WW3D2/RenderBackend.h b/Core/Libraries/Source/WWVegas/WW3D2/RenderBackend.h new file mode 100644 index 00000000000..7c72d195783 --- /dev/null +++ b/Core/Libraries/Source/WWVegas/WW3D2/RenderBackend.h @@ -0,0 +1,42 @@ +/* +** 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 . +*/ + +// TheSuperHackers @refactor bobtista 10/04/2026 Backend-agnostic access point +// for the global IRenderBackend instance. Engine-side code should include +// this header (not IRenderBackend.h or DX8Backend.h directly) to use the +// render backend. See RENDER_BACKEND.md. + +#pragma once + +#include "IRenderBackend.h" + +// The active rendering backend. Set by Init_Render_Backend() during +// WW3D device initialization and cleared by Shutdown_Render_Backend() +// during device teardown. Never null between those two calls. +extern IRenderBackend * g_renderBackend; + +// Create the render backend. Called by DX8Wrapper::Do_Onetime_Device_Dependent_Inits +// after the D3D device has been successfully created. +// +// Phase 1 always creates a DX8Backend. Phase 2 will add a compile-time +// option to select between DX8Backend, BgfxBackend, and DiligentBackend. +void Init_Render_Backend(); + +// Destroy the render backend. Called by DX8Wrapper::Do_Onetime_Device_Dependent_Shutdowns +// before the D3D device is released. +void Shutdown_Render_Backend(); diff --git a/Core/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/Core/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 1e420b66798..cce9691c305 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/Core/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -56,6 +56,7 @@ #include "dx8vertexbuffer.h" #include "dx8indexbuffer.h" #include "dx8renderer.h" +#include "RenderBackend.h" #include "ww3d.h" #include "camera.h" #include "wwstring.h" @@ -387,6 +388,11 @@ void DX8Wrapper::Do_Onetime_Device_Dependent_Inits() TextureLoader::Init(); Set_Default_Global_Render_States(); + + // TheSuperHackers @refactor bobtista 10/04/2026 Construct the global + // IRenderBackend instance now that the D3D device is ready. See + // Core/Libraries/Source/WWVegas/WW3D2/RENDER_BACKEND.md. + Init_Render_Backend(); } inline DWORD F2DW(float f) { return *((unsigned*)&f); } @@ -447,6 +453,11 @@ void DX8Wrapper::Invalidate_Cached_Render_States() void DX8Wrapper::Do_Onetime_Device_Dependent_Shutdowns() { + // TheSuperHackers @refactor bobtista 10/04/2026 Tear down the render + // backend before the D3D device is released so any backend-owned + // resources get released first. See RENDER_BACKEND.md. + Shutdown_Render_Backend(); + /* ** Shutdown ww3d systems */ From 1c0f02d329acf386b2d2589565600ecc15dfb94b Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Sat, 18 Apr 2026 02:01:27 -0400 Subject: [PATCH 4/4] fix(ww3d2): Update copyright headers to TheSuperHackers for new files --- Core/Libraries/Source/WWVegas/WW3D2/DX8Backend.cpp | 2 +- Core/Libraries/Source/WWVegas/WW3D2/DX8Backend.h | 2 +- Core/Libraries/Source/WWVegas/WW3D2/IRenderBackend.h | 2 +- Core/Libraries/Source/WWVegas/WW3D2/RenderBackend.cpp | 2 +- Core/Libraries/Source/WWVegas/WW3D2/RenderBackend.h | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Core/Libraries/Source/WWVegas/WW3D2/DX8Backend.cpp b/Core/Libraries/Source/WWVegas/WW3D2/DX8Backend.cpp index 542a776a22d..c6fd25950c2 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/DX8Backend.cpp +++ b/Core/Libraries/Source/WWVegas/WW3D2/DX8Backend.cpp @@ -1,6 +1,6 @@ /* ** Command & Conquer Generals Zero Hour(tm) -** Copyright 2025 Electronic Arts Inc. +** Copyright 2026 TheSuperHackers ** ** 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 diff --git a/Core/Libraries/Source/WWVegas/WW3D2/DX8Backend.h b/Core/Libraries/Source/WWVegas/WW3D2/DX8Backend.h index a6a93299456..916f6b76954 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/DX8Backend.h +++ b/Core/Libraries/Source/WWVegas/WW3D2/DX8Backend.h @@ -1,6 +1,6 @@ /* ** Command & Conquer Generals Zero Hour(tm) -** Copyright 2025 Electronic Arts Inc. +** Copyright 2026 TheSuperHackers ** ** 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 diff --git a/Core/Libraries/Source/WWVegas/WW3D2/IRenderBackend.h b/Core/Libraries/Source/WWVegas/WW3D2/IRenderBackend.h index 2071d987b55..80e9f4fdb60 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/IRenderBackend.h +++ b/Core/Libraries/Source/WWVegas/WW3D2/IRenderBackend.h @@ -1,6 +1,6 @@ /* ** Command & Conquer Generals Zero Hour(tm) -** Copyright 2025 Electronic Arts Inc. +** Copyright 2026 TheSuperHackers ** ** 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 diff --git a/Core/Libraries/Source/WWVegas/WW3D2/RenderBackend.cpp b/Core/Libraries/Source/WWVegas/WW3D2/RenderBackend.cpp index cf4535832f2..0ec35c51022 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/RenderBackend.cpp +++ b/Core/Libraries/Source/WWVegas/WW3D2/RenderBackend.cpp @@ -1,6 +1,6 @@ /* ** Command & Conquer Generals Zero Hour(tm) -** Copyright 2025 Electronic Arts Inc. +** Copyright 2026 TheSuperHackers ** ** 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 diff --git a/Core/Libraries/Source/WWVegas/WW3D2/RenderBackend.h b/Core/Libraries/Source/WWVegas/WW3D2/RenderBackend.h index 7c72d195783..ee4627d5717 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/RenderBackend.h +++ b/Core/Libraries/Source/WWVegas/WW3D2/RenderBackend.h @@ -1,6 +1,6 @@ /* ** Command & Conquer Generals Zero Hour(tm) -** Copyright 2025 Electronic Arts Inc. +** Copyright 2026 TheSuperHackers ** ** 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