From fd10aba8151a9dbba788eb1e5b4bc9f62605a537 Mon Sep 17 00:00:00 2001 From: Leon Styhre Date: Fri, 4 Sep 2020 18:59:19 +0200 Subject: [PATCH] Updated the GLSL shader logic and added a postprocessing function. --- es-core/src/renderers/Renderer.cpp | 41 ++-- es-core/src/renderers/Renderer.h | 29 ++- es-core/src/renderers/Renderer_GL21.cpp | 164 ++++++++++++--- es-core/src/renderers/Shader_GL21.cpp | 76 +++---- es-core/src/renderers/Shader_GL21.h | 23 +-- resources/shaders/glsl/blur_horizontal.glsl | 137 +++++++++++++ resources/shaders/glsl/blur_vertical.glsl | 137 +++++++++++++ resources/shaders/glsl/desaturate.glsl | 16 +- resources/shaders/glsl/scanlines.glsl | 208 ++++++++++++++++++++ 9 files changed, 724 insertions(+), 107 deletions(-) create mode 100644 resources/shaders/glsl/blur_horizontal.glsl create mode 100644 resources/shaders/glsl/blur_vertical.glsl create mode 100644 resources/shaders/glsl/scanlines.glsl diff --git a/es-core/src/renderers/Renderer.cpp b/es-core/src/renderers/Renderer.cpp index 0e4744185..3834c5967 100644 --- a/es-core/src/renderers/Renderer.cpp +++ b/es-core/src/renderers/Renderer.cpp @@ -70,7 +70,7 @@ namespace Renderer LOG(LogInfo) << "Creating window..."; if (SDL_Init(SDL_INIT_VIDEO) != 0) { - LOG(LogError) << "Error initializing SDL!\n " << SDL_GetError(); + LOG(LogError) << "Couldn't initialize SDL: " << SDL_GetError() << "."; return false; } @@ -167,17 +167,25 @@ namespace Renderer #if defined(USE_OPENGL_21) LOG(LogInfo) << "Loading shaders..."; - Shader* desaturateShader = new Shader(); + std::vector shaderFiles; + shaderFiles.push_back(":/shaders/glsl/desaturate.glsl"); + shaderFiles.push_back(":/shaders/glsl/blur_horizontal.glsl"); + shaderFiles.push_back(":/shaders/glsl/blur_vertical.glsl"); + shaderFiles.push_back(":/shaders/glsl/scanlines.glsl"); - desaturateShader->loadShaderFile(":/shaders/glsl/desaturate.glsl", GL_VERTEX_SHADER); - desaturateShader->loadShaderFile(":/shaders/glsl/desaturate.glsl", GL_FRAGMENT_SHADER); + for (auto it = shaderFiles.cbegin(); it != shaderFiles.cend(); it++) { + Shader* loadShader = new Shader(); - if (!desaturateShader->createProgram()) { - LOG(LogError) << "Could not create shader program."; - return false; + loadShader->loadShaderFile(*it, GL_VERTEX_SHADER); + loadShader->loadShaderFile(*it, GL_FRAGMENT_SHADER); + + if (!loadShader->createProgram()) { + LOG(LogError) << "Could not create shader program."; + return false; + } + + sShaderProgramVector.push_back(loadShader); } - - sShaderProgramVector.push_back(desaturateShader); #endif return true; @@ -373,10 +381,19 @@ namespace Renderer return red << 24 | green << 16 | blue << 8 | alpha; } - Shader* getShaderProgram(unsigned int index) + Shader* getShaderProgram(unsigned int shaderID) { - if (sShaderProgramVector.size() > index) - return sShaderProgramVector[index]; + unsigned int index = 0; + + // Find the index in sShaderProgramVector by counting the number + // of shifts required to reach 0. + while (shaderID > 0) { + shaderID = shaderID >> 1; + index++; + } + + if (sShaderProgramVector.size() > index-1) + return sShaderProgramVector[index-1]; else return nullptr; }; diff --git a/es-core/src/renderers/Renderer.h b/es-core/src/renderers/Renderer.h index 6c5024922..057e7fbc0 100644 --- a/es-core/src/renderers/Renderer.h +++ b/es-core/src/renderers/Renderer.h @@ -21,7 +21,27 @@ struct SDL_Window; namespace Renderer { + const unsigned int SHADER_DESATURATE = 1; + const unsigned int SHADER_BLUR_HORIZONTAL = 2; + const unsigned int SHADER_BLUR_VERTICAL = 4; + const unsigned int SHADER_SCANLINES = 8; + + struct shaderParameters { + std::array textureSize; + std::array textureCoordinates; + float fragmentSaturation; + unsigned int shaderPasses; + + shaderParameters() + : textureSize({0.0, 0.0}), + textureCoordinates({0.0, 0.0, 0.0, 0.0}), + fragmentSaturation(1.0), + shaderPasses(1) + {}; + }; + static std::vector sShaderProgramVector; + static GLuint shaderFBO; #if !defined(NDEBUG) #define GL_CHECK_ERROR(Function) (Function, _GLCheckError(#Function)) @@ -99,6 +119,7 @@ namespace Renderer Vector2f tex; unsigned int col; float saturation = 1.0; + unsigned int shaders = 0; }; bool init(); @@ -127,7 +148,10 @@ namespace Renderer unsigned int rgbaToABGR(unsigned int color); unsigned int abgrToRGBA(unsigned int color); - Shader* getShaderProgram(unsigned int index); + Shader* getShaderProgram(unsigned int shaderID); + void shaderPostprocessing(unsigned int shaders, + const Renderer::shaderParameters& parameters = shaderParameters(), + unsigned char* textureRGBA = nullptr); // API specific. unsigned int convertColor(const unsigned int _color); @@ -161,7 +185,8 @@ namespace Renderer const Vertex* _vertices, const unsigned int _numVertices, const Blend::Factor _srcBlendFactor = Blend::SRC_ALPHA, - const Blend::Factor _dstBlendFactor = Blend::ONE_MINUS_SRC_ALPHA); + const Blend::Factor _dstBlendFactor = Blend::ONE_MINUS_SRC_ALPHA, + const shaderParameters& parameters = shaderParameters()); void setProjection(const Transform4x4f& _projection); void setMatrix(const Transform4x4f& _matrix); void setViewport(const Rect& _viewport); diff --git a/es-core/src/renderers/Renderer_GL21.cpp b/es-core/src/renderers/Renderer_GL21.cpp index c7b05fcff..7efb8dfea 100644 --- a/es-core/src/renderers/Renderer_GL21.cpp +++ b/es-core/src/renderers/Renderer_GL21.cpp @@ -127,6 +127,13 @@ namespace Renderer else { LOG(LogInfo) << "GL_ARB_fragment_shader: OK"; } + if (extensions.find("GL_EXT_framebuffer_blit") == std::string::npos) { + LOG(LogError) << "GL_EXT_framebuffer_blit: MISSING"; + missingExtension = true; + } + else { + LOG(LogInfo) << "GL_EXT_framebuffer_blit: OK"; + } if (missingExtension) { LOG(LogError) << "Required OpenGL extensions missing."; return false; @@ -144,11 +151,15 @@ namespace Renderer GL_CHECK_ERROR(glEnableClientState(GL_TEXTURE_COORD_ARRAY)); GL_CHECK_ERROR(glEnableClientState(GL_COLOR_ARRAY)); + // This is the framebuffer that will be used for shader rendering. + GL_CHECK_ERROR(glGenFramebuffers(1, &shaderFBO)); + return true; } void destroyContext() { + GL_CHECK_ERROR(glDeleteFramebuffers(1, &shaderFBO)); SDL_GL_DeleteContext(sdlContext); sdlContext = nullptr; } @@ -225,28 +236,17 @@ namespace Renderer convertBlendFactor(_dstBlendFactor))); GL_CHECK_ERROR(glDrawArrays(GL_LINES, 0, _numVertices)); - - // If saturation is set below the maximum (default) value, run the desaturation shader. - if (_vertices->saturation < 1.0) { - Shader* desaturateShader = getShaderProgram(Shader::Desaturate); - - // Only try to use the shader if it has been loaded properly. - if (desaturateShader) { - desaturateShader->activateShaders(); - desaturateShader->getVariableLocations(desaturateShader->getProgramID()); - desaturateShader->setVariable(_vertices->saturation); - GL_CHECK_ERROR(glDrawArrays(GL_LINES, 0, _numVertices)); - desaturateShader->deactivateShaders(); - } - } } void drawTriangleStrips( const Vertex* _vertices, const unsigned int _numVertices, const Blend::Factor _srcBlendFactor, - const Blend::Factor _dstBlendFactor) + const Blend::Factor _dstBlendFactor, + const shaderParameters& parameters) { + float width = _vertices[3].pos[0]; + float height = _vertices[3].pos[1]; GL_CHECK_ERROR(glVertexPointer(2, GL_FLOAT, sizeof(Vertex), &_vertices[0].pos)); GL_CHECK_ERROR(glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), &_vertices[0].tex)); GL_CHECK_ERROR(glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Vertex), &_vertices[0].col)); @@ -256,17 +256,56 @@ namespace Renderer GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, _numVertices)); - // If saturation is set below the maximum (default) value, run the desaturation shader. - if (_vertices->saturation < 1.0) { - Shader* desaturateShader = getShaderProgram(Shader::Desaturate); + for (unsigned int i = 0; i < parameters.shaderPasses; i++) { + // If saturation is set below the maximum (default) value, run the desaturation shader. + if (_vertices->saturation < 1.0 || parameters.fragmentSaturation < 1.0) { + Shader* runShader = getShaderProgram(SHADER_DESATURATE); + // Only try to use the shader if it has been loaded properly. + if (runShader) { + runShader->activateShaders(); + runShader->getVariableLocations(runShader->getProgramID()); + runShader->setSaturation(_vertices->saturation); + GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, _numVertices)); + runShader->deactivateShaders(); + } + } - // Only try to use the shader if it has been loaded properly. - if (desaturateShader) { - desaturateShader->activateShaders(); - desaturateShader->getVariableLocations(desaturateShader->getProgramID()); - desaturateShader->setVariable(_vertices->saturation); - GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, _numVertices)); - desaturateShader->deactivateShaders(); + // Check if any other shaders are set to be used and if so, run them. + if (_vertices->shaders & SHADER_BLUR_HORIZONTAL) { + Shader* runShader = getShaderProgram(SHADER_BLUR_HORIZONTAL); + if (runShader) { + runShader->activateShaders(); + runShader->getVariableLocations(runShader->getProgramID()); + runShader->setTextureSize({width, height}); + GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, _numVertices)); + runShader->deactivateShaders(); + } + } + + if (_vertices->shaders & SHADER_BLUR_VERTICAL) { + Shader* runShader = getShaderProgram(SHADER_BLUR_VERTICAL); + if (runShader) { + runShader->activateShaders(); + runShader->getVariableLocations(runShader->getProgramID()); + runShader->setTextureSize({width, height}); + GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, _numVertices)); + runShader->deactivateShaders(); + } + } + + if (_vertices->shaders & SHADER_SCANLINES) { + Shader* runShader = getShaderProgram(SHADER_SCANLINES); + float shaderWidth = width * 1.2; + // Workaround to get the scanlines to render somehow proportional to the + // resolution. A better solution is for sure needed. + float shaderHeight = height + height / ((int)height >> 7) * 1.5; + if (runShader) { + runShader->activateShaders(); + runShader->getVariableLocations(runShader->getProgramID()); + runShader->setTextureSize({shaderWidth, shaderHeight}); + GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, _numVertices)); + runShader->deactivateShaders(); + } } } } @@ -330,6 +369,81 @@ namespace Renderer GL_CHECK_ERROR(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)); } + void shaderPostprocessing(unsigned int shaders, const Renderer::shaderParameters& parameters, + unsigned char* textureRGBA) + { + Vertex vertices[4]; + GLuint width = getScreenWidth(); + GLuint height = getScreenHeight(); + float widthf = static_cast(width); + float heightf = static_cast(height); + + // Set vertex positions and texture coordinates to full screen as all + // postprocessing is applied to the complete screen area. + vertices[0] = { { 0, 0 }, { 0, 1 }, 0 }; + vertices[1] = { { 0, heightf }, { 0, 0 }, 0 }; + vertices[2] = { { widthf, 0 }, { 1, 1 }, 0 }; + vertices[3] = { { widthf, heightf }, { 1, 0 }, 0}; + + vertices[0].shaders = shaders; + vertices[1].shaders = shaders; + vertices[2].shaders = shaders; + vertices[3].shaders = shaders; + + if (parameters.fragmentSaturation < 1.0) { + vertices[0].saturation = parameters.fragmentSaturation; + vertices[1].saturation = parameters.fragmentSaturation; + vertices[2].saturation = parameters.fragmentSaturation; + vertices[3].saturation = parameters.fragmentSaturation; + } + + setMatrix(Transform4x4f::Identity()); + + // The following method to apply the shaders is not optimal as it requires + // glBlitFramebuffer() to run twice. However, this function seems to be + // very fast so maybe it's not a practical issue. + GLuint screenTexture = createTexture(Texture::RGBA, false, false, width, height, nullptr); + + GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, 0)); + GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, shaderFBO)); + + // Attach the texture to the shader framebuffer. + GL_CHECK_ERROR(glFramebufferTexture2D( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, + screenTexture, + 0)); + + // Blit the screen contents to screenTexture. + GL_CHECK_ERROR(glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, + GL_COLOR_BUFFER_BIT, GL_NEAREST)); + + // Apply/render the shaders. + drawTriangleStrips(vertices, 4, Blend::SRC_ALPHA, Blend::ONE_MINUS_SRC_ALPHA, parameters); + + // If textureRGBA has an address, it means that the output should go to this texture + // rather than to the screen. The glReadPixels() function is slow, but since this would + // typically only run every now and then to create a cached screen texture, it doesn't + // really matter. + if (textureRGBA) { + GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, shaderFBO)); + GL_CHECK_ERROR(glReadPixels(0, 0, width, height, + GL_RGBA, GL_UNSIGNED_BYTE, textureRGBA)); + GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0)); + } + else { + // Blit the resulting postprocessed texture back to the primary framebuffer. + GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, shaderFBO)); + GL_CHECK_ERROR(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0)); + GL_CHECK_ERROR(glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, + GL_COLOR_BUFFER_BIT, GL_NEAREST)); + } + + GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, 0)); + destroyTexture(screenTexture); + } + } // Renderer:: #endif // USE_OPENGL_21 diff --git a/es-core/src/renderers/Shader_GL21.cpp b/es-core/src/renderers/Shader_GL21.cpp index 2a8d9f049..729d76f5f 100644 --- a/es-core/src/renderers/Shader_GL21.cpp +++ b/es-core/src/renderers/Shader_GL21.cpp @@ -16,12 +16,10 @@ namespace Renderer { Renderer::Shader::Shader() : mProgramID(-1), - shaderFloat_0(-1), - shaderFloat_1(-1), - shaderFloat_2(-1), - shaderVec4_0(-1), - shaderVec4_1(-1), - shaderVec4_2(-1) + shaderTextureSize(-1), + shaderTextureCoord(-1), + shaderColor(-1), + shaderSaturation(-1) { } @@ -42,7 +40,7 @@ namespace Renderer // Define the GLSL version (version 120 = OpenGL 2.1). preprocessorDefines = "#version 120\n"; - // Define the preprocessor macros that will let the shader compiler know whether + // Define the preprocessor constants that will let the shader compiler know whether // the VERTEX or FRAGMENT portion of the code should be used. if (shaderType == GL_VERTEX_SHADER) preprocessorDefines += "#define VERTEX\n"; @@ -73,7 +71,7 @@ namespace Renderer if (shaderCompiled != GL_TRUE) { LOG(LogError) << "OpenGL error: Unable to compile shader " << currentShader << " (" << std::get<0>(*it) << ")."; - printShaderInfoLog(currentShader); + printShaderInfoLog(currentShader, std::get<2>(*it)); return false; } @@ -99,47 +97,34 @@ namespace Renderer void Renderer::Shader::getVariableLocations(GLuint programID) { - shaderFloat_0 = glGetUniformLocation(mProgramID, "shaderFloat_0"); - shaderFloat_1 = glGetUniformLocation(mProgramID, "shaderFloat_1"); - shaderFloat_2 = glGetUniformLocation(mProgramID, "shaderFloat_2"); - shaderVec4_0 = glGetUniformLocation(mProgramID, "shaderVec4_0"); - shaderVec4_1 = glGetUniformLocation(mProgramID, "shaderVec4_1"); - shaderVec4_2 = glGetUniformLocation(mProgramID, "shaderVec4_2"); + // Some of the variable names are chosen to be compatible with the RetroArch GLSL shaders. + shaderTextureSize = glGetUniformLocation(mProgramID, "TextureSize"); + shaderTextureCoord = glGetAttribLocation(mProgramID, "TexCoord"); + shaderColor = glGetAttribLocation(mProgramID, "COLOR"); + shaderSaturation = glGetUniformLocation(mProgramID, "saturation"); } - void Renderer::Shader::setVariable(GLfloat shaderFloat, int index) + void Renderer::Shader::setTextureSize(std::array shaderVec2) { - switch (index) { - case 0: - GL_CHECK_ERROR(glUniform1f(shaderFloat_0, shaderFloat)); - break; - case 1: - GL_CHECK_ERROR(glUniform1f(shaderFloat_1, shaderFloat)); - break; - case 2: - GL_CHECK_ERROR(glUniform1f(shaderFloat_2, shaderFloat)); - break; - default: - break; - } + GL_CHECK_ERROR(glUniform2f(shaderTextureSize, shaderVec2[0], shaderVec2[1])); } - void Renderer::Shader::setVariable(std::array shaderVec4, int index) + void Renderer::Shader::setTextureCoordinates(std::array shaderVec4) { - switch (index) { - case 0: - GL_CHECK_ERROR(glUniform4f(shaderVec4_0, shaderVec4[0], + glEnableVertexAttribArray(shaderTextureCoord); + glVertexAttribPointer(shaderTextureCoord, 4, GL_FLOAT, GL_FALSE, 0, + (const GLvoid*)(uintptr_t)&shaderVec4); + } + + void Renderer::Shader::setColor(std::array shaderVec4) + { + GL_CHECK_ERROR(glUniform4f(shaderColor, shaderVec4[0], shaderVec4[1], shaderVec4[2], shaderVec4[3])); - break; - case 1: - GL_CHECK_ERROR(glUniform4f(shaderVec4_1, shaderVec4[0], - shaderVec4[1], shaderVec4[2], shaderVec4[3])); - case 2: - GL_CHECK_ERROR(glUniform4f(shaderVec4_2, shaderVec4[0], - shaderVec4[1], shaderVec4[2], shaderVec4[3])); - default: - break; - } + } + + void Renderer::Shader::setSaturation(GLfloat saturation) + { + GL_CHECK_ERROR(glUniform1f(shaderSaturation, saturation)); } void Renderer::Shader::activateShaders() @@ -178,7 +163,7 @@ namespace Renderer } } - void Renderer::Shader::printShaderInfoLog(GLuint shaderID) + void Renderer::Shader::printShaderInfoLog(GLuint shaderID, GLenum shaderType) { if (glIsShader(shaderID)) { int logLength; @@ -190,8 +175,9 @@ namespace Renderer glGetShaderInfoLog(shaderID, maxLength, &logLength, &infoLog.front()); if (logLength > 0) { - LOG(LogDebug) << "Renderer_GL21::printShaderLog():\n" << - std::string(infoLog.begin(), infoLog.end()); + LOG(LogDebug) << "Renderer_GL21::printShaderLog(): Error in " << + (shaderType == GL_VERTEX_SHADER ? "VERTEX section:\n" : + "FRAGMENT section:\n") << std::string(infoLog.begin(), infoLog.end()); } } else { diff --git a/es-core/src/renderers/Shader_GL21.h b/es-core/src/renderers/Shader_GL21.h index aff86e015..67c4b56ad 100644 --- a/es-core/src/renderers/Shader_GL21.h +++ b/es-core/src/renderers/Shader_GL21.h @@ -20,10 +20,6 @@ namespace Renderer class Shader { public: - enum shaderNames { - Desaturate - }; - Shader(); ~Shader(); @@ -36,8 +32,10 @@ namespace Renderer // Get references to the variables inside the compiled shaders. void getVariableLocations(GLuint programID); // One-way communication with the compiled shaders. - void setVariable(GLfloat shaderFloat, int index = 0); - void setVariable(std::array shaderVec4, int index = 0); + void setTextureSize(std::array shaderVec2); + void setTextureCoordinates(std::array shaderVec4); + void setColor(std::array shaderVec4); + void setSaturation(GLfloat saturation); // Sets the shader program to use the loaded shaders. void activateShaders(); // Sets the shader program to 0 which reverts to the fixed function pipeline. @@ -46,20 +44,19 @@ namespace Renderer GLuint getProgramID(); // Only used for error logging if the shaders fail to compile or link. void printProgramInfoLog(GLuint programID); - void printShaderInfoLog(GLuint shaderID); + void printShaderInfoLog(GLuint shaderID, GLenum shaderType); private: GLuint mProgramID; std::vector> shaderVector; // Variables used for communication with the compiled shaders. - GLint shaderFloat_0; - GLint shaderFloat_1; - GLint shaderFloat_2; - GLint shaderVec4_0; - GLint shaderVec4_1; - GLint shaderVec4_2; + GLint shaderTextureSize; + GLint shaderTextureCoord; + GLint shaderColor; + GLint shaderSaturation; }; + } // Renderer #endif // ES_CORE_RENDERER_SHADER_GL21_H diff --git a/resources/shaders/glsl/blur_horizontal.glsl b/resources/shaders/glsl/blur_horizontal.glsl new file mode 100644 index 000000000..f4897cbc8 --- /dev/null +++ b/resources/shaders/glsl/blur_horizontal.glsl @@ -0,0 +1,137 @@ +// Implementation based on the article "Efficient Gaussian blur with linear sampling" +// http://rastergrid.com/blog/2010/09/efficient-gaussian-blur-with-linear-sampling/ +/* A version for MasterEffect Reborn, a standalone version, and a custom shader version for SweetFX can be + found at http://reshade.me/forum/shader-presentation/27-gaussian-blur-bloom-unsharpmask */ + /*-----------------------------------------------------------. +/ Gaussian Blur settings / +'-----------------------------------------------------------*/ + +#define HW 1.00 + +#if defined(VERTEX) + +#if __VERSION__ >= 130 +#define COMPAT_VARYING out +#define COMPAT_ATTRIBUTE in +#define COMPAT_TEXTURE texture +#else +#define COMPAT_VARYING varying +#define COMPAT_ATTRIBUTE attribute +#define COMPAT_TEXTURE texture2D +#endif + +#ifdef GL_ES +#define COMPAT_PRECISION mediump +#else +#define COMPAT_PRECISION +#endif + +COMPAT_ATTRIBUTE vec4 VertexCoord; +COMPAT_ATTRIBUTE vec4 COLOR; +COMPAT_ATTRIBUTE vec4 TexCoord; +COMPAT_VARYING vec4 COL0; +COMPAT_VARYING vec4 TEX0; + +vec4 _oPosition1; +uniform mat4 MVPMatrix; +uniform COMPAT_PRECISION int FrameDirection; +uniform COMPAT_PRECISION int FrameCount; +uniform COMPAT_PRECISION vec2 OutputSize; +uniform COMPAT_PRECISION vec2 TextureSize; +uniform COMPAT_PRECISION vec2 InputSize; + +void main() +{ + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; +// gl_Position = MVPMatrix * VertexCoord; + COL0 = COLOR; + TEX0.xy = gl_MultiTexCoord0.xy; +// TEX0.xy = TexCoord.xy; +} + +#elif defined(FRAGMENT) + +#if __VERSION__ >= 130 +#define COMPAT_VARYING in +#define COMPAT_TEXTURE texture +out vec4 FragColor; +#else +#define COMPAT_VARYING varying +#define FragColor gl_FragColor +#define COMPAT_TEXTURE texture2D +#endif + +#ifdef GL_ES +#ifdef GL_FRAGMENT_PRECISION_HIGH +precision highp float; +#else +precision mediump float; +#endif +#define COMPAT_PRECISION mediump +#else +#define COMPAT_PRECISION +#endif + +uniform COMPAT_PRECISION int FrameDirection; +uniform COMPAT_PRECISION int FrameCount; +uniform COMPAT_PRECISION vec2 OutputSize; +uniform COMPAT_PRECISION vec2 TextureSize; +uniform COMPAT_PRECISION vec2 InputSize; +uniform sampler2D Texture; +COMPAT_VARYING vec4 TEX0; + +// compatibility #defines +#define Source Texture +#define vTexCoord TEX0.xy + +#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize +#define outsize vec4(OutputSize, 1.0 / OutputSize) + +void main() +{ + vec2 texcoord = vTexCoord; +// vec2 PIXEL_SIZE = SourceSize.zw; + vec2 PIXEL_SIZE = vec2(SourceSize.z, SourceSize.w); +#if __VERSION__ < 130 + float sampleOffsets1 = 0.0; + float sampleOffsets2 = 1.4347826; + float sampleOffsets3 = 3.3478260; + float sampleOffsets4 = 5.2608695; + float sampleOffsets5 = 7.1739130; + + float sampleWeights1 = 0.16818994; + float sampleWeights2 = 0.27276957; + float sampleWeights3 = 0.11690125; + float sampleWeights4 = 0.024067905; + float sampleWeights5 = 0.0021112196; + + vec4 color = COMPAT_TEXTURE(Source, texcoord) * sampleWeights1; + +// unroll the loop + color += COMPAT_TEXTURE(Source, texcoord + vec2(sampleOffsets2* HW * PIXEL_SIZE.x, 0.0)) * sampleWeights2; + color += COMPAT_TEXTURE(Source, texcoord - vec2(sampleOffsets2* HW * PIXEL_SIZE.x, 0.0)) * sampleWeights2; + + color += COMPAT_TEXTURE(Source, texcoord + vec2(sampleOffsets3* HW * PIXEL_SIZE.x, 0.0)) * sampleWeights3; + color += COMPAT_TEXTURE(Source, texcoord - vec2(sampleOffsets3* HW * PIXEL_SIZE.x, 0.0)) * sampleWeights3; + + color += COMPAT_TEXTURE(Source, texcoord + vec2(sampleOffsets4* HW * PIXEL_SIZE.x, 0.0)) * sampleWeights4; + color += COMPAT_TEXTURE(Source, texcoord - vec2(sampleOffsets4* HW * PIXEL_SIZE.x, 0.0)) * sampleWeights4; + + color += COMPAT_TEXTURE(Source, texcoord + vec2(sampleOffsets5* HW * PIXEL_SIZE.x, 0.0)) * sampleWeights5; + color += COMPAT_TEXTURE(Source, texcoord - vec2(sampleOffsets5* HW * PIXEL_SIZE.x, 0.0)) * sampleWeights5; +#else + + float sampleOffsets[5] = { 0.0, 1.4347826, 3.3478260, 5.2608695, 7.1739130 }; + float sampleWeights[5] = { 0.16818994, 0.27276957, 0.11690125, 0.024067905, 0.0021112196 }; + + vec4 color = COMPAT_TEXTURE(Source, texcoord) * sampleWeights[0]; + for(int i = 1; i < 5; ++i) { + color += COMPAT_TEXTURE(Source, texcoord + vec2(sampleOffsets[i]*HW * PIXEL_SIZE.x, 0.0)) * sampleWeights[i]; + color += COMPAT_TEXTURE(Source, texcoord - vec2(sampleOffsets[i]*HW * PIXEL_SIZE.x, 0.0)) * sampleWeights[i]; + } +#endif + + FragColor = vec4(color); +// FragColor = vec4(0.4, 0.0, 0.2, 0.6); +} +#endif diff --git a/resources/shaders/glsl/blur_vertical.glsl b/resources/shaders/glsl/blur_vertical.glsl new file mode 100644 index 000000000..abad15bdd --- /dev/null +++ b/resources/shaders/glsl/blur_vertical.glsl @@ -0,0 +1,137 @@ +// Implementation based on the article "Efficient Gaussian blur with linear sampling" +// http://rastergrid.com/blog/2010/09/efficient-gaussian-blur-with-linear-sampling/ +/* A version for MasterEffect Reborn, a standalone version, and a custom shader version for SweetFX can be + found at http://reshade.me/forum/shader-presentation/27-gaussian-blur-bloom-unsharpmask */ + /*-----------------------------------------------------------. +/ Gaussian Blur settings / +'-----------------------------------------------------------*/ + +#define VW 1.00 + +#if defined(VERTEX) + +#if __VERSION__ >= 130 +#define COMPAT_VARYING out +#define COMPAT_ATTRIBUTE in +#define COMPAT_TEXTURE texture +#else +#define COMPAT_VARYING varying +#define COMPAT_ATTRIBUTE attribute +#define COMPAT_TEXTURE texture2D +#endif + +#ifdef GL_ES +#define COMPAT_PRECISION mediump +#else +#define COMPAT_PRECISION +#endif + +COMPAT_ATTRIBUTE vec4 VertexCoord; +COMPAT_ATTRIBUTE vec4 COLOR; +COMPAT_ATTRIBUTE vec4 TexCoord; +COMPAT_VARYING vec4 COL0; +COMPAT_VARYING vec4 TEX0; +// out variables go here as COMPAT_VARYING whatever + +vec4 _oPosition1; +uniform mat4 MVPMatrix; +uniform COMPAT_PRECISION int FrameDirection; +uniform COMPAT_PRECISION int FrameCount; +uniform COMPAT_PRECISION vec2 OutputSize; +uniform COMPAT_PRECISION vec2 TextureSize; +uniform COMPAT_PRECISION vec2 InputSize; + +void main() +{ + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; +// gl_Position = MVPMatrix * VertexCoord; + COL0 = COLOR; + TEX0.xy = gl_MultiTexCoord0.xy; +// TEX0.xy = TexCoord.xy; +} + +#elif defined(FRAGMENT) + +#if __VERSION__ >= 130 +#define COMPAT_VARYING in +#define COMPAT_TEXTURE texture +out vec4 FragColor; +#else +#define COMPAT_VARYING varying +#define FragColor gl_FragColor +#define COMPAT_TEXTURE texture2D +#endif + +#ifdef GL_ES +#ifdef GL_FRAGMENT_PRECISION_HIGH +precision highp float; +#else +precision mediump float; +#endif +#define COMPAT_PRECISION mediump +#else +#define COMPAT_PRECISION +#endif + +uniform COMPAT_PRECISION int FrameDirection; +uniform COMPAT_PRECISION int FrameCount; +uniform COMPAT_PRECISION vec2 OutputSize; +uniform COMPAT_PRECISION vec2 TextureSize; +uniform COMPAT_PRECISION vec2 InputSize; +uniform sampler2D Texture; +COMPAT_VARYING vec4 TEX0; + +// compatibility #defines +#define Source Texture +#define vTexCoord TEX0.xy + +#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize +#define outsize vec4(OutputSize, 1.0 / OutputSize) + +void main() +{ + vec2 texcoord = vTexCoord; +// vec2 PIXEL_SIZE = SourceSize.zw; + vec2 PIXEL_SIZE = vec2(SourceSize.z, SourceSize.w); +#if __VERSION__ < 130 + float sampleOffsets1 = 0.0; + float sampleOffsets2 = 1.4347826; + float sampleOffsets3 = 3.3478260; + float sampleOffsets4 = 5.2608695; + float sampleOffsets5 = 7.1739130; + + float sampleWeights1 = 0.16818994; + float sampleWeights2 = 0.27276957; + float sampleWeights3 = 0.11690125; + float sampleWeights4 = 0.024067905; + float sampleWeights5 = 0.0021112196; + + vec4 color = COMPAT_TEXTURE(Source, texcoord) * sampleWeights1; + +// unroll the loop + color += COMPAT_TEXTURE(Source, texcoord + vec2(0.0, sampleOffsets2* VW * PIXEL_SIZE.y)) * sampleWeights2; + color += COMPAT_TEXTURE(Source, texcoord - vec2(0.0, sampleOffsets2* VW * PIXEL_SIZE.y)) * sampleWeights2; + + color += COMPAT_TEXTURE(Source, texcoord + vec2(0.0, sampleOffsets3* VW * PIXEL_SIZE.y)) * sampleWeights3; + color += COMPAT_TEXTURE(Source, texcoord - vec2(0.0, sampleOffsets3* VW * PIXEL_SIZE.y)) * sampleWeights3; + + color += COMPAT_TEXTURE(Source, texcoord + vec2(0.0, sampleOffsets4* VW * PIXEL_SIZE.y)) * sampleWeights4; + color += COMPAT_TEXTURE(Source, texcoord - vec2(0.0, sampleOffsets4* VW * PIXEL_SIZE.y)) * sampleWeights4; + + color += COMPAT_TEXTURE(Source, texcoord + vec2(0.0, sampleOffsets5* VW * PIXEL_SIZE.y)) * sampleWeights5; + color += COMPAT_TEXTURE(Source, texcoord - vec2(0.0, sampleOffsets5* VW * PIXEL_SIZE.y)) * sampleWeights5; +#else + + float sampleOffsets[5] = { 0.0, 1.4347826, 3.3478260, 5.2608695, 7.1739130 }; + float sampleWeights[5] = { 0.16818994, 0.27276957, 0.11690125, 0.024067905, 0.0021112196 }; + + vec4 color = COMPAT_TEXTURE(Source, texcoord) * sampleWeights[0]; + for(int i = 1; i < 5; ++i) { + color += COMPAT_TEXTURE(Source, texcoord + vec2(0.0, sampleOffsets[i]*VW * PIXEL_SIZE.y)) * sampleWeights[i]; + color += COMPAT_TEXTURE(Source, texcoord - vec2(0.0, sampleOffsets[i]*VW * PIXEL_SIZE.y)) * sampleWeights[i]; + } +#endif + + FragColor = vec4(color); +} +#endif diff --git a/resources/shaders/glsl/desaturate.glsl b/resources/shaders/glsl/desaturate.glsl index 83ce046c7..267918ad8 100644 --- a/resources/shaders/glsl/desaturate.glsl +++ b/resources/shaders/glsl/desaturate.glsl @@ -2,34 +2,30 @@ // desaturate.glsl // // Desaturates textures such as game images. -// The uniform variable 'shaderFloat_0' sets the saturation intensity. +// The uniform variable 'saturation' sets the saturation intensity. // Setting this to the value 0 results in complete desaturation (grayscale). // -// Vertex section of code: -// ----------------------- #if defined(VERTEX) +// Vertex section of code: varying vec2 vTexCoord; void main(void) { - vTexCoord = gl_MultiTexCoord0.xy; - gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; + vTexCoord = gl_MultiTexCoord0.xy; + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; } -#endif +#elif defined(FRAGMENT) // Fragment section of code: -// ------------------------- -#ifdef FRAGMENT -uniform float shaderFloat_0 = 1.0; +uniform float saturation = 1.0; uniform sampler2D myTexture; varying vec2 vTexCoord; void main() { - float saturation = shaderFloat_0; vec4 color = texture2D(myTexture, vTexCoord); vec3 grayscale = vec3(dot(color.rgb, vec3(0.2125, 0.7154, 0.0721))); diff --git a/resources/shaders/glsl/scanlines.glsl b/resources/shaders/glsl/scanlines.glsl new file mode 100644 index 000000000..07537eae9 --- /dev/null +++ b/resources/shaders/glsl/scanlines.glsl @@ -0,0 +1,208 @@ +/* + Phosphor shader - Copyright (C) 2011 caligari. + + Ported by Hyllian. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +// Parameter lines go here: +// 0.5 = the spot stays inside the original pixel +// 1.0 = the spot bleeds up to the center of next pixel +#pragma parameter SPOT_WIDTH "CRTCaligari Spot Width" 0.9 0.1 1.5 0.05 +#pragma parameter SPOT_HEIGHT "CRTCaligari Spot Height" 0.75 0.1 1.5 0.05 +// Used to counteract the desaturation effect of weighting. +#pragma parameter COLOR_BOOST "CRTCaligari Color Boost" 1.45 1.0 2.0 0.05 +// Constants used with gamma correction. +#pragma parameter InputGamma "CRTCaligari Input Gamma" 2.4 0.0 5.0 0.1 +#pragma parameter OutputGamma "CRTCaligari Output Gamma" 2.2 0.0 5.0 0.1 + +#if defined(VERTEX) + +#if __VERSION__ >= 130 +#define COMPAT_VARYING out +#define COMPAT_ATTRIBUTE in +#define COMPAT_TEXTURE texture +#else +#define COMPAT_VARYING varying +#define COMPAT_ATTRIBUTE attribute +#define COMPAT_TEXTURE texture2D +#endif + +#ifdef GL_ES +#define COMPAT_PRECISION mediump +#else +#define COMPAT_PRECISION +#endif + +COMPAT_ATTRIBUTE vec4 VertexCoord; +COMPAT_ATTRIBUTE vec4 COLOR; +COMPAT_ATTRIBUTE vec4 TexCoord; +COMPAT_VARYING vec4 COL0; +COMPAT_VARYING vec4 TEX0; +COMPAT_VARYING vec2 onex; +COMPAT_VARYING vec2 oney; + +vec4 _oPosition1; +uniform mat4 MVPMatrix; +uniform COMPAT_PRECISION int FrameDirection; +uniform COMPAT_PRECISION int FrameCount; +uniform COMPAT_PRECISION vec2 OutputSize; +uniform COMPAT_PRECISION vec2 TextureSize; +uniform COMPAT_PRECISION vec2 InputSize; + +#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize + +void main() +{ + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; +// gl_Position = MVPMatrix * VertexCoord; + COL0 = COLOR; + TEX0.xy = gl_MultiTexCoord0.xy; +// TEX0.xy = TexCoord.xy; + onex = vec2(SourceSize.z, 0.0); + oney = vec2(0.0, SourceSize.w); +} + +#elif defined(FRAGMENT) + +#if __VERSION__ >= 130 +#define COMPAT_VARYING in +#define COMPAT_TEXTURE texture +out vec4 FragColor; +#else +#define COMPAT_VARYING varying +#define FragColor gl_FragColor +#define COMPAT_TEXTURE texture2D +#endif + +#ifdef GL_ES +#ifdef GL_FRAGMENT_PRECISION_HIGH +precision highp float; +#else +precision mediump float; +#endif +#define COMPAT_PRECISION mediump +#else +#define COMPAT_PRECISION +#endif + +uniform COMPAT_PRECISION int FrameDirection; +uniform COMPAT_PRECISION int FrameCount; +uniform COMPAT_PRECISION vec2 OutputSize; +uniform COMPAT_PRECISION vec2 TextureSize; +uniform COMPAT_PRECISION vec2 InputSize; +uniform sampler2D Texture; +COMPAT_VARYING vec4 TEX0; +COMPAT_VARYING vec2 onex; +COMPAT_VARYING vec2 oney; + +// compatibility #defines +#define Source Texture +#define vTexCoord TEX0.xy + +#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize +#define OutputSize vec4(OutputSize, 1.0 / OutputSize) + +#ifdef PARAMETER_UNIFORM +// All parameter floats need to have COMPAT_PRECISION in front of them +uniform COMPAT_PRECISION float SPOT_WIDTH; +uniform COMPAT_PRECISION float SPOT_HEIGHT; +uniform COMPAT_PRECISION float COLOR_BOOST; +uniform COMPAT_PRECISION float InputGamma; +uniform COMPAT_PRECISION float OutputGamma; +#else +#define SPOT_WIDTH 0.9 +#define SPOT_HEIGHT 0.75 +#define COLOR_BOOST 1.45 +#define InputGamma 2.4 +#define OutputGamma 2.2 +#endif + +#define GAMMA_IN(color) pow(color,vec4(InputGamma)) +#define GAMMA_OUT(color) pow(color, vec4(1.0 / OutputGamma)) + +#define TEX2D(coords) GAMMA_IN( COMPAT_TEXTURE(Source, coords) ) + +// Macro for weights computing +#define WEIGHT(w) \ + if(w>1.0) w=1.0; \ +w = 1.0 - w * w; \ +w = w * w; + +void main() +{ + vec2 coords = ( vTexCoord * SourceSize.xy ); + vec2 pixel_center = floor( coords ) + vec2(0.5, 0.5); + vec2 texture_coords = pixel_center * SourceSize.zw; + + vec4 color = TEX2D( texture_coords ); + + float dx = coords.x - pixel_center.x; + + float h_weight_00 = dx / SPOT_WIDTH; + WEIGHT( h_weight_00 ); + + color *= vec4( h_weight_00, h_weight_00, h_weight_00, h_weight_00 ); + + // get closest horizontal neighbour to blend + vec2 coords01; + if (dx>0.0) { + coords01 = onex; + dx = 1.0 - dx; + } else { + coords01 = -onex; + dx = 1.0 + dx; + } + vec4 colorNB = TEX2D( texture_coords + coords01 ); + + float h_weight_01 = dx / SPOT_WIDTH; + WEIGHT( h_weight_01 ); + + color = color + colorNB * vec4( h_weight_01 ); + + ////////////////////////////////////////////////////// + // Vertical Blending + float dy = coords.y - pixel_center.y; + float v_weight_00 = dy / SPOT_HEIGHT; + WEIGHT( v_weight_00 ); + color *= vec4( v_weight_00 ); + + // get closest vertical neighbour to blend + vec2 coords10; + if (dy>0.0) { + coords10 = oney; + dy = 1.0 - dy; + } else { + coords10 = -oney; + dy = 1.0 + dy; + } + colorNB = TEX2D( texture_coords + coords10 ); + + float v_weight_10 = dy / SPOT_HEIGHT; + WEIGHT( v_weight_10 ); + + color = color + colorNB * vec4( v_weight_10 * h_weight_00, v_weight_10 * h_weight_00, v_weight_10 * h_weight_00, v_weight_10 * h_weight_00 ); + + colorNB = TEX2D( texture_coords + coords01 + coords10 ); + + color = color + colorNB * vec4( v_weight_10 * h_weight_01, v_weight_10 * h_weight_01, v_weight_10 * h_weight_01, v_weight_10 * h_weight_01 ); + + color *= vec4( COLOR_BOOST ); + + FragColor = clamp( GAMMA_OUT(color), 0.0, 1.0 ); +} +#endif