Phase 1
Description
Introduce backend-agnostic interfaces so the engine routes all GPU calls through an abstraction instead of calling OpenGL directly. No Vulkan code is written in this phase — the goal is to decouple the engine from OpenGL so that a second backend can be plugged in later without touching core engine logic.
Currently, raw gl* calls are spread across VertexGL/, Mesh/, Textures/, Shaders/, GT/, Imgui_Setup/, and SceneManager/. After this phase, all of those go through a set of interfaces, and the existing OpenGL code lives behind an OpenGL implementation of those interfaces.
Motivation
Renders/display_graphics.hpp already defines a Backend enum with OpenGL, Vulkan, and Metal — but nothing dispatches on it. This phase makes that enum meaningful.
Tasks
1. RenderDevice interface (RenderBackend/render_device.hpp)
- Abstract: init/shutdown, create buffers, create textures, create pipelines, begin/end frame
- Factory method that returns the correct implementation based on
DisplayGraphics::GetBackend()
2. GPUBuffer interface (RenderBackend/gpu_buffer.hpp)
- Replaces
VertexArrayObject, VertexBuffer, VertexIndex from VertexGL/ - Operations:
create(type, size, data), bind(), unbind(), updateData() - Buffer types:
Vertex, Index, Uniform
3. GPUTexture interface (RenderBackend/gpu_texture.hpp)
- Replaces the GL internals of
Textures/textures.hpp - Operations:
create(width, height, format, data), bind(slot), destroy() - Supports 2D and CubeMap targets
4. Pipeline interface (RenderBackend/pipeline.hpp)
- Replaces
Shaders/shader.hpp concept (Vulkan binds entire pipelines, not individual shaders) - Operations:
create(vertexSrc, fragmentSrc), bind(), setUniform*() - Encapsulates vertex input layout, blend state, depth state
5. RenderPass abstraction (RenderBackend/render_pass.hpp)
- Wraps the concept of "clear → draw → present" that OpenGL does implicitly
- Operations:
begin(clearColor), end(), submit() - In the OpenGL implementation this simply maps to
glClear / glfwSwapBuffers
6. OpenGL backend implementation (RenderBackend/opengl/)
GLDevice, GLBuffer, GLTexture, GLPipeline, GLRenderPass- Move existing GL code from
VertexGL/, Shaders/, Textures/ into these classes - The old classes in
VertexGL/ become thin wrappers or are replaced entirely
7. Refactor GraphicsTool::initGL() → initBackend()
- Dispatch to
RenderDevice::create() based on DisplayGraphics::GetBackend() - Remove hardcoded
glfwWindowHint(OPENGL_PROFILE, ...) and glewInit() from the generic path - GLFW window hints become backend-specific (OpenGL needs
OPENGL_PROFILE; Vulkan needs GLFW_CLIENT_API, GLFW_NO_API)
8. Refactor Mesh to use GPUBuffer
- Replace
VertexArrayObject m_vao, VertexBuffer m_vb, VertexIndex m_vi with interface pointers - Remove raw
glEnableVertexAttribArray / glVertexAttribPointer calls from mesh.cpp — vertex layout goes into Pipeline Mesh::draw() calls pipeline->bind() + renderDevice->drawIndexed() instead of glDrawElements
9. Refactor SceneManager::renderScene()
- Replace
shader.Bind() + shader.setUniformMat4fv() calls with pipeline->bind() + pipeline->setUniform*() - Wrap the render loop body in
renderPass->begin() / renderPass->end()
10. Refactor Imgui_Setup for backend awareness
- Guard
ImGui_ImplOpenGL3_* calls behind if (GetBackend() == OpenGL) - Prepare the structure so a future Vulkan ImGui backend can be added in the same file
Suggested file structure after this phase
RenderBackend/
├── render_device.hpp
├── gpu_buffer.hpp
├── gpu_texture.hpp
├── pipeline.hpp
├── render_pass.hpp
└── opengl/
├── gl_device.cpp / .hpp
├── gl_buffer.cpp / .hpp
├── gl_texture.cpp / .hpp
├── gl_pipeline.cpp / .hpp
└── gl_render_pass.cpp / .hpp
Affected files
Current file | Change
-- | --
VertexGL/vertexArrayObjects.hpp/.cpp | Internals move to GLBuffer; may become a thin wrapper or be removed
VertexGL/vertexBuffers.hpp/.cpp | Same
VertexGL/vertexIndices.hpp/.cpp | Same
Shaders/shader.hpp/.cpp | Internals move to GLPipeline
Textures/textures.hpp/.cpp | GL internals move to GLTexture
GT/graphicsTool.hpp/.cpp | initGL() → initBackend(), render loop uses RenderPass
Mesh/mesh.hpp/.cpp | Uses GPUBuffer + Pipeline instead of raw GL
SceneManager/scene_manager.cpp | Uses Pipeline interface for uniforms
Imgui_Setup/imgui_setup.cpp | Backend-guarded init/render/shutdown
Renders/display_graphics.hpp | Add factory for RenderDevice
CMakeLists.txt | Add RenderBackend/ sources
Acceptance criteria
- Engine compiles and runs identically to current behavior using the OpenGL backend
- No raw
gl* calls exist outside of RenderBackend/opengl/ DisplayGraphics::GetBackend() is checked at initialization to select the backend- Adding a new backend only requires implementing the interfaces — zero changes to
Mesh, Model, SceneManager, or application code
Notes
- This phase intentionally does not add any Vulkan code — it only prepares the engine for it
- The CRTP pattern in
GraphicsTool can coexist with runtime dispatch for backends; CRTP handles application-level polymorphism (FunGT derives from GraphicsTool<FunGT>), while the backend uses virtual interfaces - SYCL/OpenCL compute kernels in
Physics/GPU/ are out of scope for this phase
Phase 1
Description
Introduce backend-agnostic interfaces so the engine routes all GPU calls through an abstraction instead of calling OpenGL directly. No Vulkan code is written in this phase — the goal is to decouple the engine from OpenGL so that a second backend can be plugged in later without touching core engine logic.
Currently, raw
gl*calls are spread acrossVertexGL/,Mesh/,Textures/,Shaders/,GT/,Imgui_Setup/, andSceneManager/. After this phase, all of those go through a set of interfaces, and the existing OpenGL code lives behind anOpenGLimplementation of those interfaces.Motivation
Renders/display_graphics.hppalready defines aBackendenum withOpenGL,Vulkan, andMetal— but nothing dispatches on it. This phase makes that enum meaningful.Tasks
1.
RenderDeviceinterface (RenderBackend/render_device.hpp)DisplayGraphics::GetBackend()2.
GPUBufferinterface (RenderBackend/gpu_buffer.hpp)VertexArrayObject,VertexBuffer,VertexIndexfromVertexGL/create(type, size, data),bind(),unbind(),updateData()Vertex,Index,Uniform3.
GPUTextureinterface (RenderBackend/gpu_texture.hpp)Textures/textures.hppcreate(width, height, format, data),bind(slot),destroy()4.
Pipelineinterface (RenderBackend/pipeline.hpp)Shaders/shader.hppconcept (Vulkan binds entire pipelines, not individual shaders)create(vertexSrc, fragmentSrc),bind(),setUniform*()5.
RenderPassabstraction (RenderBackend/render_pass.hpp)begin(clearColor),end(),submit()glClear/glfwSwapBuffers6. OpenGL backend implementation (
RenderBackend/opengl/)GLDevice,GLBuffer,GLTexture,GLPipeline,GLRenderPassVertexGL/,Shaders/,Textures/into these classesVertexGL/become thin wrappers or are replaced entirely7. Refactor
GraphicsTool::initGL()→initBackend()RenderDevice::create()based onDisplayGraphics::GetBackend()glfwWindowHint(OPENGL_PROFILE, ...)andglewInit()from the generic pathOPENGL_PROFILE; Vulkan needsGLFW_CLIENT_API, GLFW_NO_API)8. Refactor
Meshto useGPUBufferVertexArrayObject m_vao,VertexBuffer m_vb,VertexIndex m_viwith interface pointersglEnableVertexAttribArray/glVertexAttribPointercalls frommesh.cpp— vertex layout goes intoPipelineMesh::draw()callspipeline->bind()+renderDevice->drawIndexed()instead ofglDrawElements9. Refactor
SceneManager::renderScene()shader.Bind()+shader.setUniformMat4fv()calls withpipeline->bind()+pipeline->setUniform*()renderPass->begin()/renderPass->end()10. Refactor
Imgui_Setupfor backend awarenessImGui_ImplOpenGL3_*calls behindif (GetBackend() == OpenGL)Suggested file structure after this phase
Affected files
Current file | Change -- | -- VertexGL/vertexArrayObjects.hpp/.cpp | Internals move to GLBuffer; may become a thin wrapper or be removed VertexGL/vertexBuffers.hpp/.cpp | Same VertexGL/vertexIndices.hpp/.cpp | Same Shaders/shader.hpp/.cpp | Internals move to GLPipeline Textures/textures.hpp/.cpp | GL internals move to GLTexture GT/graphicsTool.hpp/.cpp | initGL() → initBackend(), render loop uses RenderPass Mesh/mesh.hpp/.cpp | Uses GPUBuffer + Pipeline instead of raw GL SceneManager/scene_manager.cpp | Uses Pipeline interface for uniforms Imgui_Setup/imgui_setup.cpp | Backend-guarded init/render/shutdown Renders/display_graphics.hpp | Add factory for RenderDevice CMakeLists.txt | Add RenderBackend/ sourcesAcceptance criteria
gl*calls exist outside ofRenderBackend/opengl/DisplayGraphics::GetBackend()is checked at initialization to select the backendMesh,Model,SceneManager, or application codeNotes
GraphicsToolcan coexist with runtime dispatch for backends; CRTP handles application-level polymorphism (FunGTderives fromGraphicsTool<FunGT>), while the backend uses virtual interfacesPhysics/GPU/are out of scope for this phase