ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

shader.cpp

Go to the documentation of this file.
00001 /* ResidualVM - A 3D game interpreter
00002  *
00003  * ResidualVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "common/scummsys.h"
00024 
00025 #if defined(USE_GLES2) || defined(USE_OPENGL_SHADERS)
00026 
00027 #include "graphics/opengl/shader.h"
00028 
00029 #include "graphics/opengl/context.h"
00030 
00031 namespace OpenGL {
00032 
00033 static const GLchar *readFile(const Common::String &filename) {
00034     Common::File file;
00035 
00036     // Allow load shaders from source code directory without install them
00037     // It's used for development purpose
00038     // FIXME: it's doesn't work with just search subdirs in 'engines'
00039     SearchMan.addDirectory("GRIM_SHADERS", "engines/grim", 0, 2);
00040     SearchMan.addDirectory("MYST3_SHADERS", "engines/myst3", 0, 2);
00041     SearchMan.addDirectory("STARK_SHADERS", "engines/stark", 0, 2);
00042     file.open(Common::String("shaders/") + filename);
00043     if (!file.isOpen())
00044         error("Could not open shader %s!", filename.c_str());
00045     SearchMan.remove("GRIM_SHADERS");
00046     SearchMan.remove("MYST3_SHADERS");
00047     SearchMan.remove("STARK_SHADERS");
00048 
00049     const int32 size = file.size();
00050     GLchar *shaderSource = new GLchar[size + 1];
00051 
00052     file.read(shaderSource, size);
00053     file.close();
00054     shaderSource[size] = '\0';
00055     return shaderSource;
00056 }
00057 
00058 static GLuint createDirectShader(const char *shaderSource, GLenum shaderType, const Common::String &name) {
00059     GLuint shader = glCreateShader(shaderType);
00060     glShaderSource(shader, 1, &shaderSource, NULL);
00061     glCompileShader(shader);
00062 
00063     GLint status;
00064     glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
00065     if (status != GL_TRUE) {
00066         char buffer[512];
00067         glGetShaderInfoLog(shader, 512, NULL, buffer);
00068         error("Could not compile shader %s: %s", name.c_str(), buffer);
00069     }
00070 
00071     return shader;
00072 }
00073 
00074 static GLuint createCompatShader(const char *shaderSource, GLenum shaderType, const Common::String &name) {
00075     const GLchar *versionSource = OpenGLContext.type == kContextGLES2 ? "#version 100\n" : "#version 120\n";
00076     const GLchar *compatSource =
00077             shaderType == GL_VERTEX_SHADER ? OpenGL::BuiltinShaders::compatVertex : OpenGL::BuiltinShaders::compatFragment;
00078     const GLchar *shaderSources[] = {
00079         versionSource,
00080         compatSource,
00081         shaderSource
00082     };
00083 
00084     GLuint shader = glCreateShader(shaderType);
00085     glShaderSource(shader, 3, shaderSources, NULL);
00086     glCompileShader(shader);
00087 
00088     GLint status;
00089     glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
00090     if (status != GL_TRUE) {
00091         char buffer[512];
00092         glGetShaderInfoLog(shader, 512, NULL, buffer);
00093         error("Could not compile shader %s: %s", name.c_str(), buffer);
00094     }
00095 
00096     return shader;
00097 }
00098 
00099 static GLuint loadShaderFromFile(const char *base, const char *extension, GLenum shaderType) {
00100     const Common::String filename = Common::String(base) + "." + extension;
00101     const GLchar *shaderSource = readFile(filename);
00102 
00103     GLuint shader = createCompatShader(shaderSource, shaderType, filename);
00104 
00105     delete[] shaderSource;
00106 
00107     return shader;
00108 }
00109 
00113 struct SharedPtrProgramDeleter {
00114     void operator()(GLuint *ptr) {
00115         if (ptr) {
00116             glDeleteProgram(*ptr);
00117         }
00118         delete ptr;
00119     }
00120 };
00121 
00122 Shader* Shader::_previousShader = nullptr;
00123 
00124 Shader::Shader(const Common::String &name, GLuint vertexShader, GLuint fragmentShader, const char **attributes)
00125     : _name(name) {
00126     assert(attributes);
00127     GLuint shaderProgram = glCreateProgram();
00128     glAttachShader(shaderProgram, vertexShader);
00129     glAttachShader(shaderProgram, fragmentShader);
00130 
00131     for (int idx = 0; attributes[idx]; ++idx) {
00132         glBindAttribLocation(shaderProgram, idx, attributes[idx]);
00133         _attributes.push_back(VertexAttrib(idx, attributes[idx]));
00134     }
00135     glLinkProgram(shaderProgram);
00136 
00137     glDetachShader(shaderProgram, vertexShader);
00138     glDetachShader(shaderProgram, fragmentShader);
00139 
00140     glDeleteShader(vertexShader);
00141     glDeleteShader(fragmentShader);
00142 
00143     _shaderNo = Common::SharedPtr<GLuint>(new GLuint(shaderProgram), SharedPtrProgramDeleter());
00144     _uniforms = Common::SharedPtr<UniformsMap>(new UniformsMap());
00145 }
00146 
00147 Shader *Shader::fromStrings(const Common::String &name, const char *vertex, const char *fragment, const char **attributes) {
00148     GLuint vertexShader = createDirectShader(vertex, GL_VERTEX_SHADER, name + ".vertex");
00149     GLuint fragmentShader = createDirectShader(fragment, GL_FRAGMENT_SHADER, name + ".fragment");
00150     return new Shader(name, vertexShader, fragmentShader, attributes);
00151 }
00152 
00153 
00154 Shader *Shader::fromFiles(const char *vertex, const char *fragment, const char **attributes) {
00155     GLuint vertexShader = loadShaderFromFile(vertex, "vertex", GL_VERTEX_SHADER);
00156     GLuint fragmentShader = loadShaderFromFile(fragment, "fragment", GL_FRAGMENT_SHADER);
00157 
00158     Common::String name = Common::String::format("%s/%s", vertex, fragment);
00159     return new Shader(name, vertexShader, fragmentShader, attributes);
00160 }
00161 
00162 void Shader::use(bool forceReload) {
00163     static uint32 previousNumAttributes = 0;
00164     if (this == _previousShader && !forceReload)
00165         return;
00166 
00167     // The previous shader might have had more attributes. Disable any extra ones.
00168     if (_attributes.size() < previousNumAttributes) {
00169         for (uint32 i = _attributes.size(); i < previousNumAttributes; ++i) {
00170             glDisableVertexAttribArray(i);
00171         }
00172     }
00173 
00174     _previousShader = this;
00175     previousNumAttributes = _attributes.size();
00176 
00177     glUseProgram(*_shaderNo);
00178     for (uint32 i = 0; i < _attributes.size(); ++i) {
00179         VertexAttrib &attrib = _attributes[i];
00180         if (attrib._enabled) {
00181             glEnableVertexAttribArray(i);
00182             glBindBuffer(GL_ARRAY_BUFFER, attrib._vbo);
00183             glVertexAttribPointer(i, attrib._size, attrib._type, attrib._normalized, attrib._stride, (const GLvoid *)attrib._offset);
00184         } else {
00185             glDisableVertexAttribArray(i);
00186             switch (attrib._size) {
00187             case 2:
00188                 glVertexAttrib2fv(i, attrib._const);
00189                 break;
00190             case 3:
00191                 glVertexAttrib3fv(i, attrib._const);
00192                 break;
00193             case 4:
00194                 glVertexAttrib4fv(i, attrib._const);
00195                 break;
00196             }
00197         }
00198     }
00199 }
00200 
00201 GLuint Shader::createBuffer(GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage) {
00202     GLuint vbo;
00203     glGenBuffers(1, &vbo);
00204     glBindBuffer(target, vbo);
00205     glBufferData(target, size, data, usage);
00206     return vbo;
00207 }
00208 
00209 void Shader::freeBuffer(GLuint vbo) {
00210     glDeleteBuffers(1, &vbo);
00211 }
00212 
00213 VertexAttrib &Shader::getAttributeAt(uint32 idx) {
00214     assert(idx < _attributes.size());
00215     return _attributes[idx];
00216 }
00217 
00218 VertexAttrib &Shader::getAttribute(const char *attrib) {
00219     for (uint32 i = 0; i < _attributes.size(); ++i)
00220         if (_attributes[i]._name.equals(attrib))
00221             return _attributes[i];
00222     error("Could not find attribute %s in shader %s", attrib, _name.c_str());
00223     return _attributes[0];
00224 }
00225 
00226 void Shader::enableVertexAttribute(const char *attrib, GLuint vbo, GLint size, GLenum type, GLboolean normalized, GLsizei stride, uint32 offset) {
00227     VertexAttrib &va = getAttribute(attrib);
00228     va._enabled = true;
00229     va._vbo = vbo;
00230     va._size = size;
00231     va._type = type;
00232     va._normalized = normalized;
00233     va._stride = stride;
00234     va._offset = offset;
00235 }
00236 
00237 void Shader::disableVertexAttribute(const char *attrib, int size, const float *data) {
00238     VertexAttrib &va = getAttribute(attrib);
00239     va._enabled = false;
00240     va._size = size;
00241     for (int i = 0; i < size; ++i)
00242         va._const[i] = data[i];
00243 }
00244 
00245 void Shader::unbind() {
00246     glUseProgram(0);
00247     _previousShader = nullptr;
00248 }
00249 
00250 Shader::~Shader() {
00251     // If this is the currently active shader, unbind
00252     if (_previousShader == this) {
00253         unbind();
00254     }
00255 }
00256 
00257 } // End of namespace OpenGL
00258 
00259 #endif


Generated on Sat May 18 2019 05:01:20 for ResidualVM by doxygen 1.7.1
curved edge   curved edge