Move OpenGL backend classes from tests/OpenGL to engine/

- Relocated OpenGLDevice, OpenGLShader, OpenGLBuffer, OpenGLVertexArray, OpenGLTexture to engine/
- Updated engine/CMakeLists.txt to include OpenGL backend source files
- Updated tests/OpenGL/CMakeLists.txt to use engine backend
- Added OpenGLTexture class implementation
This commit is contained in:
2026-03-16 17:22:45 +08:00
parent 434ba0f336
commit fee738b0b9
13 changed files with 354 additions and 36 deletions

View File

@@ -0,0 +1,61 @@
#define GLFW_INCLUDE_NONE
#include "XCEngine/RHI/OpenGL/OpenGLBuffer.h"
#include <glad/glad.h>
#include <GLFW/glfw3.h>
namespace XCEngine {
namespace RHI {
OpenGLBuffer::OpenGLBuffer()
: m_buffer(0)
, m_size(0)
, m_isIndexBuffer(false) {
}
OpenGLBuffer::~OpenGLBuffer() {
Shutdown();
}
bool OpenGLBuffer::InitializeVertexBuffer(const void* data, size_t size) {
glGenBuffers(1, &m_buffer);
glBindBuffer(GL_ARRAY_BUFFER, m_buffer);
glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
m_size = size;
m_isIndexBuffer = false;
return true;
}
bool OpenGLBuffer::InitializeIndexBuffer(const void* data, size_t size) {
glGenBuffers(1, &m_buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
m_size = size;
m_isIndexBuffer = true;
return true;
}
void OpenGLBuffer::Shutdown() {
if (m_buffer) {
glDeleteBuffers(1, &m_buffer);
m_buffer = 0;
}
}
void OpenGLBuffer::Bind() const {
if (m_isIndexBuffer) {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buffer);
} else {
glBindBuffer(GL_ARRAY_BUFFER, m_buffer);
}
}
void OpenGLBuffer::Unbind() const {
if (m_isIndexBuffer) {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
} else {
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
}
} // namespace RHI
} // namespace XCEngine

View File

@@ -0,0 +1,95 @@
#define GLFW_INCLUDE_NONE
#include "XCEngine/RHI/OpenGL/OpenGLDevice.h"
#include <glad/glad.h>
#include <GLFW/glfw3.h>
namespace XCEngine {
namespace RHI {
OpenGLDevice::OpenGLDevice()
: m_window(nullptr)
, m_initialized(false)
, m_ownsWindow(false) {
}
OpenGLDevice::~OpenGLDevice() {
Shutdown();
}
bool OpenGLDevice::CreateRenderWindow(int width, int height, const char* title, bool enableDebug) {
if (m_initialized) {
return true;
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
m_window = glfwCreateWindow(width, height, title, nullptr, nullptr);
if (!m_window) {
return false;
}
m_ownsWindow = true;
return InitializeWithExistingWindow(m_window);
}
bool OpenGLDevice::InitializeWithExistingWindow(GLFWwindow* window) {
if (m_initialized) {
return true;
}
m_window = window;
if (!m_window) {
return false;
}
glfwMakeContextCurrent(m_window);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
return false;
}
m_deviceInfo.vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
m_deviceInfo.renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
m_deviceInfo.version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
glGetIntegerv(GL_MAJOR_VERSION, &m_deviceInfo.majorVersion);
glGetIntegerv(GL_MINOR_VERSION, &m_deviceInfo.minorVersion);
m_initialized = true;
return true;
}
void OpenGLDevice::Shutdown() {
if (m_ownsWindow && m_window) {
glfwDestroyWindow(m_window);
}
m_window = nullptr;
m_initialized = false;
m_ownsWindow = false;
}
void OpenGLDevice::SwapBuffers() {
if (m_window) {
glfwSwapBuffers(m_window);
}
}
bool OpenGLDevice::PollEvents() {
glfwPollEvents();
return !glfwWindowShouldClose(m_window);
}
void OpenGLDevice::SetShouldClose(bool shouldClose) {
if (m_window) {
glfwSetWindowShouldClose(m_window, shouldClose ? GLFW_TRUE : GLFW_FALSE);
}
}
bool OpenGLDevice::ShouldClose() const {
return m_window && glfwWindowShouldClose(m_window) == GLFW_TRUE;
}
} // namespace RHI
} // namespace XCEngine

View File

@@ -0,0 +1,130 @@
#define GLFW_INCLUDE_NONE
#include "XCEngine/RHI/OpenGL/OpenGLShader.h"
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <fstream>
#include <sstream>
#include <iostream>
namespace XCEngine {
namespace RHI {
OpenGLShader::OpenGLShader()
: m_program(0) {
}
OpenGLShader::~OpenGLShader() {
Shutdown();
}
bool OpenGLShader::CompileFromFile(const char* vertexPath, const char* fragmentPath) {
std::string vertexCode, fragmentCode;
std::ifstream vShaderFile(vertexPath), fShaderFile(fragmentPath);
if (!vShaderFile.is_open() || !fShaderFile.is_open()) {
return false;
}
std::stringstream vShaderStream, fShaderStream;
vShaderStream << vShaderFile.rdbuf();
fShaderStream << fShaderFile.rdbuf();
vShaderFile.close();
fShaderFile.close();
vertexCode = vShaderStream.str();
fragmentCode = fShaderStream.str();
return Compile(vertexCode.c_str(), fragmentCode.c_str());
}
bool OpenGLShader::Compile(const char* vertexSource, const char* fragmentSource) {
unsigned int vertex, fragment;
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vertexSource, NULL);
glCompileShader(vertex);
if (!CheckCompileErrors(vertex, "VERTEX")) {
return false;
}
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fragmentSource, NULL);
glCompileShader(fragment);
if (!CheckCompileErrors(fragment, "FRAGMENT")) {
return false;
}
m_program = glCreateProgram();
glAttachShader(m_program, vertex);
glAttachShader(m_program, fragment);
glLinkProgram(m_program);
if (!CheckLinkErrors(m_program)) {
return false;
}
glDeleteShader(vertex);
glDeleteShader(fragment);
return true;
}
void OpenGLShader::Shutdown() {
if (m_program) {
glDeleteProgram(m_program);
m_program = 0;
}
}
void OpenGLShader::Use() const {
glUseProgram(m_program);
}
void OpenGLShader::SetInt(const std::string& name, int value) const {
glUniform1i(glGetUniformLocation(m_program, name.c_str()), value);
}
void OpenGLShader::SetFloat(const std::string& name, float value) const {
glUniform1f(glGetUniformLocation(m_program, name.c_str()), value);
}
void OpenGLShader::SetVec3(const std::string& name, float x, float y, float z) const {
glUniform3f(glGetUniformLocation(m_program, name.c_str()), x, y, z);
}
void OpenGLShader::SetVec3(const std::string& name, const float* values) const {
glUniform3fv(glGetUniformLocation(m_program, name.c_str()), 1, values);
}
void OpenGLShader::SetMat4(const std::string& name, const float* value) const {
glUniformMatrix4fv(glGetUniformLocation(m_program, name.c_str()), 1, GL_FALSE, value);
}
bool OpenGLShader::CheckCompileErrors(unsigned int shader, const char* type) {
int success;
char infoLog[1024];
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(shader, 1024, NULL, infoLog);
std::cout << "ERROR::SHADER_COMPILATION_ERROR: " << type << "\n" << infoLog << std::endl;
return false;
}
return true;
}
bool OpenGLShader::CheckLinkErrors(unsigned int program) {
int success;
char infoLog[1024];
glGetProgramiv(program, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(program, 1024, NULL, infoLog);
std::cout << "ERROR::PROGRAM_LINKING_ERROR\n" << infoLog << std::endl;
return false;
}
return true;
}
} // namespace RHI
} // namespace XCEngine

