236 lines
5.1 KiB
C++

/*
* Copyright 2016 - 2024 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include <ox/std/defines.hpp>
#include <glad/glad.h>
#include <ox/std/bounds.hpp>
#include <ox/std/cstringview.hpp>
#include <ox/std/error.hpp>
#include <ox/std/size.hpp>
#include <ox/std/string.hpp>
#include <ox/std/vec.hpp>
#include <ox/std/vector.hpp>
namespace glutils {
struct Empty {
virtual ~Empty() noexcept = default;
};
struct TextureBase {
GLsizei width = 0;
GLsizei height = 0;
constexpr TextureBase() noexcept = default;
constexpr TextureBase(TextureBase &&tb) noexcept {
width = tb.width;
height = tb.height;
tb.width = 0;
tb.height = 0;
}
constexpr TextureBase &operator=(TextureBase &&tb) noexcept {
width = tb.width;
height = tb.height;
tb.width = 0;
tb.height = 0;
return *this;
}
virtual ~TextureBase() noexcept = default;
};
template<auto del, typename Base = Empty>
struct GLObject: public Base {
GLuint id = 0;
constexpr GLObject() noexcept = default;
explicit constexpr GLObject(GLuint id) noexcept {
this->id = id;
}
constexpr GLObject(GLObject &&o) noexcept: Base(std::move(o)) {
id = o.id;
o.id = 0;
}
~GLObject() noexcept override {
del(id);
}
GLObject &operator=(GLObject &&o) noexcept {
if (this != &o) {
del(id);
Base::operator=(std::move(o));
id = o.id;
o.id = 0;
}
return *this;
}
constexpr GLuint release() noexcept {
auto out = id;
id = 0;
return out;
}
constexpr operator GLuint&() noexcept {
return id;
}
constexpr operator const GLuint&() const noexcept {
return id;
}
};
void deleteBuffer(GLuint b) noexcept;
void deleteFrameBuffer(GLuint b) noexcept;
void deleteRenderBuffer(GLuint b) noexcept;
void deleteTexture(GLuint t) noexcept;
void deleteVertexArray(GLuint v) noexcept;
void deleteProgram(GLuint p) noexcept;
void deleteShader(GLuint s) noexcept;
extern template struct GLObject<deleteBuffer>;
extern template struct GLObject<deleteFrameBuffer>;
extern template struct GLObject<deleteRenderBuffer>;
extern template struct GLObject<deleteTexture, TextureBase>;
extern template struct GLObject<deleteVertexArray>;
extern template struct GLObject<deleteProgram>;
extern template struct GLObject<deleteShader>;
using GLBuffer = GLObject<deleteBuffer>;
using GLFrameBuffer = GLObject<deleteFrameBuffer>;
using GLRenderBuffer = GLObject<deleteRenderBuffer>;
using GLShader = GLObject<deleteShader>;
using GLProgram = GLObject<deleteProgram>;
using GLTexture = GLObject<deleteTexture, TextureBase>;
using GLVertexArray = GLObject<deleteVertexArray>;
/**
* FrameBuffer holds everything needed for a usable frame buffer to exist.
* It differs from GLFrameBuffer in that GLFrameBuffer only manages the FBO
* and not its dependencies.
*/
struct FrameBuffer {
int width = 0;
int height = 0;
GLFrameBuffer fbo;
GLTexture color;
GLRenderBuffer depth;
constexpr operator GLuint&() noexcept {
return fbo.id;
}
constexpr operator const GLuint&() const noexcept {
return fbo.id;
}
[[nodiscard]]
constexpr ox::Vec2 sizef() const noexcept {
return {
static_cast<float>(width),
static_cast<float>(height),
};
}
[[nodiscard]]
constexpr ox::Size size() const noexcept {
return {
width,
height,
};
}
};
class FrameBufferBind {
private:
static const FrameBuffer *s_activeFb;
const FrameBuffer *m_restoreFb = nullptr;
public:
explicit FrameBufferBind(const FrameBuffer &fb) noexcept;
~FrameBufferBind() noexcept;
};
void bind(const FrameBuffer &fb) noexcept;
struct ShaderVarSet {
GLsizei len{};
ox::String name;
};
struct ProgramSource {
ox::Vector<glutils::ShaderVarSet> const shaderParams;
GLsizei const rowLen = [this] {
GLsizei len{};
for (auto const&v : shaderParams) {
len += v.len;
}
return len;
}();
GLsizei const vboLen = rowLen * 4;
ox::String const vertShader{};
ox::String const fragShader{};
ox::String const geomShader{};
};
ox::Result<GLProgram> buildShaderProgram(ProgramSource const&src) noexcept;
ox::Result<GLProgram> buildShaderProgram(
ox::CStringView const&vert,
ox::CStringView const&frag,
ox::CStringView const&geo = "") noexcept;
void setupShaderParams(
GLProgram const&shader,
ox::Vector<ShaderVarSet> const&vars,
GLsizei vertexRowLen) noexcept;
void setupShaderParams(GLProgram const&shader, ox::Vector<ShaderVarSet> const&vars) noexcept;
glutils::GLVertexArray generateVertexArrayObject() noexcept;
glutils::GLBuffer generateBuffer() noexcept;
[[nodiscard]]
FrameBuffer generateFrameBuffer(int width, int height) noexcept;
void resizeFrameBuffer(FrameBuffer &fb, int width, int height) noexcept;
/**
* Resizes a FrameBuffer, and creates if it does not already exist.
*/
void resizeInitFrameBuffer(FrameBuffer &fb, int width, int height) noexcept;
void resizeInitFrameBuffer(FrameBuffer &fb, ox::Size const&sz) noexcept;
struct BufferSet {
glutils::GLVertexArray vao;
glutils::GLBuffer vbo;
glutils::GLBuffer ebo;
glutils::GLTexture tex;
ox::Vector<float> vertices;
ox::Vector<GLuint> elements;
};
void sendVbo(BufferSet const&bs) noexcept;
void sendEbo(BufferSet const&bs) noexcept;
void clearScreen() noexcept;
}