diff --git a/modules/juce_opengl/juce_opengl.cpp b/modules/juce_opengl/juce_opengl.cpp index 8ff4f75aa5..266667dccc 100644 --- a/modules/juce_opengl/juce_opengl.cpp +++ b/modules/juce_opengl/juce_opengl.cpp @@ -104,14 +104,6 @@ void OpenGLExtensionFunctions::initialise() #undef JUCE_GL_EXTENSION_FUNCTIONS -#if JUCE_OPENGL_ES - #define JUCE_MEDIUMP "mediump" - #define JUCE_HIGHP "highp" -#else - #define JUCE_MEDIUMP - #define JUCE_HIGHP -#endif - #if JUCE_DEBUG && ! defined (JUCE_CHECK_OPENGL_ERROR) static const char* getGLErrorMessage (const GLenum e) { diff --git a/modules/juce_opengl/juce_opengl.h b/modules/juce_opengl/juce_opengl.h index d380ecb22d..d805383a9b 100644 --- a/modules/juce_opengl/juce_opengl.h +++ b/modules/juce_opengl/juce_opengl.h @@ -64,6 +64,31 @@ #include #endif +//============================================================================= +#if JUCE_OPENGL_ES || defined (DOXYGEN) + /** This macro is a helper for use in GLSL shader code which needs to compile on both GLES and desktop GL. + Since it's mandatory in GLES to mark a variable with a precision, but the keywords don't exist in normal GLSL, + these macros define the various precision keywords only on GLES. + */ + #define JUCE_MEDIUMP "mediump" + + /** This macro is a helper for use in GLSL shader code which needs to compile on both GLES and desktop GL. + Since it's mandatory in GLES to mark a variable with a precision, but the keywords don't exist in normal GLSL, + these macros define the various precision keywords only on GLES. + */ + #define JUCE_HIGHP "highp" + + /** This macro is a helper for use in GLSL shader code which needs to compile on both GLES and desktop GL. + Since it's mandatory in GLES to mark a variable with a precision, but the keywords don't exist in normal GLSL, + these macros define the various precision keywords only on GLES. + */ + #define JUCE_LOWP "lowp" +#else + #define JUCE_MEDIUMP + #define JUCE_HIGHP + #define JUCE_LOWP +#endif + //============================================================================= namespace juce { diff --git a/modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.cpp b/modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.cpp index d38d802675..afd0e38ae2 100644 --- a/modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.cpp +++ b/modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.cpp @@ -1631,6 +1631,13 @@ public: state->shaderQuadQueue.add (iter, fillType.colour.getPixelARGB()); } + void fillRectWithCustomShader (OpenGLRendering::ShaderPrograms::ShaderBase& shader, const Rectangle& area, Colour colour) + { + state->setShader (shader); + state->shaderQuadQueue.add (area, colour.getPixelARGB()); + state->currentShader.clearShader (state->shaderQuadQueue); + } + //============================================================================== Font font; GLState* state; @@ -1644,7 +1651,7 @@ private: //============================================================================== -class ShaderContext : public RenderingHelpers::StackBasedLowLevelGraphicsContext +class ShaderContext : public RenderingHelpers::StackBasedLowLevelGraphicsContext { public: ShaderContext (const Target& target) : glState (target) @@ -1652,7 +1659,11 @@ public: stack.initialise (new SavedState (&glState)); } -private: + void fillRectWithCustomShader (ShaderPrograms::ShaderBase& shader, const Rectangle& area, Colour colour) + { + static_cast (*stack).fillRectWithCustomShader (shader, area, colour); + } + GLState glState; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ShaderContext) @@ -1736,3 +1747,42 @@ void clearOpenGLGlyphCache() { OpenGLRendering::SavedState::GlyphCacheType::getInstance().reset(); } + + +//============================================================================== +struct OpenGLGraphicsContextCustomShader::Pimpl : public OpenGLRendering::ShaderPrograms::ShaderBase +{ + Pimpl (OpenGLRendering::ShaderContext& c, const String& fragmentShader) + : ShaderBase (c.glState.target.context, fragmentShader.toRawUTF8()) + { + } + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl) +}; + +OpenGLGraphicsContextCustomShader::OpenGLGraphicsContextCustomShader (Pimpl* p) : pimpl (p) {} +OpenGLGraphicsContextCustomShader::~OpenGLGraphicsContextCustomShader() {} + +OpenGLGraphicsContextCustomShader* OpenGLGraphicsContextCustomShader::create (LowLevelGraphicsContext& gc, StringRef fragmentShaderCode) +{ + if (OpenGLRendering::ShaderContext* sc = dynamic_cast (&gc)) + { + ScopedPointer p (new Pimpl (*sc, String (JUCE_DECLARE_VARYING_COLOUR JUCE_DECLARE_VARYING_PIXELPOS "\n") + fragmentShaderCode)); + + if (! p->program.isLinked()) + return nullptr; + + return new OpenGLGraphicsContextCustomShader (p.release()); + } + + jassertfalse; // You've passed-in a non-GL context! + return nullptr; +} + +void OpenGLGraphicsContextCustomShader::fillRect (LowLevelGraphicsContext& gc, const Rectangle& area, Colour colour) const +{ + jassert (pimpl != nullptr); + + if (OpenGLRendering::ShaderContext* sc = dynamic_cast (&gc)) + sc->fillRectWithCustomShader (*pimpl, area, colour); +} diff --git a/modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.h b/modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.h index 5f01bf9bd0..c087d81b64 100644 --- a/modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.h +++ b/modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.h @@ -46,4 +46,45 @@ LowLevelGraphicsContext* createOpenGLGraphicsContext (OpenGLContext& context, int width, int height); +//============================================================================== +/** + Used to create custom shaders for use with an openGL 2D rendering context. + + Given a GL-based rendering context, you can write a fragment shader that applies some + kind of per-pixel effect. +*/ +struct JUCE_API OpenGLGraphicsContextCustomShader +{ + /** Destructor. */ + ~OpenGLGraphicsContextCustomShader(); + + /** Attempts to compile and return a new shader object. + This must be called only when an openGL context is active. It'll return nullptr + if the code fails to compile or some other error occurs. + + The shader code should be a normal fragment shader. As well as the usual variables, there + will be some extra ones: "frontColour", which is the colour that gets passed into the fillRect + method, and "pixelPos", which is a vec2 indicating the pixel position within the graphics context + of the pixel being drawn. + */ + static OpenGLGraphicsContextCustomShader* create (LowLevelGraphicsContext&, + StringRef fragmentShaderCode); + + /** Applies the shader to a rectangle within the graphics context. + NB: This will ignore any clip region that is active. + */ + void fillRect (LowLevelGraphicsContext&, const Rectangle& area, Colour colour) const; + +private: + struct Pimpl; + friend struct Pimpl; + friend struct ContainerDeletePolicy; + ScopedPointer pimpl; + + OpenGLGraphicsContextCustomShader (Pimpl*); + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLGraphicsContextCustomShader) +}; + + #endif // JUCE_OPENGLGRAPHICSCONTEXT_H_INCLUDED diff --git a/modules/juce_opengl/opengl/juce_OpenGLShaderProgram.h b/modules/juce_opengl/opengl/juce_OpenGLShaderProgram.h index 2113c34e09..17d0f258de 100644 --- a/modules/juce_opengl/opengl/juce_OpenGLShaderProgram.h +++ b/modules/juce_opengl/opengl/juce_OpenGLShaderProgram.h @@ -80,7 +80,10 @@ public: bool link() noexcept; /** Get the output for the last shader compilation or link that failed. */ - const String& getLastError() const noexcept { return errorLog; } + const String& getLastError() const noexcept { return errorLog; } + + /** Returns true if the program is linked and ready for use. */ + bool isLinked() const noexcept { return programID != 0; } /** Selects this program into the current context. */ void use() const noexcept;