View File

@@ -0,0 +1,79 @@
#define GLFW_INCLUDE_NONE
#include "XCEngine/RHI/OpenGL/OpenGLTexture.h"
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <stb_image.h>
#include <iostream>
namespace XCEngine {
namespace RHI {
OpenGLTexture::OpenGLTexture()
: m_texture(0)
, m_width(0)
, m_height(0)
, m_channels(0) {
}
OpenGLTexture::~OpenGLTexture() {
Shutdown();
}
bool OpenGLTexture::Initialize2D(int width, int height, int channels, const void* data, bool generateMipmap) {
glGenTextures(1, &m_texture);
glBindTexture(GL_TEXTURE_2D, m_texture);
GLenum format = (channels == 4) ? GL_RGBA : GL_RGB;
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
if (generateMipmap) {
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
} else {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
m_width = width;
m_height = height;
m_channels = channels;
glBindTexture(GL_TEXTURE_2D, 0);
return true;
}
bool OpenGLTexture::LoadFromFile(const char* path, bool flipVertical) {
stbi_set_flip_vertically_on_load(flipVertical ? 1 : 0);
unsigned char* data = stbi_load(path, &m_width, &m_height, &m_channels, 0);
if (!data) {
std::cout << "Failed to load texture: " << path << std::endl;
return false;
}
bool result = Initialize2D(m_width, m_height, m_channels, data, true);
stbi_image_free(data);
return result;
}
void OpenGLTexture::Shutdown() {
if (m_texture) {
glDeleteTextures(1, &m_texture);
m_texture = 0;
}
}
void OpenGLTexture::Bind(int slot) const {
glActiveTexture(GL_TEXTURE0 + slot);
glBindTexture(GL_TEXTURE_2D, m_texture);
}
void OpenGLTexture::Unbind() const {
glBindTexture(GL_TEXTURE_2D, 0);
}
} // namespace RHI
} // namespace XCEngine

View File

@@ -0,0 +1,60 @@
#define GLFW_INCLUDE_NONE
#include "XCEngine/RHI/OpenGL/OpenGLVertexArray.h"
#include <glad/glad.h>
#include <GLFW/glfw3.h>
namespace XCEngine {
namespace RHI {
OpenGLVertexArray::OpenGLVertexArray()
: m_vao(0)
, m_indexBuffer(0)
, m_indexCount(0)
, m_vertexBufferCount(0) {
}
OpenGLVertexArray::~OpenGLVertexArray() {
Shutdown();
}
bool OpenGLVertexArray::Initialize() {
glGenVertexArrays(1, &m_vao);
return true;
}
void OpenGLVertexArray::AddVertexBuffer(unsigned int buffer, const VertexAttribute& attribute) {
glBindVertexArray(m_vao);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glEnableVertexAttribArray(attribute.index);
glVertexAttribPointer(attribute.index, attribute.count, attribute.type,
attribute.normalized ? GL_TRUE : GL_FALSE,
attribute.stride, (void*)attribute.offset);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
m_vertexBufferCount++;
}
void OpenGLVertexArray::SetIndexBuffer(unsigned int buffer, unsigned int type) {
glBindVertexArray(m_vao);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
glBindVertexArray(0);
m_indexBuffer = buffer;
}
void OpenGLVertexArray::Shutdown() {
if (m_vao) {
glDeleteVertexArrays(1, &m_vao);
m_vao = 0;
}
}
void OpenGLVertexArray::Bind() const {
glBindVertexArray(m_vao);
}
void OpenGLVertexArray::Unbind() const {
glBindVertexArray(0);
}
} // namespace RHI
} // namespace XCEngine