srctree

Robin Linden parent 4aa35845 740791ad
gfx/opengl: Add a shader abstraction

filename was Deleted added: 151, removed: 2, total 149
@@ -0,0 +1,101 @@
// SPDX-FileCopyrightText: 2023 Robin Lindén <dev@robinlinden.eu>
//
// SPDX-License-Identifier: BSD-2-Clause
 
#include "gfx/opengl_shader.h"
 
#include <GL/glew.h>
 
#include <cassert>
#include <cstdlib>
#include <limits>
 
namespace gfx {
 
std::optional<OpenGLShader> OpenGLShader::create(std::string_view vertex_src, std::string_view fragment_src) {
// TODO(robinlinden): Move this somewhere more sensible. Calling it multiple
// times is fine, so it living here for now won't cause issues.
if (glewInit() != GLEW_OK) {
std::abort();
}
 
GLint success{0};
GLint shader_length{0};
GLchar const *shader_src{nullptr};
 
shader_length = static_cast<GLint>(vertex_src.length());
shader_src = vertex_src.data();
GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader, 1, &shader_src, &shader_length);
glCompileShader(vertex_shader);
glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);
if (success == GL_FALSE) {
glDeleteShader(vertex_shader);
return std::nullopt;
}
 
shader_length = static_cast<GLint>(fragment_src.length());
shader_src = fragment_src.data();
GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment_shader, 1, &shader_src, &shader_length);
glCompileShader(fragment_shader);
glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success);
if (success == GL_FALSE) {
glDeleteShader(fragment_shader);
glDeleteShader(vertex_shader);
return std::nullopt;
}
 
GLuint program = glCreateProgram();
if (program == 0) {
glDeleteShader(fragment_shader);
glDeleteShader(vertex_shader);
return std::nullopt;
}
 
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
glLinkProgram(program);
glGetProgramiv(program, GL_LINK_STATUS, &success);
if (success == GL_FALSE) {
glDeleteProgram(program);
glDeleteShader(fragment_shader);
glDeleteShader(vertex_shader);
return std::nullopt;
}
 
glDetachShader(program, fragment_shader);
glDetachShader(program, vertex_shader);
glDeleteShader(fragment_shader);
glDeleteShader(vertex_shader);
 
return OpenGLShader{program};
}
 
OpenGLShader::~OpenGLShader() {
if (program_ != 0) {
glDeleteProgram(program_);
}
}
 
void OpenGLShader::enable() {
glUseProgram(program_);
}
 
void OpenGLShader::disable() {
glUseProgram(0);
}
 
void OpenGLShader::set_uniform(char const *name, std::span<float const, 2> data) {
auto loc = glGetUniformLocation(program_, name);
assert(loc != -1);
glUniform2f(loc, data[0], data[1]);
}
 
void OpenGLShader::set_uniform(char const *name, std::span<float const, 4> data) {
auto loc = glGetUniformLocation(program_, name);
assert(loc != -1);
glUniform4f(loc, data[0], data[1], data[2], data[3]);
}
 
} // namespace gfx
 
filename was Deleted added: 151, removed: 2, total 149
@@ -0,0 +1,48 @@
// SPDX-FileCopyrightText: 2023 Robin Lindén <dev@robinlinden.eu>
//
// SPDX-License-Identifier: BSD-2-Clause
 
#ifndef GFX_OPENGL_SHADER_H_
#define GFX_OPENGL_SHADER_H_
 
#include <cstdint>
#include <optional>
#include <span>
#include <string_view>
#include <utility>
 
namespace gfx {
 
class OpenGLShader {
public:
static std::optional<OpenGLShader> create(std::string_view vertex_src, std::string_view fragment_src);
 
OpenGLShader(OpenGLShader const &) = delete;
OpenGLShader &operator=(OpenGLShader const &) = delete;
 
OpenGLShader(OpenGLShader &&o) noexcept : program_{std::exchange(o.program_, 0)} {}
OpenGLShader &operator=(OpenGLShader &&o) noexcept {
program_ = std::exchange(o.program_, 0);
return *this;
}
 
~OpenGLShader();
 
void enable();
void disable();
void set_uniform(char const *name, std::span<float const, 2>);
void set_uniform(char const *name, std::span<float const, 4>);
 
std::uint32_t id() const { return program_; }
 
private:
explicit OpenGLShader(std::uint32_t program) : program_{program} {}
 
// Really a GLuint, but https://www.khronos.org/opengl/wiki/OpenGL_Type says
// it's always exactly 32 bits wide, so let's hide the GL header properly.
std::uint32_t program_{0};
};
 
} // namespace gfx
 
#endif