123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553 |
- /*!
- * \file src/system/Shader.cpp
- * \brief OpenGL Shader Implementation
- *
- * \author xythobuz
- */
-
- #include <sstream>
-
- #include "global.h"
- #include "Log.h"
- #include "Render.h"
- #include "system/Window.h"
- #include "system/Shader.h"
-
- #include <glbinding/gl/gl.h>
-
- ShaderBuffer::~ShaderBuffer() {
- if (created)
- gl::glDeleteBuffers(1, &buffer);
- }
-
- void ShaderBuffer::bufferData(int elem, int size, void* data) {
- if (!created) {
- gl::glGenBuffers(1, &buffer);
- created = true;
- }
-
- boundSize = elem;
- gl::glBindBuffer(gl::GL_ARRAY_BUFFER, buffer);
- gl::glBufferData(gl::GL_ARRAY_BUFFER, elem * size, data, gl::GL_DYNAMIC_DRAW);
- }
-
- void ShaderBuffer::bindBuffer() {
- if (!created) {
- gl::glGenBuffers(1, &buffer);
- created = true;
- }
-
- gl::glBindBuffer(gl::GL_ELEMENT_ARRAY_BUFFER, buffer);
- }
-
- void ShaderBuffer::bindBuffer(int location, int size) {
- if (!created) {
- gl::glGenBuffers(1, &buffer);
- created = true;
- }
-
- gl::glEnableVertexAttribArray(location);
- gl::glBindBuffer(gl::GL_ARRAY_BUFFER, buffer);
- gl::glVertexAttribPointer(location, size, gl::GL_FLOAT, gl::GL_FALSE, 0, nullptr);
- }
-
- void ShaderBuffer::unbind(int location) {
- orAssert(created == true);
- gl::glDisableVertexAttribArray(location);
- }
-
- // ----------------------------------------------------------------------------
-
- ShaderTexture::ShaderTexture(int w, int h) : width(w), height(h) {
- gl::glGenFramebuffers(1, &framebuffer);
- bind();
-
- texture = TextureManager::loadBufferSlot(nullptr, width, height, ColorMode::RGBA,
- 32, TextureStorage::SYSTEM, -1, false);
-
- gl::glGenRenderbuffers(1, &depth);
- gl::glBindRenderbuffer(gl::GL_RENDERBUFFER, depth);
- gl::glRenderbufferStorage(gl::GL_RENDERBUFFER, gl::GL_DEPTH_COMPONENT, width, height);
- gl::glFramebufferRenderbuffer(gl::GL_FRAMEBUFFER, gl::GL_DEPTH_ATTACHMENT, gl::GL_RENDERBUFFER,
- depth);
-
- gl::glFramebufferTexture(gl::GL_FRAMEBUFFER, gl::GL_COLOR_ATTACHMENT0,
- TextureManager::getTextureID(texture, TextureStorage::SYSTEM), 0);
-
- gl::GLenum drawBuffer = gl::GL_COLOR_ATTACHMENT0;
- gl::glDrawBuffers(1, &drawBuffer);
-
- orAssert(gl::glCheckFramebufferStatus(gl::GL_FRAMEBUFFER) == gl::GL_FRAMEBUFFER_COMPLETE);
- }
-
- ShaderTexture::~ShaderTexture() {
- gl::glDeleteRenderbuffers(1, &depth);
- gl::glDeleteFramebuffers(1, &framebuffer);
-
- //! \fixme free texture slot
- }
-
- void ShaderTexture::clear() {
- bind();
- gl::glClear(gl::GL_COLOR_BUFFER_BIT | gl::GL_DEPTH_BUFFER_BIT);
- }
-
- void ShaderTexture::bind() {
- gl::glBindFramebuffer(gl::GL_FRAMEBUFFER, framebuffer);
- gl::glViewport(0, 0, width, height);
- }
-
- // ----------------------------------------------------------------------------
-
- Shader::~Shader() {
- if (programID >= 0)
- gl::glDeleteProgram(programID);
- }
-
- int Shader::getAttrib(const char* name) {
- orAssert(programID >= 0);
- orAssert(name != nullptr);
- orAssert(name[0] != '\0');
- return gl::glGetAttribLocation(programID, name);
- }
-
- int Shader::addUniform(const char* name) {
- orAssert(programID >= 0);
- int r = gl::glGetUniformLocation(programID, name);
- if (r < 0) {
- Log::get(LOG_ERROR) << "Can't find GLSL Uniform \"" << name << "\"!" << Log::endl;
- return -1;
- }
- uniforms.push_back(r);
- return uniforms.size() - 1;
- }
-
- unsigned int Shader::getUniform(int n) {
- orAssert(n >= 0);
- orAssert(n < uniforms.size());
- return uniforms.at(n);
- }
-
- void Shader::loadUniform(int uni, glm::vec2 vec) {
- gl::glUniform2f(getUniform(uni), vec.x, vec.y);
- }
-
- void Shader::loadUniform(int uni, glm::vec4 vec) {
- gl::glUniform4f(getUniform(uni), vec.r, vec.g, vec.b, vec.a);
- }
-
- void Shader::loadUniform(int uni, glm::mat4 mat) {
- gl::glUniformMatrix4fv(getUniform(uni), 1, gl::GL_FALSE, &mat[0][0]);
- }
-
- void Shader::loadUniform(int uni, int texture, TextureStorage store) {
- if ((Render::getMode() == RenderMode::Solid)
- && (store == TextureStorage::GAME)) {
- gl::glUniform1i(getUniform(uni), TextureManager::bindTexture(TEXTURE_SPLASH,
- TextureStorage::SYSTEM));
- } else {
- gl::glUniform1i(getUniform(uni), TextureManager::bindTexture(texture, store));
- }
- }
-
- void Shader::use() {
- orAssert(programID >= 0);
- static int lastID = -1;
- if (programID != lastID) {
- gl::glUseProgram(programID);
- lastID = programID;
- }
- }
-
- int Shader::compile(const char* vertex, const char* fragment) {
- orAssert(vertex != nullptr);
- orAssert(fragment != nullptr);
-
- gl::GLuint vertexID = gl::glCreateShader(gl::GL_VERTEX_SHADER);
- gl::GLuint fragmentID = gl::glCreateShader(gl::GL_FRAGMENT_SHADER);
-
- gl::GLint result = gl::GLint(gl::GL_FALSE);
- gl::GLint logLength = 0;
-
- // Compile vertex shader
- gl::glShaderSource(vertexID, 1, &vertex, nullptr);
- gl::glCompileShader(vertexID);
-
- // Check vertex shader
- gl::glGetShaderiv(vertexID, gl::GL_COMPILE_STATUS, &result);
- gl::glGetShaderiv(vertexID, gl::GL_INFO_LOG_LENGTH, &logLength);
- if ((logLength > 0) && (result != gl::GLint(gl::GL_TRUE))) {
- std::vector<char> message(logLength + 1);
- gl::glGetShaderInfoLog(vertexID, logLength, nullptr, &message[0]);
- Log::get(LOG_ERROR) << "Vertex Shader compilation error:" << Log::endl;
- Log::get(LOG_ERROR) << &message[0] << Log::endl;
- gl::glDeleteShader(vertexID);
- gl::glDeleteShader(fragmentID);
- return -1;
- }
-
- // Compile fragment shader
- gl::glShaderSource(fragmentID, 1, &fragment, nullptr);
- gl::glCompileShader(fragmentID);
-
- // Check fragment shader
- gl::glGetShaderiv(fragmentID, gl::GL_COMPILE_STATUS, &result);
- gl::glGetShaderiv(fragmentID, gl::GL_INFO_LOG_LENGTH, &logLength);
- if ((logLength > 0) && (result != gl::GLint(gl::GL_TRUE))) {
- std::vector<char> message(logLength + 1);
- gl::glGetShaderInfoLog(fragmentID, logLength, nullptr, &message[0]);
- Log::get(LOG_ERROR) << "Fragment Shader compilation error:" << Log::endl;
- Log::get(LOG_ERROR) << &message[0] << Log::endl;
- gl::glDeleteShader(vertexID);
- gl::glDeleteShader(fragmentID);
- return -2;
- }
-
- // Link both shaders
- programID = gl::glCreateProgram();
- gl::glAttachShader(programID, vertexID);
- gl::glAttachShader(programID, fragmentID);
- gl::glLinkProgram(programID);
-
- // Check resulting program
- gl::glGetProgramiv(programID, gl::GL_LINK_STATUS, &result);
- gl::glGetProgramiv(programID, gl::GL_INFO_LOG_LENGTH, &logLength);
- if ((logLength > 0) && (result != gl::GLint(gl::GL_TRUE))) {
- std::vector<char> message(logLength + 1);
- gl::glGetProgramInfoLog(programID, logLength, nullptr, &message[0]);
- Log::get(LOG_ERROR) << "Shader link error:" << Log::endl;
- Log::get(LOG_ERROR) << &message[0] << Log::endl;
- gl::glDeleteShader(vertexID);
- gl::glDeleteShader(fragmentID);
- gl::glDeleteProgram(programID);
- return -3;
- }
-
- gl::glDeleteShader(vertexID);
- gl::glDeleteShader(fragmentID);
- return programID;
- }
-
- // ----------------------------------------------------------------------------
-
- std::string Shader::getVersion(bool linked) {
- static std::string cache;
- static std::string cacheLinked;
- static bool cacheFilled = false;
-
- if (!cacheFilled) {
- std::ostringstream str;
- str << "OpenGL v" << gl::glGetString(gl::GL_VERSION);
- cache = str.str();
- str.str("");
- str << "OpenGL " << gl::glGetString(gl::GL_SHADING_LANGUAGE_VERSION) << " "
- << gl::glGetString(gl::GL_RENDERER) << " (" << gl::glGetString(gl::GL_VENDOR) << ")";
- cacheLinked = str.str();
- cacheFilled = true;
- }
-
- if (linked) {
- return cacheLinked;
- } else {
- return cache;
- }
- }
-
- Shader Shader::textureShader;
- Shader Shader::colorShader;
- Shader Shader::transformedColorShader;
- unsigned int Shader::vertexArrayID = 0;
- bool Shader::lastBufferWasNotFramebuffer = true;
-
- int Shader::initialize() {
- gl::glGenVertexArrays(1, &vertexArrayID);
- gl::glBindVertexArray(vertexArrayID);
-
- // Set background color
- gl::glClearColor(0.0f, 0.0f, 0.4f, 1.0f);
-
- set2DState(false);
- gl::glDepthFunc(gl::GL_LESS);
-
- gl::glEnable(gl::GL_BLEND);
- gl::glBlendEquation(gl::GL_FUNC_ADD);
- gl::glBlendFunc(gl::GL_SRC_ALPHA, gl::GL_ONE_MINUS_SRC_ALPHA);
-
- gl::glPointSize(5.0f);
-
- if (textureShader.compile(textureShaderVertex, textureShaderFragment) < 0)
- return -1;
- if (textureShader.addUniform("MVP") < 0)
- return -2;
- if (textureShader.addUniform("textureSampler") < 0)
- return -3;
-
- if (colorShader.compile(colorShaderVertex, colorShaderFragment) < 0)
- return -4;
- if (colorShader.addUniform("MVP") < 0)
- return -5;
-
- if (transformedColorShader.compile(transformedColorShaderVertex,
- transformedColorShaderFragment) < 0)
- return -6;
-
- return 0;
- }
-
- void Shader::shutdown() {
- gl::glDeleteVertexArrays(1, &vertexArrayID);
- }
-
- void Shader::set2DState(bool on, bool depth) {
- if (on) {
- gl::glDisable(gl::GL_CULL_FACE);
- if (depth)
- gl::glDisable(gl::GL_DEPTH_TEST);
- } else {
- gl::glEnable(gl::GL_CULL_FACE);
- if (depth)
- gl::glEnable(gl::GL_DEPTH_TEST);
- }
- }
-
- void Shader::bindProperBuffer(ShaderTexture* target) {
- if ((target == nullptr) && lastBufferWasNotFramebuffer) {
- lastBufferWasNotFramebuffer = false;
- gl::glBindFramebuffer(gl::GL_FRAMEBUFFER, 0);
- gl::glViewport(0, 0, Window::getSize().x, Window::getSize().y);
- } else if (target != nullptr) {
- lastBufferWasNotFramebuffer = true;
- target->bind();
- }
- }
-
- void Shader::drawGL(std::vector<glm::vec3>& vertices, std::vector<glm::vec2>& uvs,
- glm::mat4 MVP, unsigned int texture, TextureStorage store,
- gl::GLenum mode, ShaderTexture* target, Shader& shader) {
- bindProperBuffer(target);
-
- shader.use();
- shader.loadUniform(0, MVP);
- shader.loadUniform(1, texture, store);
-
- shader.vertexBuffer.bufferData(vertices);
- shader.otherBuffer.bufferData(uvs);
-
- shader.vertexBuffer.bindBuffer(0, 3);
- shader.otherBuffer.bindBuffer(1, 2);
-
- gl::glDrawArrays(mode, 0, shader.vertexBuffer.getSize());
-
- shader.vertexBuffer.unbind(0);
- shader.otherBuffer.unbind(1);
- }
-
- void Shader::drawGL(std::vector<glm::vec3>& vertices, std::vector<glm::vec2>& uvs,
- std::vector<unsigned short>& indices, glm::mat4 MVP,
- unsigned int texture, TextureStorage store,
- gl::GLenum mode, ShaderTexture* target, Shader& shader) {
- drawGLBuffer(vertices, uvs);
- drawGLOnly(indices, MVP, texture, store, mode, target, shader);
- }
-
- void Shader::drawGLBuffer(std::vector<glm::vec3>& vertices, std::vector<glm::vec2>& uvs,
- Shader& shader) {
- shader.vertexBuffer.bufferData(vertices);
- shader.otherBuffer.bufferData(uvs);
- }
-
- void Shader::drawGLOnly(std::vector<unsigned short>& indices, glm::mat4 MVP,
- unsigned int texture, TextureStorage store,
- gl::GLenum mode, ShaderTexture* target, Shader& shader) {
- bindProperBuffer(target);
-
- shader.use();
- shader.loadUniform(0, MVP);
- shader.loadUniform(1, texture, store);
-
- shader.indexBuffer.bufferData(indices);
-
- shader.vertexBuffer.bindBuffer(0, 3);
- shader.otherBuffer.bindBuffer(1, 2);
- shader.indexBuffer.bindBuffer();
-
- gl::glDrawElements(mode, shader.indexBuffer.getSize(), gl::GL_UNSIGNED_SHORT, nullptr);
-
- shader.vertexBuffer.unbind(0);
- shader.otherBuffer.unbind(1);
- }
-
- void Shader::drawGL(std::vector<glm::vec3>& vertices, std::vector<glm::vec3>& colors,
- glm::mat4 MVP, gl::GLenum mode, ShaderTexture* target, Shader& shader) {
- bindProperBuffer(target);
-
- shader.use();
- shader.loadUniform(0, MVP);
-
- shader.vertexBuffer.bufferData(vertices);
- shader.otherBuffer.bufferData(colors);
-
- shader.vertexBuffer.bindBuffer(0, 3);
- shader.otherBuffer.bindBuffer(1, 3);
-
- gl::glDrawArrays(mode, 0, shader.vertexBuffer.getSize());
-
- shader.vertexBuffer.unbind(0);
- shader.otherBuffer.unbind(1);
- }
-
- void Shader::drawGL(std::vector<glm::vec3>& vertices, std::vector<glm::vec3>& colors,
- std::vector<unsigned short>& indices, glm::mat4 MVP,
- gl::GLenum mode, ShaderTexture* target, Shader& shader) {
- bindProperBuffer(target);
-
- shader.use();
- shader.loadUniform(0, MVP);
-
- shader.vertexBuffer.bufferData(vertices);
- shader.otherBuffer.bufferData(colors);
- shader.indexBuffer.bufferData(indices);
-
- shader.vertexBuffer.bindBuffer(0, 3);
- shader.otherBuffer.bindBuffer(1, 3);
- shader.indexBuffer.bindBuffer();
-
- gl::glDrawElements(mode, shader.indexBuffer.getSize(), gl::GL_UNSIGNED_SHORT, nullptr);
-
- shader.vertexBuffer.unbind(0);
- shader.otherBuffer.unbind(1);
- }
-
- void Shader::drawGL(std::vector<glm::vec4>& vertices, std::vector<glm::vec3>& colors,
- gl::GLenum mode, ShaderTexture* target, Shader& shader) {
- bindProperBuffer(target);
-
- shader.use();
- shader.vertexBuffer.bufferData(vertices);
- shader.otherBuffer.bufferData(colors);
-
- shader.vertexBuffer.bindBuffer(0, 4);
- shader.otherBuffer.bindBuffer(1, 3);
-
- gl::glDrawArrays(mode, 0, shader.vertexBuffer.getSize());
-
- shader.vertexBuffer.unbind(0);
- shader.otherBuffer.unbind(0);
- }
-
- void Shader::drawGL(std::vector<glm::vec4>& vertices, std::vector<glm::vec3>& colors,
- std::vector<unsigned short>& indices, gl::GLenum mode,
- ShaderTexture* target, Shader& shader) {
- bindProperBuffer(target);
-
- shader.use();
- shader.vertexBuffer.bufferData(vertices);
- shader.otherBuffer.bufferData(colors);
- shader.indexBuffer.bufferData(indices);
-
- shader.vertexBuffer.bindBuffer(0, 4);
- shader.otherBuffer.bindBuffer(1, 3);
- shader.indexBuffer.bindBuffer();
-
- gl::glDrawElements(mode, shader.indexBuffer.getSize(), gl::GL_UNSIGNED_SHORT, nullptr);
-
- shader.vertexBuffer.unbind(0);
- shader.otherBuffer.unbind(0);
- }
-
- // --------------------------------------
- // *INDENT-OFF*
-
- const char* Shader::textureShaderVertex = R"!?!(
- #version 330 core
-
- layout(location = 0) in vec3 vertexPosition_modelspace;
- layout(location = 1) in vec2 vertexUV;
-
- out vec2 UV;
-
- uniform mat4 MVP;
-
- void main() {
- vec4 pos = MVP * vec4(vertexPosition_modelspace, 1);
- gl_Position = pos;
- UV = vertexUV;
- }
- )!?!";
-
- const char* Shader::textureShaderFragment = R"!?!(
- #version 330 core
-
- in vec2 UV;
-
- layout(location = 0) out vec4 color;
-
- uniform sampler2D textureSampler;
-
- void main() {
- color = texture(textureSampler, UV);
- }
- )!?!";
-
- // --------------------------------------
-
- const char* Shader::colorShaderVertex = R"!?!(
- #version 330 core
-
- layout(location = 0) in vec3 vertexPosition_modelspace;
- layout(location = 1) in vec3 vertexColor;
-
- out vec3 color;
-
- uniform mat4 MVP;
-
- void main() {
- vec4 pos = MVP * vec4(vertexPosition_modelspace, 1);
- gl_Position = pos;
- color = vertexColor;
- }
- )!?!";
-
- const char* Shader::colorShaderFragment = R"!?!(
- #version 330 core
-
- in vec3 color;
-
- layout(location = 0) out vec4 color_out;
-
- void main() {
- color_out = vec4(color, 1);
- }
- )!?!";
-
- // --------------------------------------
-
- const char* Shader::transformedColorShaderVertex = R"!?!(
- #version 330 core
-
- layout(location = 0) in vec4 vertexPosition;
- layout(location = 1) in vec3 vertexColor;
-
- out vec3 color;
-
- void main() {
- gl_Position = vertexPosition;
- color = vertexColor;
- }
- )!?!";
-
- const char* Shader::transformedColorShaderFragment = R"!?!(
- #version 330 core
-
- in vec3 color;
-
- layout(location = 0) out vec4 color_out;
-
- void main() {
- color_out = vec4(color, 1);
- }
- )!?!";
-
- // --------------------------------------
- // *INDENT-ON*
|