280 lines
9.8 KiB
C
280 lines
9.8 KiB
C
|
//
|
||
|
// Created by brett on 6/11/23.
|
||
|
//
|
||
|
|
||
|
#ifndef PARKSNREC_OPENGL_H
|
||
|
#define PARKSNREC_OPENGL_H
|
||
|
|
||
|
#include "glad/gl.h"
|
||
|
#include <vector>
|
||
|
#include "blt/math/math.h"
|
||
|
#include "blt/std/string.h"
|
||
|
#include <string>
|
||
|
#include <unordered_map>
|
||
|
#include "stb/stb_image.h"
|
||
|
|
||
|
namespace parks {
|
||
|
|
||
|
class GLTexture2D {
|
||
|
private:
|
||
|
GLuint textureID = 0;
|
||
|
struct {
|
||
|
int width = 0, height = 0, channels = 4;
|
||
|
} textureInfo;
|
||
|
public:
|
||
|
GLTexture2D() {
|
||
|
glGenTextures(1, &textureID);
|
||
|
}
|
||
|
|
||
|
void bind() const {
|
||
|
glBindTexture(GL_TEXTURE_2D, textureID);
|
||
|
}
|
||
|
|
||
|
void allocate(GLenum type, int width, int height, int channels = 4) {
|
||
|
auto storage_type = channels == 4 ? GL_RGBA : GL_RGB;
|
||
|
bind();
|
||
|
glTexImage2D(GL_TEXTURE_2D, 0, storage_type, width, height, 0, storage_type, type,
|
||
|
nullptr);
|
||
|
textureInfo.width = width;
|
||
|
textureInfo.height = height;
|
||
|
textureInfo.channels = channels;
|
||
|
}
|
||
|
|
||
|
void upload(void* data, GLenum type, int width, int height, int channels = 4) {
|
||
|
auto storage_type = channels == 4 ? GL_RGBA : GL_RGB;
|
||
|
bind();
|
||
|
if (textureInfo.width != width || textureInfo.height != height || textureInfo.channels != channels)
|
||
|
allocate(type, width, height, channels);
|
||
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, storage_type, type, data);
|
||
|
textureInfo.width = width;
|
||
|
textureInfo.height = height;
|
||
|
textureInfo.channels = channels;
|
||
|
}
|
||
|
|
||
|
~GLTexture2D() {
|
||
|
glDeleteTextures(1, &textureID);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
struct VBOData {
|
||
|
GLenum target;
|
||
|
void* data;
|
||
|
GLuint size;
|
||
|
GLenum usage = GL_STATIC_DRAW;
|
||
|
|
||
|
VBOData(GLenum target, void* data, GLuint size);
|
||
|
|
||
|
VBOData(GLenum target, void* data, GLuint size, GLenum usage);
|
||
|
};
|
||
|
|
||
|
struct VBOAttributes {
|
||
|
GLuint loc;
|
||
|
GLint size;
|
||
|
GLenum type;
|
||
|
GLsizei stride;
|
||
|
GLint offset = 0;
|
||
|
|
||
|
VBOAttributes(GLuint loc, GLint size, GLenum type, GLsizei stride, GLint offset);
|
||
|
|
||
|
VBOAttributes(GLuint loc, GLint size, GLenum type, GLsizei stride);
|
||
|
|
||
|
VBOAttributes(GLuint loc, GLint size, GLenum type);
|
||
|
};
|
||
|
|
||
|
class VAOStorageObject {
|
||
|
private:
|
||
|
struct VAO {
|
||
|
GLuint vaoID = 0;
|
||
|
};
|
||
|
struct VBO {
|
||
|
GLuint vboID;
|
||
|
GLuint bindType;
|
||
|
};
|
||
|
|
||
|
VAO vao;
|
||
|
std::vector<VBO> associatedVBOs;
|
||
|
VBO ebo;
|
||
|
public:
|
||
|
VAOStorageObject() {
|
||
|
glGenVertexArrays(1, &vao.vaoID);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Binds only the VAO and none of the VBOs
|
||
|
*/
|
||
|
inline void bind() const {
|
||
|
glBindVertexArray(vao.vaoID);
|
||
|
}
|
||
|
|
||
|
inline void bindEBO() const {
|
||
|
glBindBuffer(ebo.bindType, ebo.vboID);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Binds both the VAO and all the associated VBOs
|
||
|
*/
|
||
|
inline void bindAll() const {
|
||
|
bind();
|
||
|
for (const VBO& v : associatedVBOs)
|
||
|
glBindBuffer(v.bindType, v.vboID);
|
||
|
}
|
||
|
|
||
|
void createVBO(VBOData data) {
|
||
|
VBO vbo{};
|
||
|
vbo.bindType = data.target;
|
||
|
glGenBuffers(1, &vbo.vboID);
|
||
|
glBindBuffer(data.target, vbo.vboID);
|
||
|
glBufferData(data.target, data.size, data.data, data.usage);
|
||
|
associatedVBOs.push_back(vbo);
|
||
|
if (vbo.bindType == GL_ELEMENT_ARRAY_BUFFER)
|
||
|
ebo = vbo;
|
||
|
}
|
||
|
|
||
|
void createVBO(VBOData data, VBOAttributes attribs) {
|
||
|
createVBO(data);
|
||
|
glVertexAttribPointer(
|
||
|
attribs.loc, attribs.size, attribs.type, GL_FALSE, attribs.stride,
|
||
|
(GLvoid*) (size_t) attribs.offset
|
||
|
);
|
||
|
glEnableVertexAttribArray(attribs.loc);
|
||
|
}
|
||
|
|
||
|
void createVBO(VBOData data, const std::vector<VBOAttributes>& attribs){
|
||
|
createVBO(data);
|
||
|
for (auto attrib : attribs) {
|
||
|
glVertexAttribPointer(
|
||
|
attrib.loc, attrib.size, attrib.type, GL_FALSE, attrib.stride,
|
||
|
(GLvoid*) (size_t) attrib.offset
|
||
|
);
|
||
|
glEnableVertexAttribArray(attrib.loc);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
~VAOStorageObject() {
|
||
|
glDeleteVertexArrays(1, &vao.vaoID);
|
||
|
for (const auto& v : associatedVBOs)
|
||
|
glDeleteBuffers(1, &v.vboID);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
class ShaderBase {
|
||
|
protected:
|
||
|
struct IntDefaultedToMinusOne {
|
||
|
GLint i = -1;
|
||
|
};
|
||
|
std::unordered_map<std::string, IntDefaultedToMinusOne> uniformVars;
|
||
|
GLuint programID = 0;
|
||
|
|
||
|
inline GLint getUniformLocation(const std::string& name) {
|
||
|
if (uniformVars[name].i != -1)
|
||
|
return uniformVars[name].i;
|
||
|
int loc = glGetUniformLocation(programID, name.c_str());
|
||
|
uniformVars[name].i = loc;
|
||
|
return loc;
|
||
|
}
|
||
|
|
||
|
public:
|
||
|
inline void bind() const {
|
||
|
glUseProgram(programID);
|
||
|
}
|
||
|
|
||
|
inline void setBool(const std::string& name, bool value) {
|
||
|
glUniform1i(getUniformLocation(name), (int) value);
|
||
|
}
|
||
|
|
||
|
inline void setInt(const std::string& name, int value) {
|
||
|
glUniform1i(getUniformLocation(name), value);
|
||
|
}
|
||
|
|
||
|
inline void setFloat(const std::string& name, float value) {
|
||
|
glUniform1f(getUniformLocation(name), value);
|
||
|
}
|
||
|
|
||
|
inline void setMatrix(const std::string& name, blt::mat4x4& matrix) {
|
||
|
glUniformMatrix4fv(getUniformLocation(name), 1, GL_FALSE, matrix.ptr());
|
||
|
}
|
||
|
|
||
|
inline void setVec3(const std::string& name, const blt::vec3& vec) {
|
||
|
glUniform3f(getUniformLocation(name), vec.x(), vec.y(), vec.z());
|
||
|
}
|
||
|
|
||
|
inline void setVec4(const std::string& name, const blt::vec4& vec) {
|
||
|
glUniform4f(getUniformLocation(name), vec.x(), vec.y(), vec.z(), vec.w());
|
||
|
}
|
||
|
|
||
|
inline void setVec2(const std::string& name, float x, float y) {
|
||
|
glUniform2f(getUniformLocation(name), x, y);
|
||
|
}
|
||
|
|
||
|
inline void setVec3(const std::string& name, float x, float y, float z) {
|
||
|
glUniform3f(getUniformLocation(name), x, y, z);
|
||
|
}
|
||
|
|
||
|
inline void setVec4(const std::string& name, float x, float y, float z, float w) {
|
||
|
glUniform4f(getUniformLocation(name), x, y, z, w);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* This part was made for this assignment and will likely be used in future projects
|
||
|
*/
|
||
|
class ComputeShader : public ShaderBase {
|
||
|
private:
|
||
|
GLuint shaderID = 0;
|
||
|
public:
|
||
|
explicit ComputeShader(const std::string& shader_source, bool loadAsString = true);
|
||
|
|
||
|
inline void execute(int x, int y, int z) const {
|
||
|
bind();
|
||
|
glDispatchCompute(x, y, z);
|
||
|
}
|
||
|
|
||
|
~ComputeShader();
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Note: This is taken from my final project,
|
||
|
* https://github.com/Tri11Paragon/COSC-3P98-Final-Project/blob/main/include/render/gl.h
|
||
|
*/
|
||
|
|
||
|
class Shader : public ShaderBase {
|
||
|
private:
|
||
|
GLuint vertexShaderID = 0;
|
||
|
GLuint fragmentShaderID = 0;
|
||
|
// while these will remain unused. (Webgl2 apparently doesn't support them despite being based on GL4.3? that's a TODO!)
|
||
|
GLuint geometryShaderID = 0;
|
||
|
// this would be very useful however it is highly unlikely webgl will support it
|
||
|
// im leaving some of this stuff in here because I might expand the native application to use some of it.
|
||
|
// im trying to keep the web and native versions the same though
|
||
|
GLuint tessellationShaderID = 0;
|
||
|
|
||
|
static unsigned int createShader(const std::string& source, int type);
|
||
|
|
||
|
public:
|
||
|
/**
|
||
|
* Creates a shader
|
||
|
* @param vertex vertex shader source or file
|
||
|
* @param fragment fragment shader source or file
|
||
|
* @param geometry geometry shader source or file (optional)
|
||
|
* @param load_as_string load the shader as a string (true) or use the string to load the shader as a file (false)
|
||
|
*/
|
||
|
Shader(
|
||
|
const std::string& vertex, const std::string& fragment,
|
||
|
const std::string& geometry = "",
|
||
|
bool load_as_string = true
|
||
|
);
|
||
|
|
||
|
Shader(Shader&& move) noexcept;
|
||
|
|
||
|
// used to set the location of VAOs to the in variables in opengl shaders.
|
||
|
void bindAttribute(int attribute, const std::string& name) const;
|
||
|
|
||
|
// used to set location of shared UBOs like the perspective and view matrix
|
||
|
void setUniformBlockLocation(const std::string& name, int location) const;
|
||
|
|
||
|
~Shader();
|
||
|
};
|
||
|
}
|
||
|
|
||
|
#endif //PARKSNREC_OPENGL_H
|