Rendering Context

引言

上一节我们将引擎转变为静态库并消除了所有警告和错误。今天我们将进入渲染模块。

首先我们的渲染器需要 Context。在 OpenGL 中真的非常简单,事实上 glfw 为我们处理了几乎所有这些(对于 Vulkan 则要复杂得多)。

Context 类设计

考虑到之后会使用不同的图形 API,我们在 Infinite/ 目录下新建 Renderer 文件夹,在其中新建 GraphicsContext.h 作为父类:

#pragma once

namespace Infinite {

class GraphicsContext
{
public:
virtual void Init() = 0;
virtual void SwapBuffers() = 0;

};

}

该父类包含了初始化 Init() 和交换缓存 SwapBuffers() 两个方法的声明。

接着我们在 Platform/OpenGL 目录下新建 OpenGLContext.hOpenGLContext.cpp 作为针对 OpenGL API 的 Context 类。

#pragma once

#include "Infinite/Renderer/GraphicsContext.h"

struct GLFWwindow;

namespace Infinite {

class OpenGLContext : public GraphicsContext
{
public:
OpenGLContext(GLFWwindow* windowHandle);


virtual void Init() override;
virtual void SwapBuffers() override;
private:
GLFWwindow* m_WindowHandle;
};
}

OpenGLContext.cpp 将我们之前 WindowsWindow.cpp 的方法封装于此:

#include "ifnpch.h"
#include "OpenGLContext.h"

#include <GLFW/glfw3.h>
#include <glad/glad.h>
#include <GL/GL.h>

namespace Infinite {


OpenGLContext::OpenGLContext(GLFWwindow* windowHandle)
: m_WindowHandle(windowHandle)
{
IFN_CORE_ASSERT(windowHandle, "Window handle is null!")
}

void OpenGLContext::Init()
{
glfwMakeContextCurrent(m_WindowHandle);
int status = gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);
IFN_CORE_ASSERT(status, "Failed to initialize Glad!");
}

void OpenGLContext::SwapBuffers()
{
glfwSwapBuffers(m_WindowHandle);
}

}

窗口调整

WindowsWindow.h 中新建我们的 Context:

#pragma once

#include "Window.h"

#include <GLFW/glfw3.h>

#include "Infinite/Renderer/GraphicsContext.h"


namespace Infinite {

class WindowsWindow : public Window
{
public:
WindowsWindow(const WindowProps& props);
virtual ~WindowsWindow();

void OnUpdate() override;

inline unsigned int GetWidth() const override { return m_Data.Width; }
inline unsigned int GetHeight() const override { return m_Data.Height; }

// Window attributes
inline void SetEventCallback(const EventCallbackFn& callback) override { m_Data.EventCallback = callback; }
void SetVSync(bool enabled) override;
bool IsVSync() const override;

inline virtual void* GetNativeWindow() const { return m_Window; }
private:
virtual void Init(const WindowProps& props);
virtual void Shutdown();
private:
GLFWwindow* m_Window;
+ GraphicsContext* m_Context;

struct WindowData
{
std::string Title;
unsigned int Width, Height;
bool VSync;

EventCallbackFn EventCallback;
};

WindowData m_Data;
};

}

之后 WindowsWindow.cpp 替换为我们 Context 类方法:

#include "Infinite/Events/MouseEvent.h"
#include "Infinite/Events/KeyEvent.h"

+#include "Platform/OpenGL/OpenGLContext.h"

#include <GLAD/glad.h>

namespace Infinite {
@@ -48,9 +50,10 @@ namespace Infinite {
}

m_Window = glfwCreateWindow((int)props.Width, (int)props.Height, m_Data.Title.c_str(), nullptr, nullptr);
- glfwMakeContextCurrent(m_Window);
- int status = gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);
- IFN_CORE_ASSERT(status, "Failed to initialize GLAD!");

+ m_Context = new OpenGLContext(m_Window);
+ m_Context->Init();

glfwSetWindowUserPointer(m_Window, &m_Data);
SetVSync(true);

@@ -155,7 +158,7 @@ namespace Infinite {
void WindowsWindow::OnUpdate()
{
glfwPollEvents();
- glfwSwapBuffers(m_Window);
+ m_Context->SwapBuffers();
}

void WindowsWindow::SetVSync(bool enabled)

调试