diff --git a/CMakeLists.txt b/CMakeLists.txt index 04f3c06..d875826 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -216,12 +216,15 @@ set(EMBEDDED_INPUT shader/hue.frag shader/sprite.frag shader/plane.frag + shader/gray.frag shader/bitmapBlit.frag + shader/flatColor.frag shader/simple.frag shader/simpleColor.frag shader/simpleAlpha.frag shader/simpleAlphaUni.frag shader/flashMap.frag + shader/minimal.vert shader/simple.vert shader/simpleColor.vert shader/sprite.vert diff --git a/mkxp.pro b/mkxp.pro index f223482..558727a 100644 --- a/mkxp.pro +++ b/mkxp.pro @@ -189,12 +189,15 @@ EMBED = \ shader/hue.frag \ shader/sprite.frag \ shader/plane.frag \ + shader/gray.frag \ shader/bitmapBlit.frag \ + shader/flatColor.frag \ shader/simple.frag \ shader/simpleColor.frag \ shader/simpleAlpha.frag \ shader/simpleAlphaUni.frag \ shader/flashMap.frag \ + shader/minimal.vert \ shader/simple.vert \ shader/simpleColor.vert \ shader/sprite.vert \ diff --git a/shader/flatColor.frag b/shader/flatColor.frag new file mode 100644 index 0000000..985f5dc --- /dev/null +++ b/shader/flatColor.frag @@ -0,0 +1,7 @@ + +uniform lowp vec4 color; + +void main() +{ + gl_FragColor = color; +} diff --git a/shader/gray.frag b/shader/gray.frag new file mode 100644 index 0000000..c4cb982 --- /dev/null +++ b/shader/gray.frag @@ -0,0 +1,19 @@ + +uniform sampler2D texture; +uniform lowp float gray; + +varying vec2 v_texCoord; + +const vec3 lumaF = vec3(.299, .587, .114); + +void main() +{ + /* Sample source color */ + vec4 frag = texture2D(texture, v_texCoord); + + /* Apply gray */ + float luma = dot(frag.rgb, lumaF); + frag.rgb = mix(frag.rgb, vec3(luma), gray); + + gl_FragColor = frag; +} diff --git a/shader/minimal.vert b/shader/minimal.vert new file mode 100644 index 0000000..cccadc1 --- /dev/null +++ b/shader/minimal.vert @@ -0,0 +1,8 @@ + +uniform mat4 projMat; +attribute vec2 position; + +void main() +{ + gl_Position = projMat * vec4(position, 0, 1); +} diff --git a/src/etc-internal.h b/src/etc-internal.h index 2d3e547..0b4624c 100644 --- a/src/etc-internal.h +++ b/src/etc-internal.h @@ -60,6 +60,11 @@ struct Vec4 { return (x == other.x && y == other.y && z == other.z && w == other.w); } + + bool xyzHasEffect() const + { + return (x != 0.0 || y != 0.0 || z != 0.0); + } }; struct Vec2i @@ -129,6 +134,14 @@ struct IntRect : SDL_Rect SDL_Rect r = { x, y, w, h }; return r; } + + bool encloses(const IntRect &o) const + { + return (x <= o.x && + y <= o.y && + x+w >= o.x+o.w && + y+h >= o.y+o.h); + } }; struct StaticRect { float x, y, w, h; }; diff --git a/src/graphics.cpp b/src/graphics.cpp index ecf850f..5537b03 100644 --- a/src/graphics.cpp +++ b/src/graphics.cpp @@ -171,36 +171,112 @@ public: void requestViewportRender(Vec4 &c, Vec4 &f, Vec4 &t) { - pp.swapRender(); + const IntRect &viewpRect = glState.scissorBox.get(); + const IntRect &screenRect = geometry.rect; - /* Scissor test _does_ affect FBO blit operations, - * and since we're inside the draw cycle, it will - * be turned on, so turn it off temporarily */ - glState.scissorTest.pushSet(false); + if (t.w != 0.0) + { + pp.swapRender(); - GLMeta::blitBegin(pp.frontBuffer()); - GLMeta::blitSource(pp.backBuffer()); - GLMeta::blitRectangle(geometry.rect, Vec2i()); - GLMeta::blitEnd(); + if (!viewpRect.encloses(screenRect)) + { + /* Scissor test _does_ affect FBO blit operations, + * and since we're inside the draw cycle, it will + * be turned on, so turn it off temporarily */ + glState.scissorTest.pushSet(false); - glState.scissorTest.pop(); + GLMeta::blitBegin(pp.frontBuffer()); + GLMeta::blitSource(pp.backBuffer()); + GLMeta::blitRectangle(geometry.rect, Vec2i()); + GLMeta::blitEnd(); - PlaneShader &shader = shState->shaders().plane; + glState.scissorTest.pop(); + } + + GrayShader &shader = shState->shaders().gray; + shader.bind(); + shader.setGray(t.w); + shader.applyViewportProj(); + shader.setTexSize(screenRect.size()); + + TEX::bind(pp.backBuffer().tex); + + glState.blend.pushSet(false); + screenQuad.draw(); + glState.blend.pop(); + } + + bool toneEffect = t.xyzHasEffect(); + bool colorEffect = c.xyzHasEffect(); + bool flashEffect = f.xyzHasEffect(); + + if (!toneEffect && !colorEffect && !flashEffect) + return; + + FlatColorShader &shader = shState->shaders().flatColor; shader.bind(); - shader.setColor(c); - shader.setFlash(f); - shader.setTone(t); - shader.setOpacity(1.0); shader.applyViewportProj(); - shader.setTexSize(geometry.rect.size()); - TEX::bind(pp.backBuffer().tex); + /* Apply tone */ + if (toneEffect) + { + /* First split up additive / substractive components */ + Vec4 add, sub; - glState.blend.pushSet(false); + if (t.x > 0) + add.x = t.x; + if (t.y > 0) + add.y = t.y; + if (t.z > 0) + add.z = t.z; - screenQuad.draw(); + if (t.x < 0) + sub.x = -t.x; + if (t.y < 0) + sub.y = -t.y; + if (t.z < 0) + sub.z = -t.z; - glState.blend.pop(); + /* Then apply them using hardware blending */ + gl.BlendFuncSeparate(GL_ONE, GL_ONE, GL_ZERO, GL_ONE); + + if (add.xyzHasEffect()) + { + gl.BlendEquation(GL_FUNC_ADD); + shader.setColor(add); + + screenQuad.draw(); + } + + if (sub.xyzHasEffect()) + { + gl.BlendEquation(GL_FUNC_REVERSE_SUBTRACT); + shader.setColor(sub); + + screenQuad.draw(); + } + } + + if (colorEffect || flashEffect) + { + gl.BlendEquation(GL_FUNC_ADD); + gl.BlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, + GL_ZERO, GL_ONE); + } + + if (colorEffect) + { + shader.setColor(c); + screenQuad.draw(); + } + + if (flashEffect) + { + shader.setColor(f); + screenQuad.draw(); + } + + glState.blendMode.refresh(); } void setBrightness(float norm) diff --git a/src/shader.cpp b/src/shader.cpp index 4f891f2..3b22483 100644 --- a/src/shader.cpp +++ b/src/shader.cpp @@ -35,11 +35,14 @@ #include "transSimple.frag.xxd" #include "bitmapBlit.frag.xxd" #include "plane.frag.xxd" +#include "gray.frag.xxd" +#include "flatColor.frag.xxd" #include "simple.frag.xxd" #include "simpleColor.frag.xxd" #include "simpleAlpha.frag.xxd" #include "simpleAlphaUni.frag.xxd" #include "flashMap.frag.xxd" +#include "minimal.vert.xxd" #include "simple.vert.xxd" #include "simpleColor.vert.xxd" #include "sprite.vert.xxd" @@ -269,6 +272,21 @@ void ShaderBase::setTranslation(const Vec2i &value) } +FlatColorShader::FlatColorShader() +{ + INIT_SHADER(minimal, flatColor, FlatColorShader); + + ShaderBase::init(); + + GET_U(color); +} + +void FlatColorShader::setColor(const Vec4 &value) +{ + setVec4Uniform(u_color, value); +} + + SimpleShader::SimpleShader() { INIT_SHADER(simple, simple, SimpleShader); @@ -480,6 +498,21 @@ void PlaneShader::setOpacity(float value) } +GrayShader::GrayShader() +{ + INIT_SHADER(simple, gray, GrayShader); + + ShaderBase::init(); + + GET_U(gray); +} + +void GrayShader::setGray(float value) +{ + gl.Uniform1f(u_gray, value); +} + + TilemapShader::TilemapShader() { INIT_SHADER(tilemap, simple, TilemapShader); diff --git a/src/shader.h b/src/shader.h index 96a6e3b..323b10a 100644 --- a/src/shader.h +++ b/src/shader.h @@ -87,6 +87,17 @@ protected: GLint u_texSizeInv, u_translation; }; +class FlatColorShader : public ShaderBase +{ +public: + FlatColorShader(); + + void setColor(const Vec4 &value); + +private: + GLint u_color; +}; + class SimpleShader : public ShaderBase { public: @@ -191,6 +202,17 @@ private: GLint u_tone, u_color, u_flash, u_opacity; }; +class GrayShader : public ShaderBase +{ +public: + GrayShader(); + + void setGray(float value); + +private: + GLint u_gray; +}; + class TilemapShader : public ShaderBase { public: @@ -285,6 +307,7 @@ private: /* Global object containing all available shaders */ struct ShaderSet { + FlatColorShader flatColor; SimpleShader simple; SimpleColorShader simpleColor; SimpleAlphaShader simpleAlpha; @@ -292,6 +315,7 @@ struct ShaderSet AlphaSpriteShader alphaSprite; SpriteShader sprite; PlaneShader plane; + GrayShader gray; TilemapShader tilemap; FlashMapShader flashMap; TransShader trans;