ADD: OpenGLWrapper

This commit is contained in:
sebastian 2026-07-29 12:18:47 +02:00
parent 7c7ac67fc8
commit 4ada346252
13 changed files with 381 additions and 23 deletions

View File

@ -80,6 +80,13 @@ target_include_directories(glad PUBLIC third_party/glad/include)
add_library(Engine STATIC add_library(Engine STATIC
engine/src/core/Window.h engine/src/core/Window.h
engine/src/core/Window.cpp engine/src/core/Window.cpp
engine/src/core/Application.cpp
engine/src/core/Application.h
engine/src/core/EngineConfig.h
engine/src/utils/openglWrapper/GLStateCache.cpp
engine/src/utils/openglWrapper/GLStateCache.h
engine/src/utils/openglWrapper/GLRenderState.cpp
engine/src/utils/openglWrapper/GLRenderState.h
) )
target_include_directories(Engine PUBLIC engine/src) target_include_directories(Engine PUBLIC engine/src)
target_link_libraries(Engine PUBLIC OpenGL::GL glfw glad glm::glm imgui) target_link_libraries(Engine PUBLIC OpenGL::GL glfw glad glm::glm imgui)
@ -87,6 +94,8 @@ target_link_libraries(Engine PUBLIC OpenGL::GL glfw glad glm::glm imgui)
# --- Executable --- # --- Executable ---
add_executable(ColorRace add_executable(ColorRace
game/src/main.cpp game/src/main.cpp
game/src/ColorRaceApp.cpp
game/src/ColorRaceApp.h
) )
target_link_libraries(ColorRace PRIVATE target_link_libraries(ColorRace PRIVATE

View File

@ -0,0 +1,37 @@
//
// Created by sebastian on 29.07.26.
//
#include "Application.h"
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include "utils/openglWrapper/GLStateCache.h"
namespace engine {
Application::Application(const EngineConfig& config) : m_config(config) {
m_window = std::make_unique<Window>(config);
}
Application::~Application() = default;
void Application::run() {
auto lastTime = static_cast<float>(glfwGetTime());
while (!m_window->shouldClose()) {
const auto currentTime = static_cast<float>(glfwGetTime());
const float deltaTime = currentTime - lastTime;
lastTime = currentTime;
m_window->pollEvents();
onUpdate(deltaTime);
GLStateCache::clearFrameBuffer(m_config.clearColor);
onRender();
m_window->swapBuffers();
}
}
}

View File

@ -0,0 +1,37 @@
//
// Created by sebastian on 29.07.26.
//
#ifndef COLORRACE_APPLICATION_H
#define COLORRACE_APPLICATION_H
#include <memory>
#include <string>
#include "EngineConfig.h"
#include "Window.h"
namespace engine {
class Application {
public:
Application(const EngineConfig& config);
virtual ~Application();
void run();
protected:
virtual void onUpdate(float deltaTime) {}
virtual void onRender() {}
private:
EngineConfig m_config;
std::unique_ptr<Window> m_window;
};
}
#endif //COLORRACE_APPLICATION_H

View File

@ -0,0 +1,28 @@
//
// Created by sebastian on 29.07.26.
//
#ifndef COLORRACE_ENGINECONFIG_H
#define COLORRACE_ENGINECONFIG_H
#include <string>
#include "glm/vec4.hpp"
namespace engine {
struct EngineConfig {
int windowWidth = 1280;
int windowHeight = 720;
std::string windowTitle = "Engine";
bool fullscreen = false;
bool vsync = true;
bool msaa = true;
int msaaSamples = 4;
glm::vec4 clearColor = {0.1f, 0.1f, 0.15f, 1.0f};
bool debugContext = true; // GL_DEBUG_OUTPUT an/aus
};
}
#endif //COLORRACE_ENGINECONFIG_H

View File

@ -6,8 +6,10 @@
#include <iostream> #include <iostream>
#include "EngineConfig.h"
#include "glad/glad.h" #include "glad/glad.h"
#include "GLFW/glfw3.h" #include "GLFW/glfw3.h"
#include "utils/openglWrapper/GLStateCache.h"
namespace engine { namespace engine {
static void GLAPIENTRY DebugCallback(GLenum source, GLenum type, GLuint id, static void GLAPIENTRY DebugCallback(GLenum source, GLenum type, GLuint id,
@ -17,31 +19,47 @@ namespace engine {
std::cerr << "[GL DEBUG] " << message << "\n"; std::cerr << "[GL DEBUG] " << message << "\n";
} }
Window::Window(int width, int height, const std::string& title) { Window::Window(const EngineConfig& config) {
if (!glfwInit()) throw std::runtime_error("GLFW init failed"); if (!glfwInit()) throw std::runtime_error("GLFW init failed");
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE); glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, config.debugContext ? GLFW_TRUE : GLFW_FALSE);
m_handle = glfwCreateWindow(width, height, title.c_str(), nullptr, nullptr); if (config.msaa) {
glfwWindowHint(GLFW_SAMPLES, config.msaaSamples);
}
GLFWmonitor* monitor = config.fullscreen ? glfwGetPrimaryMonitor() : nullptr;
m_handle = glfwCreateWindow(config.windowWidth, config.windowHeight, config.windowTitle.c_str(), monitor, nullptr);
if (!m_handle) { if (!m_handle) {
glfwTerminate(); glfwTerminate();
throw std::runtime_error("Window creation failed"); throw std::runtime_error("Window creation failed");
} }
glfwMakeContextCurrent(m_handle); glfwMakeContextCurrent(m_handle);
glfwSwapInterval(config.vsync ? 1 : 0); // VSync
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
throw std::runtime_error("GLAD init failed"); throw std::runtime_error("GLAD init failed");
} }
glEnable(GL_DEBUG_OUTPUT); GLStateCache::init();
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
glDebugMessageCallback(DebugCallback, nullptr);
glViewport(0, 0, width, height); if (config.debugContext) {
glEnable(GL_DEBUG_OUTPUT);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
glDebugMessageCallback(DebugCallback, nullptr);
}
if (config.msaa) {
glEnable(GL_MULTISAMPLE);
}
glViewport(0, 0, config.windowWidth, config.windowHeight);
} }
Window::~Window() { Window::~Window() {

View File

@ -8,12 +8,14 @@
#pragma once #pragma once
#include <string> #include <string>
#include "EngineConfig.h"
struct GLFWwindow; struct GLFWwindow;
namespace engine { namespace engine {
class Window { class Window {
public: public:
Window(int width, int height, const std::string& title); Window(const EngineConfig& config);
~Window(); ~Window();
bool shouldClose() const; bool shouldClose() const;

View File

@ -0,0 +1,17 @@
//
// Created by sebastian on 29.07.26.
//
#include "GLRenderState.h"
#include "GLStateCache.h"
namespace engine {
void GLRenderState::apply() const {
GLStateCache::setFaceCulling(backfaceCulling || frontFaceCulling, frontFaceCulling);
GLStateCache::setAntialiasing(antialiasing);
GLStateCache::setAlphaBlending(alphaBlending);
GLStateCache::setDepthTest(depthTesting);
GLStateCache::setDepthWriting(depthWriting);
}
}

View File

@ -0,0 +1,22 @@
//
// Created by sebastian on 29.07.26.
//
#ifndef COLORRACE_GLRENDERSTATE_H
#define COLORRACE_GLRENDERSTATE_H
namespace engine {
struct GLRenderState {
bool backfaceCulling = false;
bool frontFaceCulling = false;
bool alphaBlending = false;
bool antialiasing = false;
bool depthTesting = true; // in 3D meist sinnvoller Default
bool depthWriting = true;
void apply() const;
};
}
#endif //COLORRACE_GLRENDERSTATE_H

View File

@ -0,0 +1,115 @@
//
// Created by sebastian on 29.07.26.
//
#include "GLStateCache.h"
#include <GL/gl.h>
namespace engine {
void GLStateCache::init() {
glDisable(GL_CULL_FACE);
glDisable(GL_MULTISAMPLE);
glDisable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glDisable(GL_SCISSOR_TEST);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
void GLStateCache::setFaceCulling(bool enabled, bool frontFace) {
if (enabled) {
if (!s_cullingFaces) {
glEnable(GL_CULL_FACE);
s_cullingFaces = true;
}
if (frontFace != s_frontFaceCulling) {
glCullFace(frontFace ? GL_FRONT : GL_BACK);
s_frontFaceCulling = frontFace;
}
} else if (s_cullingFaces) {
glDisable(GL_CULL_FACE);
s_cullingFaces = false;
}
}
void GLStateCache::setAntialiasing(bool enabled) {
if (enabled == s_antialiasing) return;
enabled ? glEnable(GL_MULTISAMPLE) : glDisable(GL_MULTISAMPLE);
s_antialiasing = enabled;
}
void GLStateCache::setAlphaBlending(bool enabled) {
if (enabled == s_alphaBlending && !s_additiveBlending) return;
if (enabled) {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
s_alphaBlending = true;
s_additiveBlending = false;
} else if (s_alphaBlending) {
glDisable(GL_BLEND);
s_alphaBlending = false;
}
}
void GLStateCache::setAdditiveBlending(bool enabled) {
if (enabled && !s_additiveBlending) {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
s_additiveBlending = true;
s_alphaBlending = false;
} else if (!enabled && s_additiveBlending) {
glDisable(GL_BLEND);
s_additiveBlending = false;
}
}
void GLStateCache::setDepthTest(bool enabled) {
if (enabled == s_depthTest) return;
enabled ? glEnable(GL_DEPTH_TEST) : glDisable(GL_DEPTH_TEST);
s_depthTest = enabled;
}
void GLStateCache::setDepthWriting(bool enabled) {
if (enabled == s_depthWriting) return;
glDepthMask(enabled ? GL_TRUE : GL_FALSE);
s_depthWriting = enabled;
}
void GLStateCache::setScissorTest(bool enabled, int x, int y, int width, int height) {
if (enabled && !s_scissorTest) {
glEnable(GL_SCISSOR_TEST);
s_scissorTest = true;
} else if (!enabled && s_scissorTest) {
glDisable(GL_SCISSOR_TEST);
s_scissorTest = false;
return;
}
if (enabled && (x != s_scissorBounds[0] || y != s_scissorBounds[1] ||
width != s_scissorBounds[2] || height != s_scissorBounds[3])) {
glScissor(x, y, width, height);
s_scissorBounds[0] = x; s_scissorBounds[1] = y;
s_scissorBounds[2] = width; s_scissorBounds[3] = height;
}
}
void GLStateCache::setWireframe(bool enabled) {
if (enabled == s_wireframe) return;
glPolygonMode(GL_FRONT_AND_BACK, enabled ? GL_LINE : GL_FILL);
s_wireframe = enabled;
}
void GLStateCache::bindTexture2D(unsigned int textureId, int slot) {
glActiveTexture(GL_TEXTURE0 + slot);
glBindTexture(GL_TEXTURE_2D, textureId);
}
void GLStateCache::clearColorBuffer() { glClear(GL_COLOR_BUFFER_BIT); }
void GLStateCache::clearDepthBuffer() { glClear(GL_DEPTH_BUFFER_BIT); }
void GLStateCache::clearFrameBuffer() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); }
void GLStateCache::clearFrameBuffer(glm::vec4 color) {
glClearColor(color.r, color.g, color.b, color.a);
clearFrameBuffer();
}
}

View File

@ -0,0 +1,44 @@
//
// Created by sebastian on 29.07.26.
//
#ifndef COLORRACE_GLSTATECACHE_H
#define COLORRACE_GLSTATECACHE_H
#include "glm/vec4.hpp"
namespace engine {
class GLStateCache {
public:
static void init(); // einmal nach GLAD-Init aufrufen, um Startzustand zu setzen
static void setFaceCulling(bool enabled, bool frontFace);
static void setAntialiasing(bool enabled);
static void setAlphaBlending(bool enabled);
static void setAdditiveBlending(bool enabled);
static void setDepthTest(bool enabled);
static void setDepthWriting(bool enabled);
static void setScissorTest(bool enabled, int x = 0, int y = 0, int width = 0, int height = 0);
static void setWireframe(bool enabled);
static void bindTexture2D(unsigned int textureId, int slot);
static void clearColorBuffer();
static void clearDepthBuffer();
static void clearFrameBuffer();
static void clearFrameBuffer(glm::vec4 color);
private:
inline static bool s_cullingFaces = false;
inline static bool s_frontFaceCulling = false;
inline static bool s_antialiasing = false;
inline static bool s_alphaBlending = false;
inline static bool s_additiveBlending = false;
inline static bool s_depthTest = false;
inline static bool s_depthWriting = true;
inline static bool s_scissorTest = false;
inline static bool s_wireframe = false;
inline static int s_scissorBounds[4] = {0, 0, 0, 0};
inline static glm::vec4 s_clearColor = {0.0f, 0.0f, 0.0f, 1.0f};
};
}
#endif //COLORRACE_GLSTATECACHE_H

12
game/src/ColorRaceApp.cpp Normal file
View File

@ -0,0 +1,12 @@
//
// Created by sebastian on 29.07.26.
//
#include "ColorRaceApp.h"
void ColorRaceApp::onUpdate(float deltaTime) {
}
void ColorRaceApp::onRender() {
}

29
game/src/ColorRaceApp.h Normal file
View File

@ -0,0 +1,29 @@
//
// Created by sebastian on 29.07.26.
//
#ifndef COLORRACE_COLORRACEAPP_H
#define COLORRACE_COLORRACEAPP_H
#include "core/Application.h"
class ColorRaceApp : public engine::Application {
public:
static engine::EngineConfig makeConfig() {
engine::EngineConfig config;
config.windowWidth = 1280;
config.windowHeight = 720;
config.windowTitle = "ColorRace";
config.clearColor = glm::vec4(0.1f, 0.1f, 0.15f, 1.0f);
config.vsync = true;
return config;
}
ColorRaceApp() : Application(makeConfig()) {}
protected:
void onUpdate(float deltaTime) override;
void onRender() override;
};
#endif //COLORRACE_COLORRACEAPP_H

View File

@ -1,20 +1,8 @@
#include <iostream> #include "ColorRaceApp.h"
#include "core/Window.h"
#include "glad/glad.h"
// TIP To <b>Run</b> code, press <shortcut actionId="Run"/> or click the <icon src="AllIcons.Actions.Execute"/> icon in the gutter. // TIP To <b>Run</b> code, press <shortcut actionId="Run"/> or click the <icon src="AllIcons.Actions.Execute"/> icon in the gutter.
int main() { int main() {
engine::Window window(1280, 720, "ColorRace"); ColorRaceApp app;
app.run();
while (!window.shouldClose()) {
window.pollEvents();
glClearColor(0.1f, 0.1f, 0.15f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
window.swapBuffers();
}
return 0; return 0;
} }