|
@@ -1,38 +1,113 @@
|
|
|
#include <GL/glew.h>
|
|
|
#include <iostream>
|
|
|
+#include <type_traits>
|
|
|
|
|
|
+#include "utils/Array.h"
|
|
|
#include "wrapper/GL.h"
|
|
|
|
|
|
-bool GL::checkAndPrintError(const char* message) {
|
|
|
+static_assert(std::is_same<GL::Shader, GLuint>::value,
|
|
|
+ "shader has invalid type");
|
|
|
+static_assert(std::is_same<GL::Program, GLuint>::value, "p has invalid type");
|
|
|
+static_assert(std::is_same<char, GLchar>::value, "char has invalid type");
|
|
|
+static_assert(std::is_same<int, GLint>::value, "int has invalid type");
|
|
|
+static_assert(std::is_same<float, GLfloat>::value, "float has invalid type");
|
|
|
+static_assert(std::is_same<GL::ShaderType, GLenum>::value,
|
|
|
+ "shader type has invalid type");
|
|
|
+static_assert(std::is_same<GL::Texture, GLuint>::value,
|
|
|
+ "texture has invalid type");
|
|
|
+static_assert(std::is_same<GL::Framebuffer, GLuint>::value,
|
|
|
+ "framebuffer has invalid type");
|
|
|
+static_assert(std::is_same<GL::ColorAttachment, GLenum>::value,
|
|
|
+ "color attachment has invalid type");
|
|
|
+static_assert(std::is_same<GL::VertexArray, GLuint>::value,
|
|
|
+ "vertex array has invalid type");
|
|
|
+static_assert(std::is_same<GL::Buffer, GLuint>::value,
|
|
|
+ "buffer has invalid type");
|
|
|
+
|
|
|
+GL::ShaderType GL::VERTEX_SHADER = GL_VERTEX_SHADER;
|
|
|
+GL::ShaderType GL::FRAGMENT_SHADER = GL_FRAGMENT_SHADER;
|
|
|
+GL::ShaderType GL::GEOMETRY_SHADER = GL_GEOMETRY_SHADER;
|
|
|
+
|
|
|
+GL::Attribute::Attribute(int count, int size, int type, bool normalized)
|
|
|
+ : count(count), size(size), type(type), normalized(normalized) {
|
|
|
+}
|
|
|
+
|
|
|
+GL::Attribute GL::Attribute::newFloat(int count) {
|
|
|
+ return GL::Attribute(count, sizeof(float), GL_FLOAT, false);
|
|
|
+}
|
|
|
+
|
|
|
+GL::Attribute GL::Attribute::newColor(int count) {
|
|
|
+ return GL::Attribute(count, sizeof(float), GL_FLOAT, false);
|
|
|
+}
|
|
|
+
|
|
|
+GL::Attribute GL::Attribute::newDummy() {
|
|
|
+ return GL::Attribute(0, 0, -1, false);
|
|
|
+}
|
|
|
+
|
|
|
+bool GL::Attribute::isDummy() const {
|
|
|
+ return type == -1;
|
|
|
+}
|
|
|
+
|
|
|
+int GL::Attribute::getSize() const {
|
|
|
+ return count * size;
|
|
|
+}
|
|
|
+
|
|
|
+GL::TextureFormat::TextureFormat(int internalformat, int format, int type)
|
|
|
+ : internalformat(internalformat), format(format), type(type) {
|
|
|
+}
|
|
|
+
|
|
|
+GL::TextureFormat GL::TextureFormat::color8(int channels) {
|
|
|
+ switch(channels) {
|
|
|
+ case 1: return TextureFormat(GL_RED, GL_RED, GL_UNSIGNED_BYTE);
|
|
|
+ case 2: return TextureFormat(GL_RG, GL_RG, GL_UNSIGNED_BYTE);
|
|
|
+ case 3: return TextureFormat(GL_RGB, GL_RGB, GL_UNSIGNED_BYTE);
|
|
|
+ case 4: return TextureFormat(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
|
|
|
+ }
|
|
|
+ std::cout << channels << " is not a valid amount of channels\n";
|
|
|
+ return unknown();
|
|
|
+}
|
|
|
+
|
|
|
+GL::TextureFormat GL::TextureFormat::float16(int channels) {
|
|
|
+ switch(channels) {
|
|
|
+ case 1: return TextureFormat(GL_R16F, GL_RED, GL_FLOAT);
|
|
|
+ case 2: return TextureFormat(GL_RG16F, GL_RG, GL_FLOAT);
|
|
|
+ case 3: return TextureFormat(GL_RGB16F, GL_RGB, GL_FLOAT);
|
|
|
+ case 4: return TextureFormat(GL_RGBA16F, GL_RGBA, GL_FLOAT);
|
|
|
+ }
|
|
|
+ std::cout << channels << " is not a valid amount of channels\n";
|
|
|
+ return unknown();
|
|
|
+}
|
|
|
+
|
|
|
+GL::TextureFormat GL::TextureFormat::float32(int channels) {
|
|
|
+ switch(channels) {
|
|
|
+ case 1: return TextureFormat(GL_R32F, GL_RED, GL_FLOAT);
|
|
|
+ case 2: return TextureFormat(GL_RG32F, GL_RG, GL_FLOAT);
|
|
|
+ case 3: return TextureFormat(GL_RGB32F, GL_RGB, GL_FLOAT);
|
|
|
+ case 4: return TextureFormat(GL_RGBA32F, GL_RGBA, GL_FLOAT);
|
|
|
+ }
|
|
|
+ std::cout << channels << " is not a valid amount of channels\n";
|
|
|
+ return unknown();
|
|
|
+}
|
|
|
+
|
|
|
+GL::TextureFormat GL::TextureFormat::depth16() {
|
|
|
+ return TextureFormat(GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_FLOAT);
|
|
|
+}
|
|
|
+
|
|
|
+GL::TextureFormat GL::TextureFormat::depth32() {
|
|
|
+ return TextureFormat(GL_DEPTH_COMPONENT32, GL_DEPTH_COMPONENT, GL_FLOAT);
|
|
|
+}
|
|
|
+
|
|
|
+GL::TextureFormat GL::TextureFormat::unknown() {
|
|
|
+ return TextureFormat(-1, -1, -1);
|
|
|
+}
|
|
|
+
|
|
|
+bool GL::printError(const char* message) {
|
|
|
GLenum error = glGetError();
|
|
|
- switch(error) {
|
|
|
- case GL_NO_ERROR: return false;
|
|
|
- case GL_INVALID_ENUM:
|
|
|
- std::cout << message << ": an unacceptable value is specified for an enumerated argument\n";
|
|
|
- break;
|
|
|
- case GL_INVALID_VALUE: std::cout << message << ": a numeric argument is out of range\n"; break;
|
|
|
- case GL_INVALID_OPERATION:
|
|
|
- std::cout << message << ": the specified operation is not allowed in the current state\n";
|
|
|
- break;
|
|
|
- case GL_INVALID_FRAMEBUFFER_OPERATION:
|
|
|
- std::cout << message << ": the framebuffer object is not complete\n";
|
|
|
- break;
|
|
|
- case GL_OUT_OF_MEMORY:
|
|
|
- std::cout << message << ": there is not enough memory left to execute the command\n";
|
|
|
- break;
|
|
|
- case GL_STACK_UNDERFLOW:
|
|
|
- std::cout << message
|
|
|
- << ": an attempt has been made to perform an operation that would cause an internal stack to "
|
|
|
- "underflow\n";
|
|
|
- break;
|
|
|
- case GL_STACK_OVERFLOW:
|
|
|
- std::cout << message
|
|
|
- << ": an attempt has been made to perform an operation that would cause an internal stack to "
|
|
|
- "overflow\n";
|
|
|
- break;
|
|
|
- default: std::cout << message << ": unknown OpenGL error '" << error << "'\n";
|
|
|
+ if(error != GL_NO_ERROR) {
|
|
|
+ std::cout << message << ": " << gluErrorString(error) << '\n';
|
|
|
+ return true;
|
|
|
}
|
|
|
- return true;
|
|
|
+ return false;
|
|
|
}
|
|
|
|
|
|
void GL::enableDepthTesting() {
|
|
@@ -47,7 +122,7 @@ void GL::bindMainFramebuffer() {
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
|
}
|
|
|
|
|
|
-void GL::clearFramebuffer() {
|
|
|
+void GL::clear() {
|
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
}
|
|
|
|
|
@@ -63,4 +138,248 @@ void GL::disableBlending() {
|
|
|
|
|
|
void GL::setViewport(int width, int height) {
|
|
|
glViewport(0, 0, width, height);
|
|
|
+}
|
|
|
+
|
|
|
+void GL::vertexAttribPointer(int index, const Attribute& a, int stride,
|
|
|
+ int offset) {
|
|
|
+ glVertexAttribPointer(index, a.count, a.type, a.normalized, stride,
|
|
|
+ static_cast<char*>(0) + offset);
|
|
|
+ glEnableVertexAttribArray(index);
|
|
|
+}
|
|
|
+
|
|
|
+GL::Program GL::createProgram() {
|
|
|
+ return glCreateProgram();
|
|
|
+}
|
|
|
+
|
|
|
+void GL::attachShader(Program p, Shader s) {
|
|
|
+ glAttachShader(p, s);
|
|
|
+}
|
|
|
+
|
|
|
+void GL::linkProgram(Program p) {
|
|
|
+ glLinkProgram(p);
|
|
|
+}
|
|
|
+
|
|
|
+bool GL::logLinkerError(Program p) {
|
|
|
+ GLint linked;
|
|
|
+ glGetProgramiv(p, GL_LINK_STATUS, &linked);
|
|
|
+ if(!linked) {
|
|
|
+ Array<char, 1024> log;
|
|
|
+ glGetProgramInfoLog(p, log.getLength(), nullptr, log.begin());
|
|
|
+ std::cout << "linker log: " << log.begin() << "\n";
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+void GL::deleteShader(Shader s) {
|
|
|
+ glDeleteShader(s);
|
|
|
+}
|
|
|
+
|
|
|
+void GL::deleteProgram(Program p) {
|
|
|
+ glDeleteProgram(p);
|
|
|
+}
|
|
|
+
|
|
|
+GL::Shader GL::createShader(ShaderType type) {
|
|
|
+ return glCreateShader(type);
|
|
|
+}
|
|
|
+
|
|
|
+void GL::compileShader(Shader s, const char* code) {
|
|
|
+ glShaderSource(s, 1, &code, nullptr);
|
|
|
+ glCompileShader(s);
|
|
|
+}
|
|
|
+
|
|
|
+bool GL::logCompileError(Shader s) {
|
|
|
+ GLint compiled;
|
|
|
+ glGetShaderiv(s, GL_COMPILE_STATUS, &compiled);
|
|
|
+ if(!compiled) {
|
|
|
+ Array<char, 1024> log;
|
|
|
+ glGetShaderInfoLog(s, log.getLength(), nullptr, log.begin());
|
|
|
+ std::cout << "compiler log: " << log.begin() << "\n";
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+void GL::useProgram(Program p) {
|
|
|
+ glUseProgram(p);
|
|
|
+}
|
|
|
+
|
|
|
+void GL::setMatrix(Program p, const char* name, const float* data) {
|
|
|
+ glUniformMatrix4fv(glGetUniformLocation(p, name), 1, GL_TRUE, data);
|
|
|
+}
|
|
|
+
|
|
|
+void GL::setInt(Program p, const char* name, int data) {
|
|
|
+ glUniform1i(glGetUniformLocation(p, name), data);
|
|
|
+}
|
|
|
+
|
|
|
+void GL::setFloat(Program p, const char* name, float data) {
|
|
|
+ glUniform1f(glGetUniformLocation(p, name), data);
|
|
|
+}
|
|
|
+
|
|
|
+void GL::set2Float(Program p, const char* name, const float* data) {
|
|
|
+ glUniform2fv(glGetUniformLocation(p, name), 1, data);
|
|
|
+}
|
|
|
+
|
|
|
+void GL::set3Float(Program p, const char* name, const float* data) {
|
|
|
+ glUniform3fv(glGetUniformLocation(p, name), 1, data);
|
|
|
+}
|
|
|
+
|
|
|
+void GL::set4Float(Program p, const char* name, const float* data) {
|
|
|
+ glUniform4fv(glGetUniformLocation(p, name), 1, data);
|
|
|
+}
|
|
|
+
|
|
|
+void GL::texImage2D(const TextureFormat& tf, int width, int height,
|
|
|
+ const void* data, int level) {
|
|
|
+ glTexImage2D(GL_TEXTURE_2D, level, tf.internalformat, width, height, 0,
|
|
|
+ tf.format, tf.type, data);
|
|
|
+}
|
|
|
+
|
|
|
+GL::Texture GL::genTexture() {
|
|
|
+ Texture t;
|
|
|
+ glGenTextures(1, &t);
|
|
|
+ return t;
|
|
|
+}
|
|
|
+
|
|
|
+void GL::deleteTexture(Texture t) {
|
|
|
+ glDeleteTextures(1, &t);
|
|
|
+}
|
|
|
+
|
|
|
+void GL::setNearFilter2D() {
|
|
|
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
|
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
|
+}
|
|
|
+
|
|
|
+void GL::setMipMapNearFilter2D() {
|
|
|
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
|
|
|
+ GL_NEAREST_MIPMAP_LINEAR);
|
|
|
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
|
+}
|
|
|
+
|
|
|
+void GL::setLinearFilter2D() {
|
|
|
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
|
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
+}
|
|
|
+
|
|
|
+void GL::setMipMapLinearFilter2D() {
|
|
|
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
|
|
|
+ GL_LINEAR_MIPMAP_LINEAR);
|
|
|
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
+}
|
|
|
+
|
|
|
+void GL::setClampWrap2D() {
|
|
|
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
|
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
|
+}
|
|
|
+
|
|
|
+void GL::setRepeatWrap2D() {
|
|
|
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
|
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
|
+}
|
|
|
+
|
|
|
+void GL::bindTexture2D(Texture t) {
|
|
|
+ glBindTexture(GL_TEXTURE_2D, t);
|
|
|
+}
|
|
|
+
|
|
|
+void GL::activeTexture(int index) {
|
|
|
+ glActiveTexture(GL_TEXTURE0 + index);
|
|
|
+}
|
|
|
+
|
|
|
+void GL::generateMipmap2D(int maxLevels) {
|
|
|
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
|
|
|
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, maxLevels);
|
|
|
+ glGenerateMipmap(GL_TEXTURE_2D);
|
|
|
+}
|
|
|
+
|
|
|
+void GL::deleteFramebuffers(Framebuffer fb) {
|
|
|
+ glDeleteFramebuffers(1, &fb);
|
|
|
+}
|
|
|
+
|
|
|
+GL::Framebuffer GL::genFramebuffer() {
|
|
|
+ Framebuffer fb;
|
|
|
+ glGenFramebuffers(1, &fb);
|
|
|
+ return fb;
|
|
|
+}
|
|
|
+
|
|
|
+void GL::bindFramebuffer(Framebuffer fb) {
|
|
|
+ glBindFramebuffer(GL_FRAMEBUFFER, fb);
|
|
|
+}
|
|
|
+
|
|
|
+void GL::framebufferDepthTexture2D(Texture t) {
|
|
|
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
|
|
|
+ t, 0);
|
|
|
+}
|
|
|
+
|
|
|
+GL::ColorAttachment GL::framebufferColorTexture2D(Texture t, int index) {
|
|
|
+ GLenum c = GL_COLOR_ATTACHMENT0 + index;
|
|
|
+ glFramebufferTexture2D(GL_FRAMEBUFFER, c, GL_TEXTURE_2D, t, 0);
|
|
|
+ return c;
|
|
|
+}
|
|
|
+
|
|
|
+void GL::drawBuffers(int length, ColorAttachment* c) {
|
|
|
+ glDrawBuffers(length, c);
|
|
|
+}
|
|
|
+
|
|
|
+bool GL::printFramebufferError() {
|
|
|
+ GLenum error = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
|
|
+ if(error == GL_FRAMEBUFFER_COMPLETE) {
|
|
|
+ std::cout << "framebuffer error: " << error << '\n';
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+GL::VertexArray GL::genVertexArray() {
|
|
|
+ VertexArray va;
|
|
|
+ glGenVertexArrays(1, &va);
|
|
|
+ return va;
|
|
|
+}
|
|
|
+
|
|
|
+GL::Buffer GL::genBuffer() {
|
|
|
+ Buffer b;
|
|
|
+ glGenBuffers(1, &b);
|
|
|
+ return b;
|
|
|
+}
|
|
|
+
|
|
|
+void GL::deleteBuffer(Buffer b) {
|
|
|
+ glDeleteBuffers(1, &b);
|
|
|
+}
|
|
|
+
|
|
|
+void GL::deleteVertexArray(VertexArray va) {
|
|
|
+ glDeleteVertexArrays(1, &va);
|
|
|
+}
|
|
|
+
|
|
|
+void GL::bindVertexArray(VertexArray va) {
|
|
|
+ glBindVertexArray(va);
|
|
|
+}
|
|
|
+
|
|
|
+void GL::bindBuffer(Buffer b) {
|
|
|
+ glBindBuffer(GL_ARRAY_BUFFER, b);
|
|
|
+}
|
|
|
+
|
|
|
+void GL::bufferDataStatic(int size, const void* data) {
|
|
|
+ glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
|
|
|
+}
|
|
|
+
|
|
|
+void GL::bufferDataStream(int size, const void* data) {
|
|
|
+ glBufferData(GL_ARRAY_BUFFER, size, data, GL_STREAM_DRAW);
|
|
|
+}
|
|
|
+
|
|
|
+void GL::bufferDataDynamic(int size, const void* data) {
|
|
|
+ glBufferData(GL_ARRAY_BUFFER, size, data, GL_DYNAMIC_DRAW);
|
|
|
+}
|
|
|
+
|
|
|
+void GL::bufferSubData(int offset, int size, const void* data) {
|
|
|
+ glBufferSubData(GL_ARRAY_BUFFER, offset, size, data);
|
|
|
+}
|
|
|
+
|
|
|
+void GL::drawTriangles(int offset, int vertices) {
|
|
|
+ glDrawArrays(GL_TRIANGLES, offset, vertices);
|
|
|
+}
|
|
|
+
|
|
|
+void GL::drawTriangleStrip(int offset, int vertices) {
|
|
|
+ glDrawArrays(GL_TRIANGLE_STRIP, offset, vertices);
|
|
|
+}
|
|
|
+
|
|
|
+void GL::drawPoints(int offset, int vertices) {
|
|
|
+ glDrawArrays(GL_POINTS, offset, vertices);
|
|
|
}
|