From 42f2aea4e15ba53784dd931a98cfb7002ccf0dcf Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Fri, 10 Apr 2026 14:42:32 -0400 Subject: [PATCH 1/7] 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/7] 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/7] 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/7] 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 From a8f04fafc6d3e34e5aef6ba3552fb628371c4703 Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Sun, 31 May 2026 11:46:02 +1000 Subject: [PATCH 5/7] refactor(ww3d2): trim redundant comments from render backend interface --- .../Source/WWVegas/WW3D2/DX8Backend.cpp | 18 ---- .../Source/WWVegas/WW3D2/DX8Backend.h | 24 +---- .../Source/WWVegas/WW3D2/IRenderBackend.h | 99 +++---------------- .../Source/WWVegas/WW3D2/RenderBackend.cpp | 8 +- .../Source/WWVegas/WW3D2/RenderBackend.h | 19 ++-- .../Source/WWVegas/WW3D2/dx8wrapper.cpp | 5 +- 6 files changed, 26 insertions(+), 147 deletions(-) diff --git a/Core/Libraries/Source/WWVegas/WW3D2/DX8Backend.cpp b/Core/Libraries/Source/WWVegas/WW3D2/DX8Backend.cpp index c6fd25950c2..7ddbe267aef 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/DX8Backend.cpp +++ b/Core/Libraries/Source/WWVegas/WW3D2/DX8Backend.cpp @@ -38,8 +38,6 @@ DX8Backend::~DX8Backend() { } -// -- Device state queries ---------------------------------------------------- - bool DX8Backend::Is_Device_Lost() const { return DX8Wrapper::Is_Device_Lost(); @@ -65,8 +63,6 @@ void DX8Backend::Set_Gamma(float gamma, float bright, float contrast, bool calib DX8Wrapper::Set_Gamma(gamma, bright, contrast, calibrate, uselimit); } -// -- Frame lifecycle --------------------------------------------------------- - void DX8Backend::Begin_Scene() { DX8Wrapper::Begin_Scene(); @@ -101,8 +97,6 @@ void DX8Backend::Set_Viewport(const RenderBackendViewport & viewport) DX8Wrapper::Set_Viewport(&vp); } -// -- Vertex / index buffers -------------------------------------------------- - void DX8Backend::Set_Vertex_Buffer(const VertexBufferClass * vb, unsigned int stream) { DX8Wrapper::Set_Vertex_Buffer(vb, stream); @@ -128,8 +122,6 @@ 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); @@ -165,8 +157,6 @@ 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); @@ -207,8 +197,6 @@ void DX8Backend::Set_Projection_Transform_With_Z_Bias(const Matrix4x4 & matrix, 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); @@ -244,8 +232,6 @@ 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, @@ -271,8 +257,6 @@ void DX8Backend::Draw_Strip(unsigned short start_index, 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)); @@ -293,8 +277,6 @@ 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); diff --git a/Core/Libraries/Source/WWVegas/WW3D2/DX8Backend.h b/Core/Libraries/Source/WWVegas/WW3D2/DX8Backend.h index 916f6b76954..7e1cdbb8a20 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/DX8Backend.h +++ b/Core/Libraries/Source/WWVegas/WW3D2/DX8Backend.h @@ -18,10 +18,7 @@ // 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. +// existing DX8Wrapper static facade. Pure adaptation, no new rendering logic. #pragma once @@ -33,16 +30,12 @@ class DX8Backend : public IRenderBackend 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(); @@ -51,16 +44,12 @@ class DX8Backend : public IRenderBackend 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); @@ -69,8 +58,6 @@ class DX8Backend : public IRenderBackend 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); @@ -80,8 +67,6 @@ class DX8Backend : public IRenderBackend 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; @@ -90,8 +75,6 @@ class DX8Backend : public IRenderBackend 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, @@ -106,15 +89,12 @@ class DX8Backend : public IRenderBackend unsigned short min_vertex_index, unsigned short vertex_count); - // -- Programmable pipeline ------------------------------------------------ - + // The shader id is treated as an opaque unsigned long. 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(); diff --git a/Core/Libraries/Source/WWVegas/WW3D2/IRenderBackend.h b/Core/Libraries/Source/WWVegas/WW3D2/IRenderBackend.h index 80e9f4fdb60..88137f49b8d 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/IRenderBackend.h +++ b/Core/Libraries/Source/WWVegas/WW3D2/IRenderBackend.h @@ -16,25 +16,16 @@ ** 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. +// TheSuperHackers @refactor bobtista 10/04/2026 Abstract W3D-facing rendering +// interface so WW3D2 rendering can be re-targeted to other backends while the +// existing DX8 path stays as the reference implementation. #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. +// Forward declarations keep this header includable without pulling in the full +// WW3D2 header graph. All W3D types below are passed by pointer or reference. class ShaderClass; class VertexMaterialClass; @@ -52,15 +43,9 @@ 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. + // Values match D3DTS_* so DX8Backend can map them without a branch. RB_TRANSFORM_VIEW = 2, // D3DTS_VIEW RB_TRANSFORM_PROJECTION = 3, // D3DTS_PROJECTION RB_TRANSFORM_WORLD = 256 // D3DTS_WORLD @@ -76,52 +61,25 @@ struct RenderBackendViewport 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. +// Exposes the high-level subset of DX8Wrapper's public API: the calls that take +// and return W3D types (ShaderClass, TextureBaseClass, Matrix4x4, etc.). The +// low-level D3D8-specific entry points on DX8Wrapper are not exposed here and +// remain reachable only through DX8Wrapper's static methods. // -// **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. +// Method names intentionally match the existing DX8Wrapper names so migrating a +// caller is a mechanical DX8Wrapper::X(...) -> g_renderBackend->X(...) rewrite. 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; @@ -130,20 +88,12 @@ class IRenderBackend 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; @@ -153,10 +103,6 @@ class IRenderBackend 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; @@ -167,10 +113,6 @@ class IRenderBackend 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; @@ -179,10 +121,6 @@ class IRenderBackend 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, @@ -199,23 +137,12 @@ class IRenderBackend 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. - + // The shader id is treated 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; diff --git a/Core/Libraries/Source/WWVegas/WW3D2/RenderBackend.cpp b/Core/Libraries/Source/WWVegas/WW3D2/RenderBackend.cpp index 0ec35c51022..70190545323 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/RenderBackend.cpp +++ b/Core/Libraries/Source/WWVegas/WW3D2/RenderBackend.cpp @@ -16,9 +16,9 @@ ** 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. +// TheSuperHackers @refactor bobtista 10/04/2026 Render backend global owner. +// Holds the single g_renderBackend pointer and constructs/destroys the +// concrete backend instance. #include "RenderBackend.h" #include "DX8Backend.h" @@ -32,8 +32,6 @@ void Init_Render_Backend() 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(); } diff --git a/Core/Libraries/Source/WWVegas/WW3D2/RenderBackend.h b/Core/Libraries/Source/WWVegas/WW3D2/RenderBackend.h index ee4627d5717..39386ee5dd0 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/RenderBackend.h +++ b/Core/Libraries/Source/WWVegas/WW3D2/RenderBackend.h @@ -17,26 +17,19 @@ */ // 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. +// for the global IRenderBackend instance. Engine-side code should include this +// header (not IRenderBackend.h or DX8Backend.h directly) to use the backend. #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. +// The active rendering backend. Set by Init_Render_Backend() and cleared by +// Shutdown_Render_Backend(); 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. +// Create the render backend. Must be called after the render device is ready. void Init_Render_Backend(); -// Destroy the render backend. Called by DX8Wrapper::Do_Onetime_Device_Dependent_Shutdowns -// before the D3D device is released. +// Destroy the render backend. Must be called before the render 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 cce9691c305..c2c7550f98b 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/Core/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -390,8 +390,7 @@ void DX8Wrapper::Do_Onetime_Device_Dependent_Inits() 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. + // IRenderBackend instance now that the D3D device is ready. Init_Render_Backend(); } @@ -455,7 +454,7 @@ 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. + // resources get released first. Shutdown_Render_Backend(); /* From 987406ada5a8f316b85610356221de587ded88a1 Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Sun, 31 May 2026 11:46:29 +1000 Subject: [PATCH 6/7] refactor(ww3d2): move backend implementations into Backend subfolder --- .../Source/WWVegas/WW3D2/{ => Backend}/DX8Backend.cpp | 0 .../Source/WWVegas/WW3D2/{ => Backend}/DX8Backend.h | 0 .../Source/WWVegas/WW3D2/{ => Backend}/RenderBackend.cpp | 0 .../Source/WWVegas/WW3D2/{ => Backend}/RenderBackend.h | 0 Core/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt | 8 ++++---- Core/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp | 2 +- 6 files changed, 5 insertions(+), 5 deletions(-) rename Core/Libraries/Source/WWVegas/WW3D2/{ => Backend}/DX8Backend.cpp (100%) rename Core/Libraries/Source/WWVegas/WW3D2/{ => Backend}/DX8Backend.h (100%) rename Core/Libraries/Source/WWVegas/WW3D2/{ => Backend}/RenderBackend.cpp (100%) rename Core/Libraries/Source/WWVegas/WW3D2/{ => Backend}/RenderBackend.h (100%) diff --git a/Core/Libraries/Source/WWVegas/WW3D2/DX8Backend.cpp b/Core/Libraries/Source/WWVegas/WW3D2/Backend/DX8Backend.cpp similarity index 100% rename from Core/Libraries/Source/WWVegas/WW3D2/DX8Backend.cpp rename to Core/Libraries/Source/WWVegas/WW3D2/Backend/DX8Backend.cpp diff --git a/Core/Libraries/Source/WWVegas/WW3D2/DX8Backend.h b/Core/Libraries/Source/WWVegas/WW3D2/Backend/DX8Backend.h similarity index 100% rename from Core/Libraries/Source/WWVegas/WW3D2/DX8Backend.h rename to Core/Libraries/Source/WWVegas/WW3D2/Backend/DX8Backend.h diff --git a/Core/Libraries/Source/WWVegas/WW3D2/RenderBackend.cpp b/Core/Libraries/Source/WWVegas/WW3D2/Backend/RenderBackend.cpp similarity index 100% rename from Core/Libraries/Source/WWVegas/WW3D2/RenderBackend.cpp rename to Core/Libraries/Source/WWVegas/WW3D2/Backend/RenderBackend.cpp diff --git a/Core/Libraries/Source/WWVegas/WW3D2/RenderBackend.h b/Core/Libraries/Source/WWVegas/WW3D2/Backend/RenderBackend.h similarity index 100% rename from Core/Libraries/Source/WWVegas/WW3D2/RenderBackend.h rename to Core/Libraries/Source/WWVegas/WW3D2/Backend/RenderBackend.h diff --git a/Core/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt b/Core/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt index dd4050fce15..90b37a4b311 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt +++ b/Core/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt @@ -43,8 +43,10 @@ set(WW3D2_SRC distlod.cpp distlod.h dllist.h - DX8Backend.cpp - DX8Backend.h + Backend/DX8Backend.cpp + Backend/DX8Backend.h + Backend/RenderBackend.cpp + Backend/RenderBackend.h dx8caps.cpp dx8caps.h #dx8fvf.cpp @@ -158,8 +160,6 @@ 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/dx8wrapper.cpp b/Core/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index c2c7550f98b..9485afab04a 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/Core/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -56,7 +56,7 @@ #include "dx8vertexbuffer.h" #include "dx8indexbuffer.h" #include "dx8renderer.h" -#include "RenderBackend.h" +#include "Backend/RenderBackend.h" #include "ww3d.h" #include "camera.h" #include "wwstring.h" From a3d0d92616b34e3902ef6293dce2164a7b2902ae Mon Sep 17 00:00:00 2001 From: Bobby Battista Date: Sun, 31 May 2026 11:47:38 +1000 Subject: [PATCH 7/7] feat(ww3d2): add IRenderBackend Initialize and Shutdown lifecycle hooks --- Core/Libraries/Source/WWVegas/WW3D2/IRenderBackend.h | 7 +++++++ Core/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp | 5 ++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Core/Libraries/Source/WWVegas/WW3D2/IRenderBackend.h b/Core/Libraries/Source/WWVegas/WW3D2/IRenderBackend.h index 88137f49b8d..4b80eb18151 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/IRenderBackend.h +++ b/Core/Libraries/Source/WWVegas/WW3D2/IRenderBackend.h @@ -74,6 +74,13 @@ class IRenderBackend public: virtual ~IRenderBackend() {} + // Optional device lifecycle. DX8Wrapper owns the render device and calls + // these after the backend is constructed and before it is destroyed. A + // backend that drives its own device creates it in Initialize and releases + // it in Shutdown; the DX8 reference backend leaves them as no-ops. + virtual void Initialize(void * window, int width, int height) {} + virtual void Shutdown() {} + virtual bool Is_Device_Lost() const = 0; virtual bool Has_Stencil() = 0; virtual WW3DFormat Get_Back_Buffer_Format() = 0; diff --git a/Core/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/Core/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp index 9485afab04a..99070bcc382 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp +++ b/Core/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp @@ -390,8 +390,10 @@ void DX8Wrapper::Do_Onetime_Device_Dependent_Inits() Set_Default_Global_Render_States(); // TheSuperHackers @refactor bobtista 10/04/2026 Construct the global - // IRenderBackend instance now that the D3D device is ready. + // IRenderBackend instance now that the D3D device is ready, then let it + // bring up any device of its own. Init_Render_Backend(); + g_renderBackend->Initialize(_Hwnd, ResolutionWidth, ResolutionHeight); } inline DWORD F2DW(float f) { return *((unsigned*)&f); } @@ -455,6 +457,7 @@ 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. + g_renderBackend->Shutdown(); Shutdown_Render_Backend(); /*