diff --git a/Core/Libraries/Source/WWVegas/WW3D2/Backend/DX8Backend.cpp b/Core/Libraries/Source/WWVegas/WW3D2/Backend/DX8Backend.cpp
new file mode 100644
index 00000000000..7cac76073bb
--- /dev/null
+++ b/Core/Libraries/Source/WWVegas/WW3D2/Backend/DX8Backend.cpp
@@ -0,0 +1,328 @@
+/*
+** Command & Conquer Generals Zero Hour(tm)
+** 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
+** 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 "RenderBackend.h"
+
+#include "WW3D2/dx8wrapper.h"
+#include "WWMath/vector3.h"
+#include "WWMath/matrix4.h"
+#include "WWMath/matrix3d.h"
+#include "WW3D2/light.h"
+#include "WW3D2/lightenvironment.h"
+
+DX8Backend::DX8Backend()
+{
+}
+
+DX8Backend::~DX8Backend()
+{
+}
+
+IRenderBackend *Create_Render_Backend()
+{
+ return new DX8Backend();
+}
+
+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();
+}
+
+void DX8Backend::Set_Gamma(float gamma, float bright, float contrast, bool calibrate, bool uselimit)
+{
+ DX8Wrapper::Set_Gamma(gamma, bright, contrast, calibrate, uselimit);
+}
+
+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);
+}
+
+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 int index_base_offset)
+{
+ DX8Wrapper::Set_Index_Buffer(ib, static_cast(index_base_offset));
+}
+
+void DX8Backend::Set_Index_Buffer(const DynamicIBAccessClass & iba, unsigned int index_base_offset)
+{
+ DX8Wrapper::Set_Index_Buffer(iba, static_cast(index_base_offset));
+}
+
+void DX8Backend::Set_Index_Buffer_Index_Offset(unsigned int offset)
+{
+ DX8Wrapper::Set_Index_Buffer_Index_Offset(offset);
+}
+
+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();
+}
+
+static D3DTRANSFORMSTATETYPE To_D3D_Transform(TransformKind transform)
+{
+ switch (transform)
+ {
+ case RB_TRANSFORM_VIEW:
+ return D3DTS_VIEW;
+ case RB_TRANSFORM_PROJECTION:
+ return D3DTS_PROJECTION;
+ case RB_TRANSFORM_WORLD:
+ default:
+ return D3DTS_WORLD;
+ }
+}
+
+void DX8Backend::Set_Transform(TransformKind transform, const Matrix4x4 & m)
+{
+ DX8Wrapper::Set_Transform(To_D3D_Transform(transform), m);
+}
+
+void DX8Backend::Set_Transform(TransformKind transform, const Matrix3D & m)
+{
+ DX8Wrapper::Set_Transform(To_D3D_Transform(transform), m);
+}
+
+void DX8Backend::Get_Transform(TransformKind transform, Matrix4x4 & m)
+{
+ DX8Wrapper::Get_Transform(To_D3D_Transform(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);
+}
+
+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();
+}
+
+void DX8Backend::Draw_Triangles(unsigned int start_index,
+ unsigned int polygon_count,
+ unsigned int min_vertex_index,
+ unsigned int vertex_count)
+{
+ DX8Wrapper::Draw_Triangles(static_cast(start_index),
+ static_cast(polygon_count),
+ static_cast(min_vertex_index),
+ static_cast(vertex_count));
+}
+
+void DX8Backend::Draw_Triangles(unsigned int buffer_type,
+ unsigned int start_index,
+ unsigned int polygon_count,
+ unsigned int min_vertex_index,
+ unsigned int vertex_count)
+{
+ DX8Wrapper::Draw_Triangles(buffer_type,
+ static_cast(start_index),
+ static_cast(polygon_count),
+ static_cast(min_vertex_index),
+ static_cast(vertex_count));
+}
+
+void DX8Backend::Draw_Strip(unsigned int start_index,
+ unsigned int index_count,
+ unsigned int min_vertex_index,
+ unsigned int vertex_count)
+{
+ DX8Wrapper::Draw_Strip(static_cast(start_index),
+ static_cast(index_count),
+ static_cast(min_vertex_index),
+ static_cast(vertex_count));
+}
+
+void DX8Backend::Set_Vertex_Shader(unsigned int vertex_shader)
+{
+ DX8Wrapper::Set_Vertex_Shader(static_cast(vertex_shader));
+}
+
+void DX8Backend::Set_Pixel_Shader(unsigned int 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);
+}
+
+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/Backend/DX8Backend.h b/Core/Libraries/Source/WWVegas/WW3D2/Backend/DX8Backend.h
new file mode 100644
index 00000000000..e6e4e955529
--- /dev/null
+++ b/Core/Libraries/Source/WWVegas/WW3D2/Backend/DX8Backend.h
@@ -0,0 +1,101 @@
+/*
+** Command & Conquer Generals Zero Hour(tm)
+** 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
+** 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. Pure adaptation, no new rendering logic.
+
+#pragma once
+
+#include "WW3D2/IRenderBackend.h"
+
+class DX8Backend : public IRenderBackend
+{
+public:
+ DX8Backend();
+ virtual ~DX8Backend() override;
+
+ virtual bool Is_Device_Lost() const override;
+ virtual bool Has_Stencil() override;
+ virtual WW3DFormat Get_Back_Buffer_Format() override;
+ virtual void Set_Gamma(float gamma, float bright, float contrast, bool calibrate, bool uselimit) override;
+
+ virtual void Begin_Scene() override;
+ virtual void End_Scene(bool flip_frame) override;
+ virtual void Flip_To_Primary() override;
+ virtual void Clear(bool clear_color, bool clear_z_stencil,
+ const Vector3 & color,
+ float dest_alpha, float z, unsigned int stencil) override;
+ virtual void Set_Viewport(const RenderBackendViewport & viewport) override;
+
+ virtual void Set_Vertex_Buffer(const VertexBufferClass * vb, unsigned int stream) override;
+ virtual void Set_Vertex_Buffer(const DynamicVBAccessClass & vba) override;
+ virtual void Set_Index_Buffer(const IndexBufferClass * ib, unsigned int index_base_offset) override;
+ virtual void Set_Index_Buffer(const DynamicIBAccessClass & iba, unsigned int index_base_offset) override;
+ virtual void Set_Index_Buffer_Index_Offset(unsigned int offset) override;
+
+ virtual void Set_Shader(const ShaderClass & shader) override;
+ virtual void Get_Shader(ShaderClass & shader) override;
+ virtual void Set_Material(const VertexMaterialClass * material) override;
+ virtual void Set_Texture(unsigned int stage, TextureBaseClass * texture) override;
+ virtual void Apply_Render_State_Changes() override;
+ virtual void Apply_Default_State() override;
+ virtual void Invalidate_Cached_Render_States() override;
+
+ virtual void Set_Transform(TransformKind transform, const Matrix4x4 & m) override;
+ virtual void Set_Transform(TransformKind transform, const Matrix3D & m) override;
+ virtual void Get_Transform(TransformKind transform, Matrix4x4 & m) override;
+ virtual void Set_World_Identity() override;
+ virtual void Set_View_Identity() override;
+ virtual bool Is_World_Identity() override;
+ virtual bool Is_View_Identity() override;
+ virtual void Set_Projection_Transform_With_Z_Bias(const Matrix4x4 & matrix, float znear, float zfar) override;
+
+ virtual void Set_Light(unsigned int index, const LightClass & light) override;
+ virtual void Set_Ambient(const Vector3 & color) override;
+ virtual const Vector3 & Get_Ambient() const override;
+ virtual void Set_Fog(bool enable, const Vector3 & color, float start, float end) override;
+ virtual bool Get_Fog_Enable() const override;
+ virtual void Set_Light_Environment(LightEnvironmentClass * light_env) override;
+ virtual LightEnvironmentClass * Get_Light_Environment() const override;
+
+ virtual void Draw_Triangles(unsigned int start_index,
+ unsigned int polygon_count,
+ unsigned int min_vertex_index,
+ unsigned int vertex_count) override;
+ virtual void Draw_Triangles(unsigned int buffer_type,
+ unsigned int start_index,
+ unsigned int polygon_count,
+ unsigned int min_vertex_index,
+ unsigned int vertex_count) override;
+ virtual void Draw_Strip(unsigned int start_index,
+ unsigned int index_count,
+ unsigned int min_vertex_index,
+ unsigned int vertex_count) override;
+
+ virtual void Set_Vertex_Shader(unsigned int vertex_shader) override;
+ virtual void Set_Pixel_Shader(unsigned int pixel_shader) override;
+ virtual void Set_Vertex_Shader_Constant(int reg, const void * data, int count) override;
+ virtual void Set_Pixel_Shader_Constant(int reg, const void * data, int count) override;
+
+ virtual TextureClass * Create_Render_Target(int width, int height, WW3DFormat format) override;
+ virtual void Set_Render_Target_With_Z(TextureClass * texture, ZTextureClass * ztexture) override;
+ virtual bool Is_Render_To_Texture() override;
+ virtual void Set_Shadow_Map(int idx, ZTextureClass * ztex) override;
+ virtual ZTextureClass * Get_Shadow_Map(int idx) override;
+};
diff --git a/Core/Libraries/Source/WWVegas/WW3D2/Backend/RenderBackend.cpp b/Core/Libraries/Source/WWVegas/WW3D2/Backend/RenderBackend.cpp
new file mode 100644
index 00000000000..1a908c1c196
--- /dev/null
+++ b/Core/Libraries/Source/WWVegas/WW3D2/Backend/RenderBackend.cpp
@@ -0,0 +1,51 @@
+/*
+** Command & Conquer Generals Zero Hour(tm)
+** 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
+** 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.
+
+#include "RenderBackend.h"
+
+#include "WWDebug/wwdebug.h"
+
+IRenderBackend * g_renderBackend = nullptr;
+
+void Init_Render_Backend()
+{
+ // Construction is single shot. WW3D::Init pairs with WW3D::Shutdown, which
+ // destroys the backend again, so arriving here with a live backend means the
+ // library lifecycle is unbalanced.
+ WWASSERT(g_renderBackend == nullptr);
+ if (g_renderBackend != nullptr)
+ {
+ return;
+ }
+
+ g_renderBackend = Create_Render_Backend();
+}
+
+void Shutdown_Render_Backend()
+{
+ if (g_renderBackend == nullptr)
+ {
+ return;
+ }
+ delete g_renderBackend;
+ g_renderBackend = nullptr;
+}
diff --git a/Core/Libraries/Source/WWVegas/WW3D2/Backend/RenderBackend.h b/Core/Libraries/Source/WWVegas/WW3D2/Backend/RenderBackend.h
new file mode 100644
index 00000000000..5dceab05cc7
--- /dev/null
+++ b/Core/Libraries/Source/WWVegas/WW3D2/Backend/RenderBackend.h
@@ -0,0 +1,41 @@
+/*
+** Command & Conquer Generals Zero Hour(tm)
+** 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
+** 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 backend.
+
+#pragma once
+
+#include "WW3D2/IRenderBackend.h"
+
+// 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;
+
+// Construct the backend selected by the build. Exactly one backend
+// implementation must define this function.
+IRenderBackend *Create_Render_Backend();
+
+// Create the render backend. Called once from WW3D::Init, before any render
+// device exists, and exactly once per Shutdown_Render_Backend().
+void Init_Render_Backend();
+
+// Destroy the render backend. Called from WW3D::Shutdown, after the render
+// device has been released.
+void Shutdown_Render_Backend();
diff --git a/Core/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt b/Core/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt
index 4e10ae78d31..decac0ea6f3 100644
--- a/Core/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt
+++ b/Core/Libraries/Source/WWVegas/WW3D2/CMakeLists.txt
@@ -13,6 +13,10 @@ set(WW3D2_SRC
#assetmgr.h
assetstatus.cpp
assetstatus.h
+ Backend/DX8Backend.cpp
+ Backend/DX8Backend.h
+ Backend/RenderBackend.cpp
+ Backend/RenderBackend.h
bitmaphandler.cpp
bitmaphandler.h
bmp2d.cpp
@@ -90,6 +94,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..fe87944800e
--- /dev/null
+++ b/Core/Libraries/Source/WWVegas/WW3D2/IRenderBackend.h
@@ -0,0 +1,160 @@
+/*
+** Command & Conquer Generals Zero Hour(tm)
+** 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
+** 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 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 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;
+class TextureBaseClass;
+class TextureClass;
+class ZTextureClass;
+class VertexBufferClass;
+class IndexBufferClass;
+class DynamicVBAccessClass;
+class DynamicIBAccessClass;
+class LightClass;
+class LightEnvironmentClass;
+class Matrix4x4;
+class Matrix3D;
+class Vector3;
+
+enum TransformKind
+{
+ RB_TRANSFORM_WORLD,
+ RB_TRANSFORM_VIEW,
+ RB_TRANSFORM_PROJECTION
+};
+
+struct RenderBackendViewport
+{
+ unsigned int x;
+ unsigned int y;
+ unsigned int width;
+ unsigned int height;
+ float min_z;
+ float max_z;
+};
+
+// 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 migrating a
+// caller is a mechanical DX8Wrapper::X(...) -> g_renderBackend->X(...) rewrite.
+
+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;
+ virtual void Set_Gamma(float gamma, float bright, float contrast, bool calibrate, bool uselimit) = 0;
+
+ 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;
+
+ 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 int index_base_offset) = 0;
+ virtual void Set_Index_Buffer(const DynamicIBAccessClass & iba, unsigned int index_base_offset) = 0;
+ virtual void Set_Index_Buffer_Index_Offset(unsigned int offset) = 0;
+
+ 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;
+
+ 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;
+
+ 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;
+
+ // Ranges are unsigned int rather than the DX8 era unsigned short so the
+ // interface does not pin every future backend to 16-bit draw counts. The DX8
+ // reference backend narrows on the way through to DX8Wrapper.
+
+ virtual void Draw_Triangles(unsigned int start_index,
+ unsigned int polygon_count,
+ unsigned int min_vertex_index,
+ unsigned int vertex_count) = 0;
+
+ virtual void Draw_Triangles(unsigned int buffer_type,
+ unsigned int start_index,
+ unsigned int polygon_count,
+ unsigned int min_vertex_index,
+ unsigned int vertex_count) = 0;
+
+ virtual void Draw_Strip(unsigned int start_index,
+ unsigned int index_count,
+ unsigned int min_vertex_index,
+ unsigned int vertex_count) = 0;
+
+ // Legacy fixed function vertex format code or shader handle. Always 32 bits
+ // wide; unsigned long would be 64 bits on targets where long is 64-bit.
+ virtual void Set_Vertex_Shader(unsigned int vertex_shader) = 0;
+ virtual void Set_Pixel_Shader(unsigned int 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;
+
+ 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;
+};
diff --git a/Core/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp b/Core/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp
index ba897a753a5..869a001cd40 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 "Backend/RenderBackend.h"
#include "ww3d.h"
#include "camera.h"
#include "WWLib/wwstring.h"
@@ -390,6 +391,11 @@ void DX8Wrapper::Do_Onetime_Device_Dependent_Inits()
TextureLoader::Init();
Set_Default_Global_Render_States();
+
+ // TheSuperHackers @refactor bobtista 10/04/2026 The backend object is created
+ // in WW3D::Init and outlives every device cycle. Only its device dependent
+ // state is brought up here, now that the D3D device is ready.
+ g_renderBackend->Initialize(_Hwnd, ResolutionWidth, ResolutionHeight);
}
inline DWORD F2DW(float f) { return *((unsigned*)&f); }
@@ -450,6 +456,14 @@ void DX8Wrapper::Invalidate_Cached_Render_States()
void DX8Wrapper::Do_Onetime_Device_Dependent_Shutdowns()
{
+ // TheSuperHackers @refactor bobtista 10/04/2026 Release the backend's device
+ // dependent state before the D3D device goes away. The backend object itself
+ // is destroyed later, in WW3D::Shutdown.
+ if (g_renderBackend != nullptr)
+ {
+ g_renderBackend->Shutdown();
+ }
+
/*
** Shutdown ww3d systems
*/
diff --git a/Core/Libraries/Source/WWVegas/WW3D2/ww3d.cpp b/Core/Libraries/Source/WWVegas/WW3D2/ww3d.cpp
index 226c8a63c98..7547c17f889 100644
--- a/Core/Libraries/Source/WWVegas/WW3D2/ww3d.cpp
+++ b/Core/Libraries/Source/WWVegas/WW3D2/ww3d.cpp
@@ -104,6 +104,7 @@
#include "dazzle.h"
#include "meshmdl.h"
#include "dx8renderer.h"
+#include "Backend/RenderBackend.h"
#include "render2d.h"
#include "WWLib/bound.h"
#include "rddesc.h"
@@ -278,6 +279,12 @@ WW3DErrorType WW3D::Init(void *hwnd, char *defaultpal, bool lite)
if (!DX8Wrapper::Init(_Hwnd, lite)) {
return(WW3D_ERROR_INITIALIZATION_FAILED);
}
+
+ // TheSuperHackers @refactor bobtista 07/08/2026 The backend object is created
+ // once here and destroyed in WW3D::Shutdown, so it survives the device
+ // release and create cycles that drive its Initialize and Shutdown calls.
+ Init_Render_Backend();
+
WWDEBUG_SAY(("Allocate Debug Resources"));
Allocate_Debug_Resources();
@@ -368,6 +375,8 @@ WW3DErrorType WW3D::Shutdown()
DX8Wrapper::Shutdown();
}
+ Shutdown_Render_Backend();
+
/*
** Clear the default static sort lists
*/