diff --git a/modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.cpp b/modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.cpp index 9034df75bc..f929bd9724 100644 --- a/modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.cpp +++ b/modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.cpp @@ -177,6 +177,7 @@ public: GLuint textureID; Rectangle area, clip; +private: struct EdgeTableData { EdgeTableData (const EdgeTable& et) @@ -285,10 +286,8 @@ namespace void fillRectangleList (const RectangleList& list) { - glEnableClientState (GL_VERTEX_ARRAY); - glDisableClientState (GL_TEXTURE_COORD_ARRAY); - GLfloat vertices [8]; + glEnableClientState (GL_VERTEX_ARRAY); glVertexPointer (2, GL_FLOAT, 0, vertices); for (RectangleList::Iterator i (list); i.next();) @@ -302,6 +301,24 @@ namespace } } + void fillRectangleList (const RectangleList& list, const Rectangle& clip) + { + GLfloat vertices [8]; + glEnableClientState (GL_VERTEX_ARRAY); + glVertexPointer (2, GL_FLOAT, 0, vertices); + + for (RectangleList::Iterator i (list); i.next();) + { + const Rectangle r (i.getRectangle()->getIntersection (clip)); + vertices[0] = vertices[4] = (GLfloat) r.getX(); + vertices[1] = vertices[3] = (GLfloat) r.getY(); + vertices[2] = vertices[6] = (GLfloat) r.getRight(); + vertices[5] = vertices[7] = (GLfloat) r.getBottom(); + + glDrawArrays (GL_TRIANGLE_STRIP, 0, 4); + } + } + inline void setColour (const float alpha) noexcept { glColor4f (alpha, alpha, alpha, alpha); @@ -698,6 +715,123 @@ namespace mask1, mask2, replaceExistingContents, true); } } + + //============================================================================== + struct VariableAlphaColour + { + VariableAlphaColour (const Colour& c) noexcept + : r (c.getFloatRed()), g (c.getFloatGreen()), b (c.getFloatBlue()), + alphaScale (c.getFloatAlpha() / 255.0f), lastAlpha (-1) + {} + + void setForAlpha (const int alpha) noexcept + { + if (lastAlpha != alpha) + { + lastAlpha = alpha; + const float a = alpha * alphaScale; + glColor4f (r * a, g * a, b * a, a); + } + } + + private: + const float r, g, b, alphaScale; + int lastAlpha; + + JUCE_DECLARE_NON_COPYABLE (VariableAlphaColour); + }; + + //============================================================================== + struct EdgeTableRenderer + { + EdgeTableRenderer (const Colour& c) noexcept + : colour (c) + {} + + void draw (const EdgeTable& et) + { + glDisableClientState (GL_TEXTURE_COORD_ARRAY); + glEnableClientState (GL_VERTEX_ARRAY); + glVertexPointer (2, GL_FLOAT, 0, vertices); + + et.iterate (*this); + } + + void setEdgeTableYPos (const int y) noexcept + { + vertices[1] = vertices[5] = (GLfloat) y; + vertices[3] = vertices[7] = (GLfloat) (y + 1); + } + + void handleEdgeTablePixel (const int x, const int alphaLevel) noexcept + { + drawHorizontal (x, 1, alphaLevel); + } + + void handleEdgeTablePixelFull (const int x) noexcept + { + drawHorizontal (x, 1, 255); + } + + void handleEdgeTableLine (const int x, const int width, const int alphaLevel) noexcept + { + drawHorizontal (x, width, alphaLevel); + } + + void handleEdgeTableLineFull (const int x, const int width) noexcept + { + drawHorizontal (x, width, 255); + } + + private: + GLfloat vertices[8]; + VariableAlphaColour colour; + + void drawHorizontal (int x, const int w, const int alpha) noexcept + { + vertices[0] = vertices[2] = (GLfloat) x; + vertices[4] = vertices[6] = (GLfloat) (x + w); + + colour.setForAlpha (alpha); + glDrawArrays (GL_TRIANGLE_STRIP, 0, 4); + } + + JUCE_DECLARE_NON_COPYABLE (EdgeTableRenderer); + }; + + //============================================================================== + struct FloatRectangleRenderer + { + FloatRectangleRenderer (const Colour& c) noexcept + : colour (c) + {} + + void draw (const Rectangle& r) + { + glDisableClientState (GL_TEXTURE_COORD_ARRAY); + glEnableClientState (GL_VERTEX_ARRAY); + glVertexPointer (2, GL_FLOAT, 0, vertices); + + RenderingHelpers::FloatRectangleRasterisingInfo (r).iterate (*this); + } + + void operator() (const int x, const int y, const int w, const int h, const int alpha) + { + vertices[0] = vertices[2] = (GLfloat) x; + vertices[1] = vertices[5] = (GLfloat) y; + vertices[4] = vertices[6] = (GLfloat) (x + w); + vertices[3] = vertices[7] = (GLfloat) (y + h); + + colour.setForAlpha (alpha); + glDrawArrays (GL_TRIANGLE_STRIP, 0, 4); + } + + private: + GLfloat vertices[8]; + VariableAlphaColour colour; + + JUCE_DECLARE_NON_COPYABLE (FloatRectangleRenderer); + }; } //============================================================================== @@ -722,7 +856,9 @@ public: virtual Ptr clipToTexture (const PositionedTexture&) = 0; virtual Rectangle getClipBounds() const = 0; virtual void fillRect (const OpenGLTarget&, const Rectangle& area, const FillType&, GradientTexture&, bool replaceContents) = 0; + virtual void fillRect (const OpenGLTarget&, const Rectangle& area, const FillType&, GradientTexture&) = 0; virtual void fillMask (const OpenGLTarget& target, const Rectangle& area, const PositionedTexture&, const FillType&, GradientTexture&) = 0; + virtual void fillEdgeTable (const OpenGLTarget& target, EdgeTable& et, const FillType& fill, GradientTexture& gradientTexture) = 0; virtual void drawImage (const OpenGLTarget&, const OpenGLTextureFromImage&, const AffineTransform&, float alpha, const Rectangle& clip, const PositionedTexture* mask) = 0; @@ -888,12 +1024,26 @@ public: fillRectInternal (target, r, fill, gradientTexture, false); } + void fillRect (const OpenGLTarget& target, const Rectangle& area, const FillType& fill, GradientTexture& gradientTexture) + { + EdgeTable et (area); + fillEdgeTable (target, et, fill, gradientTexture); + } + void fillMask (const OpenGLTarget& target, const Rectangle& area, const PositionedTexture& texture, const FillType& fill, GradientTexture& gradientTexture) { PositionedTexture pt (mask.getTextureID(), Rectangle (maskOrigin.x, maskOrigin.y, mask.getWidth(), mask.getHeight()), area); fillTexture (target, area, fill, gradientTexture, &texture, &pt, false); } + void fillEdgeTable (const OpenGLTarget& target, EdgeTable& et, const FillType& fill, GradientTexture& gradientTexture) + { + OpenGLTexture texture; + PositionedTexture pt (texture, et, clip); + + fillMask (target, pt.clip, pt, fill, gradientTexture); + } + void fillRectInternal (const OpenGLTarget& target, const Rectangle& area, const FillType& fill, GradientTexture& gradientTexture, bool replaceContents) { PositionedTexture pt (mask.getTextureID(), Rectangle (maskOrigin.x, maskOrigin.y, mask.getWidth(), mask.getHeight()), area); @@ -970,18 +1120,54 @@ public: Ptr clipToRectangleList (const RectangleList& r) { return clip.clipTo (r) ? this : nullptr; } Ptr excludeClipRectangle (const Rectangle& r) { clip.subtract (r); return clip.isEmpty() ? nullptr : this; } - Ptr clipToTexture (const PositionedTexture& t) { return toMask()->clipToTexture (t); } + Ptr clipToTexture (const PositionedTexture& t) { return toMask()->clipToTexture (t); } Ptr clipToPath (const Path& p, const AffineTransform& transform) { return toMask()->clipToPath (p, transform); } Ptr clipToImageAlpha (const OpenGLTextureFromImage& image, const AffineTransform& transform) { return toMask()->clipToImageAlpha (image, transform); } void fillRect (const OpenGLTarget& target, const Rectangle& area, const FillType& fill, GradientTexture& gradientTexture, bool replaceContents) { - for (RectangleList::Iterator i (clip); i.next();) + if (fill.isColour()) { - const Rectangle r (i.getRectangle()->getIntersection (area)); + disableMultiTexture(); + setBlendMode (replaceContents || fill.colour.isOpaque()); + setPremultipliedColour (fill.colour); + fillRectangleList (clip, area); + } + else + { + for (RectangleList::Iterator i (clip); i.next();) + { + const Rectangle r (i.getRectangle()->getIntersection (area)); - if (! r.isEmpty()) - fillTexture (target, r, fill, gradientTexture, nullptr, nullptr, replaceContents); + if (! r.isEmpty()) + fillTexture (target, r, fill, gradientTexture, nullptr, nullptr, replaceContents); + } + } + } + + void fillRect (const OpenGLTarget& target, const Rectangle& area, const FillType& fill, GradientTexture& gradientTexture) + { + if (fill.isColour()) + { + disableMultiTexture(); + setPremultipliedBlendingMode(); + setPremultipliedColour (fill.colour); + + for (RectangleList::Iterator i (clip); i.next();) + { + const Rectangle r (i.getRectangle()->toFloat().getIntersection (area)); + + if (! r.isEmpty()) + { + FloatRectangleRenderer frr (fill.colour); + frr.draw (r); + } + } + } + else + { + EdgeTable et (area); + fillEdgeTable (target, et, fill, gradientTexture); } } @@ -997,6 +1183,39 @@ public: } } + void fillEdgeTable (const OpenGLTarget& target, EdgeTable& et, const FillType& fill, GradientTexture& gradientTexture) + { + if (fill.isColour()) + { + setPremultipliedBlendingMode(); + disableMultiTexture (GL_TEXTURE2); + disableMultiTexture (GL_TEXTURE1); + disableMultiTexture (GL_TEXTURE0); + + for (RectangleList::Iterator i (clip); i.next();) + { + const Rectangle r (i.getRectangle()->getIntersection (et.getMaximumBounds())); + + if (! r.isEmpty()) + { + target.scissor (r); + + EdgeTableRenderer etr (fill.colour); + etr.draw (et); + } + } + + glDisable (GL_SCISSOR_TEST); + } + else + { + OpenGLTexture texture; + PositionedTexture pt (texture, et, clip.getBounds()); + + fillMask (target, pt.clip, pt, fill, gradientTexture); + } + } + void fillMask (const OpenGLTarget& target, const Rectangle& area, const PositionedTexture& texture, const FillType& fill, GradientTexture& gradientTexture) { fillTexture (target, area, fill, gradientTexture, &texture, nullptr, false); @@ -1196,10 +1415,7 @@ public: .getIntersection (clip->getClipBounds().toFloat())); if (! c.isEmpty()) - { - EdgeTable et (c); - fillEdgeTable (et); - } + clip->fillRect (target, c, getFillType(), gradientTexture); } else { @@ -1332,10 +1548,7 @@ private: void fillEdgeTable (EdgeTable& et) { - OpenGLTexture texture; - PositionedTexture pt (texture, et, clip->getClipBounds()); - - clip->fillMask (target, pt.clip, pt, getFillType(), gradientTexture); + clip->fillEdgeTable (target, et, getFillType(), gradientTexture); } class CachedGlyphEdgeTable