Skip to content

Commit

Permalink
fully raii gl objects
Browse files Browse the repository at this point in the history
  • Loading branch information
archibate committed May 11, 2024
1 parent 3bd33a3 commit 52acbee
Show file tree
Hide file tree
Showing 8 changed files with 280 additions and 30 deletions.
1 change: 0 additions & 1 deletion include/Game.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ struct Game {

Game(Game &&) = delete;

static Game &get();
void set_window(GLFWwindow *window);
void initialize();
void render();
Expand Down
15 changes: 13 additions & 2 deletions include/OBJ.hpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
#pragma once

#include "check_gl.hpp"
#include <glm/glm.hpp>
#include <glm/ext.hpp>
#include <vector>
#include <string>

struct DrawableOBJ {
check_gl::GLVertexArray vao;
check_gl::GLBuffer vbo;
check_gl::GLBuffer ebo;
std::size_t numElements;

void draw();
};

struct OBJ {
struct Vertex {
glm::vec3 position;
Expand All @@ -13,5 +24,5 @@ struct OBJ {

void load_obj(std::string path);
void auto_normal();
void draw_obj();
[[nodiscard]] DrawableOBJ draw_obj();
};
229 changes: 229 additions & 0 deletions include/check_gl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <string>
#include <tuple>

namespace check_gl {
const char *opengl_errno_name(GLenum err);
Expand All @@ -18,3 +19,231 @@ void opengl_link_program(unsigned int program);
(x); \
::check_gl::opengl_check_error(__FILE__, __LINE__, #x); \
} while (0)

namespace check_gl {

struct GLHandle {
unsigned int handle;

GLHandle() noexcept : handle(0) {
}

explicit GLHandle(std::nullptr_t) noexcept : handle(0) {
}

explicit GLHandle(unsigned int handle) noexcept : handle(handle) {
}

operator unsigned int() const noexcept {
return handle;
}

unsigned int get() const noexcept {
return handle;
}

unsigned int release() noexcept {
unsigned int ret = handle;
handle = 0;
return ret;
}

GLHandle(GLHandle &&that) noexcept : handle(that.handle) {
that.handle = 0;
}

GLHandle &operator=(GLHandle &&that) noexcept {
std::swap(handle, that.handle);
return *this;
}
};

template <class Derived>
struct GLHandleImpl : GLHandle {
using GLHandle::GLHandle;

GLHandleImpl(GLHandleImpl &&) = default;
GLHandleImpl &operator=(GLHandleImpl &&) = default;

struct [[nodiscard]] BindGuard : GLHandle {
private:
BindGuard(unsigned int handle) noexcept : GLHandle(handle) {
}

friend GLHandleImpl;

public:
BindGuard() = default;
BindGuard(BindGuard &&) = default;
BindGuard &operator=(BindGuard &&) = default;

~BindGuard() noexcept(false) {
Derived::on_bind(0);
}
};

struct [[nodiscard]] BindTargetGuard : GLHandle {
private:
unsigned int target;

BindTargetGuard(unsigned int target, unsigned int handle) noexcept : GLHandle(handle), target(target) {
}

friend GLHandleImpl;

public:
BindTargetGuard() = default;
BindTargetGuard(BindTargetGuard &&) = default;
BindTargetGuard &operator=(BindTargetGuard &&) = default;

~BindTargetGuard() noexcept(false) {
Derived::on_bind(target, 0);
}
};

BindGuard bind() {
static_assert(std::is_base_of_v<GLHandleImpl, Derived>);
Derived::on_bind(this->handle);
return BindGuard(this->handle);
}

BindTargetGuard bind(unsigned int target) {
static_assert(std::is_base_of_v<GLHandleImpl, Derived>);
Derived::on_bind(target, this->handle);
return BindTargetGuard(target, this->handle);
}

/* template <class ...Args> */
/* static Derived make(Args ...args) { */
/* unsigned int handle; */
/* Derived::on_gen(1, &handle, args...); */
/* return Derived(handle); */
/* } */

template <class ...Args>
Derived &make(Args ...args) {
if (this->handle) {
Derived::on_delete(1, &this->handle);
}
Derived::on_gen(1, &this->handle, args...);
return static_cast<Derived &>(*this);
}

void reset(unsigned int handle) {
if (this->handle) {
Derived::on_delete(1, &this->handle);
}
this->handle = handle;
}

~GLHandleImpl() {
static_assert(std::is_base_of_v<GLHandleImpl, Derived>);
if (this->handle) {
Derived::on_delete(1, &this->handle);
}
}
};

struct GLProgram : GLHandleImpl<GLProgram> {
static void on_gen(size_t count, unsigned int *handles) {
for (size_t i = 0; i < count; ++i) {
CHECK_GL(handles[i] = glCreateProgram());
}
}

static void on_delete(size_t count, const unsigned int *handles) {
for (size_t i = 0; i < count; ++i) {
CHECK_GL(glDeleteProgram(handles[i]));
}
}

static void on_bind(unsigned int handle) {
CHECK_GL(glUseProgram(handle));
}
};

struct GLShader : GLHandleImpl<GLShader> {
static void on_gen(size_t count, unsigned int *handles, unsigned int type) {
for (size_t i = 0; i < count; ++i) {
CHECK_GL(handles[i] = glCreateShader(type));
}
}

static void on_delete(size_t count, const unsigned int *handles) {
for (size_t i = 0; i < count; ++i) {
CHECK_GL(glDeleteShader(handles[i]));
}
}
};

struct GLBuffer : GLHandleImpl<GLBuffer> {
static void on_gen(size_t count, unsigned int *handles) {
CHECK_GL(glGenBuffers(count, handles));
}

static void on_delete(size_t count, const unsigned int *handles) {
CHECK_GL(glDeleteBuffers(count, handles));
}

static void on_bind(unsigned int target, unsigned int handle) {
CHECK_GL(glBindBuffer(target, handle));
}
};

struct GLVertexArray : GLHandleImpl<GLVertexArray> {
static void on_gen(size_t count, unsigned int *handles) {
CHECK_GL(glGenVertexArrays(count, handles));
}

static void on_delete(size_t count, const unsigned int *handles) {
CHECK_GL(glDeleteVertexArrays(count, handles));
}

static void on_bind(unsigned int handle) {
CHECK_GL(glBindVertexArray(handle));
}
};

struct GLFramebuffer : GLHandleImpl<GLFramebuffer> {
static void on_gen(size_t count, unsigned int *handles) {
CHECK_GL(glGenFramebuffers(count, handles));
}

static void on_delete(size_t count, const unsigned int *handles) {
CHECK_GL(glDeleteFramebuffers(count, handles));
}

static void on_bind(unsigned int target, unsigned int handle) {
CHECK_GL(glBindFramebuffer(target, handle));
}
};

struct GLRenderbuffer : GLHandleImpl<GLRenderbuffer> {
static void on_gen(size_t count, unsigned int *handles) {
CHECK_GL(glGenRenderbuffers(count, handles));
}

static void on_delete(size_t count, const unsigned int *handles) {
CHECK_GL(glDeleteRenderbuffers(count, handles));
}

static void on_bind(unsigned int target, unsigned int handle) {
CHECK_GL(glBindRenderbuffer(target, handle));
}
};

struct GLTexture : GLHandleImpl<GLRenderbuffer> {
static void on_gen(size_t count, unsigned int *handles) {
CHECK_GL(glGenTextures(count, handles));
}

static void on_delete(size_t count, const unsigned int *handles) {
CHECK_GL(glDeleteTextures(count, handles));
}

static void on_bind(unsigned int target, unsigned int handle) {
CHECK_GL(glBindTexture(target, handle));
}
};

}
9 changes: 3 additions & 6 deletions src/Game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,14 @@ struct Game::Private { // P-IMPL pattern
glm::mat4x4 projMat;

OBJ obj;
DrawableOBJ drawable;
unsigned int program;
};

Game::Game() : m_private(std::make_unique<Private>()) {}

Game::~Game() = default;

Game &Game::get() {
static Game game; // singleton
return game;
}

void Game::set_window(GLFWwindow *window) {
m_window = window;
glfwSetWindowUserPointer(window, this);
Expand Down Expand Up @@ -89,5 +85,6 @@ void Game::render() {
glm::vec3 lightDir = glm::normalize(glm::vec3(mousePos.x, mousePos.y, 1));
int location = glGetUniformLocation(m_private->program, "uniLightDir");
CHECK_GL(glUniform3fv(location, 1, glm::value_ptr(lightDir)));
m_private->obj.draw_obj();
m_private->drawable = m_private->obj.draw_obj();
m_private->drawable.draw();
}
8 changes: 8 additions & 0 deletions src/InputCtl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,10 @@ void InputCtl::cursor_pos_callback(double xpos, double ypos) {
}

void InputCtl::mouse_button_callback(int button, int action, int mods) {
(void)button;
(void)action;
(void)mods;

auto pos = get_cursor_pos();
m_private->lastpos = pos;

Expand Down Expand Up @@ -230,6 +234,10 @@ void InputCtl::scroll_callback(double xoffset, double yoffset) {
}

void InputCtl::key_callback(int key, int scancode, int action, int mods) {
(void)key;
(void)scancode;
(void)action;
(void)mods;
}

void InputCtl::framebuffer_size_callback(int width, int height) {
Expand Down
36 changes: 19 additions & 17 deletions src/OBJ.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "Game.hpp"
#include "fileutils.hpp"
#include <sstream>
#include <glm/ext.hpp>

void OBJ::load_obj(std::string path) {
std::ifstream file(path);
Expand Down Expand Up @@ -87,30 +88,29 @@ void OBJ::auto_normal() {
}
}

void DrawableOBJ::draw() {
auto vaoBind = vao.bind();
auto eboBind = ebo.bind(GL_ELEMENT_ARRAY_BUFFER);
CHECK_GL(glDrawElements(GL_TRIANGLES, numElements, GL_UNSIGNED_INT, (void *)0));
}

void OBJ::draw_obj() {
unsigned int vao = 0;
unsigned int vbo = 0;
unsigned int ebo = 0;
CHECK_GL(glGenVertexArrays(1, &vao));
CHECK_GL(glGenBuffers(1, &vbo));
CHECK_GL(glGenBuffers(1, &ebo));
CHECK_GL(glBindVertexArray(vao));
CHECK_GL(glBindBuffer(GL_ARRAY_BUFFER, vbo));
DrawableOBJ OBJ::draw_obj() {
DrawableOBJ drawable;
drawable.vao.make();
drawable.vbo.make();
drawable.ebo.make();
auto vboBind = drawable.vbo.bind(GL_ARRAY_BUFFER);
CHECK_GL(glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * vertices.size(), vertices.data(), GL_STATIC_DRAW));
CHECK_GL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo));
auto eboBind = drawable.ebo.bind(GL_ELEMENT_ARRAY_BUFFER);
CHECK_GL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(glm::uvec3) * faces.size(), faces.data(), GL_STATIC_DRAW));
auto vaoBind = drawable.vao.bind();
CHECK_GL(glEnableVertexAttribArray(0));
CHECK_GL(glEnableVertexAttribArray(1));
CHECK_GL(glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)offsetof(Vertex, position)));
CHECK_GL(glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)offsetof(Vertex, normal)));
CHECK_GL(glDrawElements(GL_TRIANGLES, faces.size() * 3, GL_UNSIGNED_INT, (void *)0));
CHECK_GL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
CHECK_GL(glBindBuffer(GL_ARRAY_BUFFER, 0));
CHECK_GL(glBindVertexArray(0));
CHECK_GL(glDeleteBuffers(1, &vbo));
CHECK_GL(glDeleteBuffers(1, &ebo));
CHECK_GL(glDeleteVertexArrays(1, &vao));
drawable.numElements = faces.size() * 3;
/* CHECK_GL(glDrawElements(GL_TRIANGLES, drawable.numElements, GL_UNSIGNED_INT, (void *)0)); */
return drawable;

/* glBegin(GL_TRIANGLES); */
/* for (auto const &face: faces) { */
Expand All @@ -125,4 +125,6 @@ void OBJ::draw_obj() {
/* glVertexAttrib3fv(0, glm::value_ptr(c.position)); */
/* } */
/* CHECK_GL(glEnd()); */

return {};
}
3 changes: 3 additions & 0 deletions src/check_gl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ static void APIENTRY opengl_debug_message_callback(
GLenum severity, GLsizei length,
const GLchar *msg, const void *data)
{
(void)length;
(void)data;

// if (severity == GL_DEBUG_SEVERITY_NOTIFICATION) return;

// ignore some non-important warning ids:
Expand Down
Loading

0 comments on commit 52acbee

Please sign in to comment.