Skip to content

Instantly share code, notes, and snippets.

@Fulgen301
Created October 19, 2021 20:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Fulgen301/18be951eb51cef5b3701d60587f52adf to your computer and use it in GitHub Desktop.
Save Fulgen301/18be951eb51cef5b3701d60587f52adf to your computer and use it in GitHub Desktop.
StdGLHelpers
/*
*LegacyClonk
*
*Copyright (c) 2021, The LegacyClonk Team and contributors
*
*Distributed under the terms of the ISC license; see accompanying file
*"COPYING" for details.
*
*"Clonk" is a registered trademark of Matthes Bender, used with permission.
*See accompanying file "TRADEMARK" for details.
*
*To redistribute this file separately, substitute the full license texts
*for the above references.
*/
#include "Shader.h"
void CStdShader::SetMacro(std::string_view key, std::string_view value)
{
macros[key.data()] = value;
}
void CStdShader::UnsetMacro(std::string_view key)
{
macros.erase(key.data());
}
void CStdShader::SetSource(const std::string &source)
{
this->source = source;
}
void CStdShader::AddInclude(const std::string &source)
{
includes.emplace_back(source);
}
void CStdShader::SetType(Type type)
{
this->type = type;
}
void CStdShader::Clear()
{
source.clear();
macros.clear();
includes.clear();
errorMessage.clear();
}
CStdShaderProgram *CStdShaderProgram::currentShaderProgram = nullptr;
bool CStdShaderProgram::AddShader(CStdShader *shader)
{
EnsureProgram();
if (std::find(shaders.cbegin(), shaders.cend(), shader) != shaders.cend())
{
return true;
}
if (AddShaderInt(shader))
{
shaders.push_back(shader);
return true;
}
return false;
}
void CStdShaderProgram::Clear()
{
shaders.clear();
}
void CStdShaderProgram::Select()
{
if (currentShaderProgram != this)
{
OnSelect();
currentShaderProgram = this;
}
}
void CStdShaderProgram::Deselect()
{
if (currentShaderProgram)
{
currentShaderProgram->OnDeselect();
currentShaderProgram = nullptr;
}
}
CStdShaderProgram *CStdShaderProgram::GetCurrentShaderProgram()
{
return currentShaderProgram;
}
void CStdGLShader::Compile()
{
if (shader) // recompiling?
{
glDeleteShader(shader);
errorMessage.clear();
}
GLenum t;
switch (type)
{
case Type::Vertex:
t = GL_VERTEX_SHADER;
break;
case Type::TesselationControl:
t = GL_TESS_CONTROL_SHADER;
break;
case Type::TesselationEvaluation:
t = GL_TESS_EVALUATION_SHADER;
break;
case Type::Geometry:
t = GL_GEOMETRY_SHADER;
break;
case Type::Fragment:
t = GL_FRAGMENT_SHADER;
break;
case Type::Compute:
t = GL_COMPUTE_SHADER;
break;
default:
throw Exception{"Invalid shader type"};
}
shader = glCreateShader(t);
if (!shader)
{
throw Exception{"Could not create shader"};
}
PrepareSource();
GLint status = 0;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if (!status)
{
GLint size = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &size);
if (size)
{
std::string errorMessage;
errorMessage.resize(size);
glGetShaderInfoLog(shader, size, NULL, errorMessage.data());
throw Exception{errorMessage.c_str()};
}
throw Exception{"Unknown error"};
}
}
void CStdGLShader::Clear()
{
if (shader)
{
glDeleteShader(shader);
shader = 0;
}
CStdShader::Clear();
}
void CStdGLShader::PrepareSource()
{
size_t pos = source.find("#version");
if (pos == std::string::npos)
{
glDeleteShader(shader);
throw Exception{"Version directive must be first statement and may not be repeated"};
}
pos = source.find('\n', pos + 1);
assert(pos != std::string::npos);
std::string copy = source;
std::string buffer = "";
for (const auto &[key, value] : macros)
{
buffer.append("#define ");
buffer.append(key);
buffer.append(" ");
buffer.append(value);
buffer.append("\n");
}
for (const auto &include : includes)
{
buffer.append(include);
}
buffer.append("#line 1\n");
copy.insert(pos + 1, buffer);
const char *s = copy.c_str();
glShaderSource(shader, 1, &s, nullptr);
glCompileShader(shader);
}
void CStdGLShaderProgram::Link()
{
EnsureProgram();
glLinkProgram(shaderProgram);
GLint status = 0;
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &status);
if (!status)
{
GLint size = 0;
glGetProgramiv(shaderProgram, GL_INFO_LOG_LENGTH, &size);
assert(size);
if (size)
{
std::string errorMessage;
errorMessage.resize(size);
glGetProgramInfoLog(shaderProgram, size, NULL, errorMessage.data());
throw Exception{errorMessage.c_str()};
}
throw Exception{"Unknown error"};
}
glValidateProgram(shaderProgram);
glGetProgramiv(shaderProgram, GL_VALIDATE_STATUS, &status);
if (!status)
{
GLint size = 0;
glGetProgramiv(shaderProgram, GL_INFO_LOG_LENGTH, &size);
if (size)
{
errorMessage.resize(size);
glGetProgramInfoLog(shaderProgram, size, NULL, errorMessage.data());
throw Exception{errorMessage.c_str()};
}
throw Exception{"Unknown error"};
}
for (const auto &shader : shaders)
{
glDetachShader(shaderProgram, dynamic_cast<CStdGLShader*>(shader)->GetHandle());
}
shaders.clear();
}
void CStdGLShaderProgram::Clear()
{
for (const auto &shader : shaders)
{
glDetachShader(shaderProgram, dynamic_cast<CStdGLShader*>(shader)->GetHandle());
}
if (shaderProgram)
{
glDeleteProgram(shaderProgram);
shaderProgram = 0;
}
attributeLocations.clear();
uniformLocations.clear();
CStdShaderProgram::Clear();
}
void CStdGLShaderProgram::EnsureProgram()
{
if (!shaderProgram)
{
shaderProgram = glCreateProgram();
}
assert(shaderProgram);
}
bool CStdGLShaderProgram::SetUniform(std::string_view key, const glm::vec2 &value)
{
return SetUniform(key, glUniform2fv, 1, glm::value_ptr(value));
}
bool CStdGLShaderProgram::SetUniform(std::string_view key, const glm::vec3 &value)
{
return SetUniform(key, glUniform3fv, 1, glm::value_ptr(value));
}
bool CStdGLShaderProgram::SetUniform(std::string_view key, const glm::vec4 &value)
{
return SetUniform(key, glUniform4fv, 1, glm::value_ptr(value));
}
bool CStdGLShaderProgram::SetUniform(std::string_view key, const glm::mat4 &value)
{
return SetUniform(key, glUniformMatrix4fv, 1, false, glm::value_ptr(value));
}
void CStdGLShaderProgram::SetObjectLabel(std::string_view label)
{
glObjectLabel(GL_PROGRAM, shaderProgram, label.size(), label.data());
}
bool CStdGLShaderProgram::AddShaderInt(CStdShader *shader)
{
if (auto *s = dynamic_cast<CStdGLShader*>(shader); s)
{
glAttachShader(shaderProgram, s->GetHandle());
return true;
}
return false;
}
void CStdGLShaderProgram::OnSelect()
{
assert(shaderProgram);
glUseProgram(shaderProgram);
}
void CStdGLShaderProgram::OnDeselect()
{
glUseProgram(GL_NONE);
}
void CStdRectangle::GenerateGeometry(std::vector<GLfloat> &vertices, std::vector<GLuint> &elements, std::vector<GLfloat> &normals, std::vector<GLfloat> &textureCoordinates)
{
vertices = {
-1.0f, -1.0f, // top left
1.0f, -1.0f, // bottom left
1.0f, 1.0f, // bottom right
-1.0f, 1.0f, // top right
};
elements = { // note that we start from 0!
0, 1, 2, // first triangle
2, 3, 0 // second triangle
};
textureCoordinates = {
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
0.0f, 1.0f
};
}
void CStdTexture3D::BindImage(GLuint unit, GLenum access) const
{
glBindImageTexture(unit, texture, 0, GL_TRUE, 0, access, internalFormat);
}
CStdFramebuffer::CStdFramebuffer(const std::int32_t width, const std::int32_t height)
: colorAttachment{{width, height}, InternalFormat, Format, Type}
{
glGenFramebuffers(1, &FBO);
colorAttachment.Bind(0);
glBindFramebuffer(GL_FRAMEBUFFER, FBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, decltype(colorAttachment)::Target, colorAttachment.GetTexture(), 0);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
{
throw std::runtime_error{ "glCheckFramebufferStatus" };
}
glViewport(0, 0, width, height);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
glBindFramebuffer(GL_FRAMEBUFFER, GL_NONE);
}
CStdFramebuffer::~CStdFramebuffer()
{
if (FBO)
{
glDeleteFramebuffers(1, &FBO);
}
}
void CStdFramebuffer::Bind() const
{
glBindFramebuffer(GL_FRAMEBUFFER, FBO);
}
void CStdFramebuffer::BindTexture(const GLenum offset) const
{
colorAttachment.Bind(offset);
}
void CStdFramebuffer::Unbind() const
{
glBindFramebuffer(GL_FRAMEBUFFER, GL_NONE);
}
void CStdSwappableFramebuffer::Bind() const
{
GetFront().Bind();
}
void CStdSwappableFramebuffer::Unbind() const
{
GetFront().Unbind();
}
void CStdSwappableTexture3D::Bind(const GLenum offset) const
{
GetFront().Bind(offset);
}
/*
*LegacyClonk
*
*Copyright (c) 2021, The LegacyClonk Team and contributors
*
*Distributed under the terms of the ISC license; see accompanying file
*"COPYING" for details.
*
*"Clonk" is a registered trademark of Matthes Bender, used with permission.
*See accompanying file "TRADEMARK" for details.
*
*To redistribute this file separately, substitute the full license texts
*for the above references.
*/
#pragma once
#include <iostream>
#include OPENGL_LOADER
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <array>
#include <string_view>
#include <unordered_map>
// shader
class CStdShader
{
public:
class Exception : public std::runtime_error
{
public:
using runtime_error::runtime_error;
};
enum class Type : uint8_t
{
Vertex,
TesselationControl,
TesselationEvaluation,
Geometry,
Fragment,
Compute
};
public:
CStdShader() = default;
explicit CStdShader(Type type, const std::string &source) : type{ type }, source{ source } {}
CStdShader(const CStdShader&) = delete;
virtual ~CStdShader() { Clear(); }
void SetMacro(std::string_view key, std::string_view value);
void UnsetMacro(std::string_view key);
void SetSource(const std::string &source);
void AddInclude(const std::string &source);
void SetType(Type type);
virtual void Compile() = 0;
virtual void Clear();
std::string GetSource() const { return source; }
virtual int64_t GetHandle() const = 0;
std::unordered_map<std::string, std::string> GetMacros() const { return macros; }
std::string GetErrorMessage() const { return errorMessage; }
virtual Type GetType() const { return type; }
protected:
Type type;
std::string source;
std::vector<std::string> includes;
std::unordered_map<std::string, std::string> macros;
std::string errorMessage;
};
class CStdGLShader : public CStdShader
{
public:
using CStdShader::CStdShader;
void Compile() override;
void Clear() override;
virtual int64_t GetHandle() const override { return shader; }
protected:
virtual void PrepareSource();
protected:
GLuint shader = 0;
};
class CStdShaderProgram
{
public:
class Exception : public std::runtime_error
{
public:
using runtime_error::runtime_error;
};
public:
CStdShaderProgram() = default;
CStdShaderProgram(const CStdShaderProgram&) = delete;
virtual ~CStdShaderProgram() { Clear(); }
virtual explicit operator bool() const = 0;
bool AddShader(CStdShader *shader);
virtual void Link() = 0;
void Select();
static void Deselect();
virtual void Clear();
virtual void EnsureProgram() = 0;
virtual int64_t GetProgram() const = 0;
std::vector<CStdShader*> GetPendingShaders() const { return shaders; }
static CStdShaderProgram *GetCurrentShaderProgram();
protected:
virtual bool AddShaderInt(CStdShader *shader) = 0;
virtual void OnSelect() = 0;
virtual void OnDeselect() = 0;
protected:
std::vector<CStdShader*> shaders;
std::string errorMessage;
static CStdShaderProgram *currentShaderProgram;
};
class CStdGLShaderProgram : public CStdShaderProgram
{
public:
using CStdShaderProgram::CStdShaderProgram;
explicit operator bool() const override { return /*glIsProgram(*/shaderProgram/*)*/; }
void Link() override;
void Clear() override;
void EnsureProgram() override;
template<typename Func, typename... Args> bool SetAttribute(std::string_view key, Func function, Args... args)
{
return SetAttribute(key, &CStdGLShaderProgram::attributeLocations, glGetAttribLocation, function, args...);
}
template<typename Func, typename... Args> bool SetUniform(std::string_view key, Func function, Args... args)
{
return SetAttribute(key, &CStdGLShaderProgram::uniformLocations, glGetUniformLocation, function, args...);
}
bool SetUniform(std::string_view key, float value) { return SetUniform(key, glUniform1f, value); }
bool SetUniform(std::string_view key, const glm::vec2 &value);
bool SetUniform(std::string_view key, const glm::vec3 &value);
bool SetUniform(std::string_view key, const glm::vec4 &value);
bool SetUniform(std::string_view key, const glm::mat4 &value);
void EnterGroup(const std::string &name) { group.assign(name).append("."); }
void LeaveGroup() { group.clear(); }
void SetObjectLabel(std::string_view label);
virtual int64_t GetProgram() const override { return shaderProgram; }
protected:
bool AddShaderInt(CStdShader *shader) override;
void OnSelect() override;
void OnDeselect() override;
using Locations = std::unordered_map<std::string, GLint>;
template<typename MapFunc, typename SetFunc, typename... Args> bool SetAttribute(std::string_view key, Locations CStdGLShaderProgram:: *locationPointer, MapFunc mapFunction, SetFunc setFunction, Args... args)
{
assert(shaderProgram);
std::string realKey{ group };
realKey.append(key.data());
GLint location;
Locations &locations{ this->*locationPointer };
if (auto it = locations.find(realKey); it != locations.end())
{
location = it->second;
assert(location != -1);
}
else
{
location = mapFunction(shaderProgram, realKey.c_str());
if (location == -1)
{
return false;
}
locations.emplace(realKey, location);
}
setFunction(location, args...);
return true;
}
protected:
GLuint shaderProgram{GL_NONE};
Locations attributeLocations;
Locations uniformLocations;
std::string group;
};
template<typename Class>
class CStdVAOObject
{
public:
CStdVAOObject() = default;
virtual ~CStdVAOObject()
{
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(VBO.size(), VBO.data());
}
public:
void Bind() const
{
glBindVertexArray(VAO);
}
void Draw() const
{
glDrawElements(Class::PrimitiveType, elementCount, GL_UNSIGNED_INT, nullptr);
}
protected:
void Init()
{
assert(!VAO);
glGenVertexArrays(1, &VAO);
glGenBuffers(VBO.size(), VBO.data());
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, VBO[VBO.size() - 1]);
std::vector<GLfloat> vertices;
std::vector<GLuint> elements;
std::vector<GLfloat> normals;
std::vector<GLfloat> textureCoordinates;
GenerateGeometry(vertices, elements, normals, textureCoordinates);
elementCount = elements.size();
constexpr std::size_t dimensions{Class::Dimensions};
glBufferData(GL_ARRAY_BUFFER, vertices.size() *sizeof(GLfloat), vertices.data(), GL_STATIC_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, elementCount *sizeof(GLuint), elements.data(), GL_STATIC_DRAW);
glVertexAttribPointer(0, dimensions, GL_FLOAT, GL_FALSE, dimensions *sizeof(GLfloat), nullptr);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, VBO[1]);
glBufferData(GL_ARRAY_BUFFER, normals.size() *sizeof(GLfloat), normals.data(), GL_STATIC_DRAW);
glVertexAttribPointer(1, dimensions, GL_FLOAT, GL_FALSE, dimensions *sizeof(GLfloat), nullptr);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, VBO[2]);
glBufferData(GL_ARRAY_BUFFER, textureCoordinates.size() *sizeof(GLfloat), textureCoordinates.data(), GL_STATIC_DRAW);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 2 *sizeof(GLfloat), nullptr);
glEnableVertexAttribArray(2);
glBindVertexArray(GL_NONE);
glBindBuffer(GL_ARRAY_BUFFER, GL_NONE);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_NONE);
}
virtual void GenerateGeometry(std::vector<GLfloat> &vertices, std::vector<GLuint> &indices, std::vector<GLfloat> &normals, std::vector<GLfloat> &textureCoordinates) = 0;
private:
std::size_t elementCount{0};
GLuint VAO{GL_NONE};
std::array<GLuint, 4> VBO{GL_NONE};
};
class CStdRectangle : public CStdVAOObject<CStdRectangle>
{
public:
static constexpr inline auto Dimensions = 2;
static constexpr inline auto PrimitiveType = GL_TRIANGLES;
public:
CStdRectangle() : CStdVAOObject{} { Init(); }
protected:
virtual void GenerateGeometry(std::vector<GLfloat> &vertices, std::vector<GLuint> &elements, std::vector<GLfloat> &normals, std::vector<GLfloat> &textureCoordinates) override;
};
template<GLenum Target, std::size_t Dimensions>
class CStdTexture;
template<GLenum Target, std::size_t Dimensions>
struct CStdTextureHelper
{
static void SetData(const CStdTexture<Target, Dimensions> &texture, void *const data);
};
template<GLenum T, std::size_t Dimensions>
class CStdTexture
{
private:
friend struct CStdTextureHelper<T, Dimensions>;
public:
static constexpr GLenum Target{T};
public:
CStdTexture() : dimensions{}, texture{GL_NONE}, internalFormat{GL_NONE}, format{GL_NONE}, type{GL_NONE} {}
CStdTexture(const std::array<std::int32_t, Dimensions> &dimensions, GLenum internalFormat, GLenum format, GLenum type, void *const data = nullptr)
: dimensions{dimensions}, internalFormat{internalFormat}, format{format}, type{type}
{
glGenTextures(1, &texture);
glBindTexture(Target, texture);
glTexParameteri(Target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(Target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
SetData(data);
}
CStdTexture(const CStdTexture &) = delete;
CStdTexture(CStdTexture& &other) : CStdTexture{}
{
swap(*this, other);
}
~CStdTexture()
{
if (texture)
{
glDeleteTextures(1, &texture);
}
}
CStdTexture &operator=(const CStdTexture &other) = delete;
CStdTexture &operator=(CStdTexture &&other)
{
swap(*this, other);
return *this;
}
template<GLenum T, std::size_t D> friend void swap(CStdTexture<T, D> &first, CStdTexture<T, D> &second);
public:
void Bind(GLenum offset) const
{
glActiveTexture(GL_TEXTURE0 + offset);
glBindTexture(Target, texture);
}
void SetData(void *const data) const
{
CStdTextureHelper<Target, Dimensions>::SetData(*this, data);
}
GLuint GetTexture() const { return texture; }
protected:
GLuint texture{GL_NONE};
std::array<std::int32_t, Dimensions> dimensions;
GLenum internalFormat;
GLenum format;
GLenum type;
};
template<GLenum Target, std::size_t Dimensions> inline void swap(CStdTexture<Target, Dimensions> &first, CStdTexture<Target, Dimensions> &second)
{
using std::swap;
swap(first.texture, second.texture);
swap(first.dimensions, second.dimensions);
swap(first.internalFormat, second.internalFormat);
swap(first.format, second.format);
swap(first.type, second.type);
}
template<GLenum Target>
struct CStdTextureHelper<Target, 2>
{
static void SetData(const CStdTexture<Target, 2> &texture, void *const data)
{
glTexImage2D(Target, 0, texture.internalFormat, texture.dimensions[0], texture.dimensions[1], 0, texture.format, texture.type, data);
}
};
template<GLenum Target>
struct CStdTextureHelper<Target, 3>
{
static void SetData(const CStdTexture<Target, 3> &texture, void *const data)
{
glTexImage3D(Target, 0, texture.internalFormat, texture.dimensions[0], texture.dimensions[1], texture.dimensions[2], 0, texture.format, texture.type, data);
}
};
class CStdTexture3D : public CStdTexture<GL_TEXTURE_3D, 3>
{
public:
CStdTexture3D() : CStdTexture{} {}
CStdTexture3D(const std::int32_t width, const std::int32_t height,const std::int32_t depth, const GLenum internalFormat, const GLenum format, const GLenum type, void *const data = nullptr)
: CStdTexture{{width, height, depth}, internalFormat, format, type, data} {}
CStdTexture3D(const std::int32_t width, const std::int32_t height, const std::int32_t depth, const std::uint8_t channels, const bool snorm = false, const bool use32BitComponentWidth = false, void *const data = nullptr)
: CStdTexture3D{width, height, depth, snorm ? InternalSnormFormats.at(channels - 1) : InternalFormats.at(channels - 1)[use32BitComponentWidth], Formats[channels - 1], GL_FLOAT, data} {}
CStdTexture3D(const CStdTexture3D &) = delete;
CStdTexture3D(CStdTexture3D& &other) : CStdTexture3D{}
{
swap(*this, other);
}
CStdTexture3D &operator=(const CStdTexture3D &other) = delete;
CStdTexture3D &operator=(CStdTexture3D &&other)
{
swap(*this, other);
return *this;
}
public:
void BindImage(GLuint unit, GLenum access) const;
private:
static constexpr std::array<GLenum, 4> Formats{GL_RED, GL_RG, GL_RGB, GL_RGBA};
static constexpr std::array<std::array<GLenum, 2>, 4> InternalFormats
{{
{GL_R32F, GL_R16F},
{GL_RG32F, GL_RG16F},
{GL_RGB32F, GL_RGB16F},
{GL_RGBA32F, GL_RGBA16F}
}};
static constexpr std::array<GLenum, 4> InternalSnormFormats{GL_R16_SNORM, GL_RG16_SNORM, GL_RGB16_SNORM, GL_RGBA16_SNORM};
static constexpr auto Type = GL_FLOAT;
};
template<typename T>
class CStdSwappable
{
public:
CStdSwappable() : buffer1{}, buffer2{}, front{nullptr}, back{nullptr} {}
template<typename... Args> CStdSwappable(Args... args) : buffer1{args...}, buffer2{args...}, front{&buffer1}, back{&buffer2} {}
CStdSwappable(CStdSwappable<T> &&other) : CStdSwappable{}
{
swap(*this, other);
}
CStdSwappable<T> &operator=(CStdSwappable<T> &&other)
{
swap(*this, other);
return *this;
}
template<typename T>
friend void swap(CStdSwappable<T> &first, CStdSwappable<T> &second);
public:
void SwapBuffers()
{
using std::swap;
swap(front, back);
}
const T &GetFront() const { return *front; }
const T &GetBack() const { return *back; }
private:
T buffer1;
T buffer2;
T *front;
T *back;
};
template<typename T>
inline void swap(CStdSwappable<T> &first, CStdSwappable<T> &second)
{
using std::swap;
swap(first.buffer1, second.buffer1);
swap(first.buffer2, second.buffer2);
first.front = second.front == &second.buffer1 ? &first.buffer1 : &first.buffer2;
first.back = second.back == &second.buffer2 ? &first.buffer2 : &first.buffer1;
}
class CStdFramebuffer
{
public:
CStdFramebuffer() : colorAttachment{}, FBO{GL_NONE} {}
CStdFramebuffer(std::int32_t width, std::int32_t height);
~CStdFramebuffer();
CStdFramebuffer(CStdFramebuffer &&other) : CStdFramebuffer{}
{
swap(*this, other);
}
CStdFramebuffer &operator=(CStdFramebuffer &&other)
{
swap(*this, other);
return *this;
}
friend void swap(CStdFramebuffer &first, CStdFramebuffer &second)
{
using std::swap;
swap(first.colorAttachment, second.colorAttachment);
swap(first.FBO, second.FBO);
}
public:
void Bind() const;
void BindTexture(GLenum offset) const;
void Unbind() const;
const CStdTexture<GL_TEXTURE_2D, 2> &GetTexture() const { return colorAttachment; }
private:
static constexpr inline auto InternalFormat = GL_RG16F;
static constexpr inline auto Format = GL_RG;
static constexpr inline auto Type = GL_FLOAT;
CStdTexture<GL_TEXTURE_2D, 2> colorAttachment;
GLuint FBO;
};
class CStdSwappableFramebuffer : public CStdSwappable<CStdFramebuffer>
{
public:
using CStdSwappable<CStdFramebuffer>::CStdSwappable;
public:
void Bind() const;
void Unbind() const;
};
class CStdSwappableTexture3D : public CStdSwappable<CStdTexture3D>
{
public:
using CStdSwappable<CStdTexture3D>::CStdSwappable;
public:
void Bind(GLenum offset) const;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment