diff --git a/BREAKING-CHANGES.txt b/BREAKING-CHANGES.txt index d2f7c04e75..edbdf6aef9 100644 --- a/BREAKING-CHANGES.txt +++ b/BREAKING-CHANGES.txt @@ -4,6 +4,31 @@ JUCE breaking changes develop ======= +Change +------ +The implementation of ColourGradient::createLookupTable has been updated to use +non-premultiplied colours. + +Possible Issues +--------------- +Programs that draw transparent gradients using the OpenGL or software +renderers, or that use lookup tables generated from transparent gradients for +other purposes, may now produce different results. + +Workaround +---------- +For gradients to render the same as they did previously, transparent colour +stops should be un-premultiplied. For colours with an alpha component of 0, it +may be necessary to specify appropriate RGB components. + +Rationale +--------- +Previously, transparent gradients rendered using CoreGraphics looked different +to the same gradients drawn using OpenGL or the software renderer. This change +updates the OpenGL and software renderers, so that they produce the same +results as CoreGraphics. + + Change ------ Projucer-generated MSVC projects now build VST3s as bundles, rather than as diff --git a/modules/juce_graphics/colour/juce_Colour.cpp b/modules/juce_graphics/colour/juce_Colour.cpp index 38d2d8b04f..572084c3dc 100644 --- a/modules/juce_graphics/colour/juce_Colour.cpp +++ b/modules/juce_graphics/colour/juce_Colour.cpp @@ -291,13 +291,18 @@ Colour::Colour (PixelAlpha alpha) noexcept } //============================================================================== -const PixelARGB Colour::getPixelARGB() const noexcept +PixelARGB Colour::getPixelARGB() const noexcept { PixelARGB p (argb); p.premultiply(); return p; } +PixelARGB Colour::getNonPremultipliedPixelARGB() const noexcept +{ + return argb; +} + uint32 Colour::getARGB() const noexcept { return argb.getInARGBMaskOrder(); diff --git a/modules/juce_graphics/colour/juce_Colour.h b/modules/juce_graphics/colour/juce_Colour.h index 3077addde6..2e1e4ee3d0 100644 --- a/modules/juce_graphics/colour/juce_Colour.h +++ b/modules/juce_graphics/colour/juce_Colour.h @@ -194,7 +194,11 @@ public: /** Returns a premultiplied ARGB pixel object that represents this colour. */ - const PixelARGB getPixelARGB() const noexcept; + PixelARGB getPixelARGB() const noexcept; + + /** Returns an ARGB pixel object that represents this colour. + */ + PixelARGB getNonPremultipliedPixelARGB() const noexcept; /** Returns a 32-bit integer that represents this colour. diff --git a/modules/juce_graphics/colour/juce_ColourGradient.cpp b/modules/juce_graphics/colour/juce_ColourGradient.cpp index a9dc3af681..4a5444e4ad 100644 --- a/modules/juce_graphics/colour/juce_ColourGradient.cpp +++ b/modules/juce_graphics/colour/juce_ColourGradient.cpp @@ -201,29 +201,28 @@ void ColourGradient::createLookupTable (PixelARGB* const lookupTable, const int jassert (numEntries > 0); jassert (colours.getReference(0).position == 0.0); // The first colour specified has to go at position 0 - auto pix1 = colours.getReference (0).colour.getPixelARGB(); int index = 0; - for (int j = 1; j < colours.size(); ++j) + for (int j = 0; j < colours.size() - 1; ++j) { - auto& p = colours.getReference (j); - auto numToDo = roundToInt (p.position * (numEntries - 1)) - index; - auto pix2 = p.colour.getPixelARGB(); + const auto& o = colours.getReference (j + 0); + const auto& p = colours.getReference (j + 1); + const auto numToDo = roundToInt (p.position * (numEntries - 1)) - index; + const auto pix1 = o.colour.getNonPremultipliedPixelARGB(); + const auto pix2 = p.colour.getNonPremultipliedPixelARGB(); - for (int i = 0; i < numToDo; ++i) + for (auto i = 0; i < numToDo; ++i) { - jassert (index >= 0 && index < numEntries); + auto blended = pix1; + blended.tween (pix2, (uint32) ((i << 8) / numToDo)); + blended.premultiply(); - lookupTable[index] = pix1; - lookupTable[index].tween (pix2, (uint32) ((i << 8) / numToDo)); - ++index; + jassert (0 <= index && index < numEntries); + lookupTable[index++] = blended; } - - pix1 = pix2; } - while (index < numEntries) - lookupTable [index++] = pix1; + std::fill (lookupTable + index, lookupTable + numEntries, colours.getLast().colour.getPixelARGB()); } int ColourGradient::createLookupTable (const AffineTransform& transform, HeapBlock& lookupTable) const diff --git a/modules/juce_graphics/colour/juce_ColourGradient.h b/modules/juce_graphics/colour/juce_ColourGradient.h index c38f5251f7..6a15d95f17 100644 --- a/modules/juce_graphics/colour/juce_ColourGradient.h +++ b/modules/juce_graphics/colour/juce_ColourGradient.h @@ -185,6 +185,17 @@ public: */ void createLookupTable (PixelARGB* resultLookupTable, int numEntries) const noexcept; + /** Creates a set of interpolated premultiplied ARGB values. + This will fill an array of a user-specified size with the gradient, interpolating to fit. + When calling this, the ColourGradient must have at least 2 colour stops specified. + */ + template + void createLookupTable (PixelARGB (&resultLookupTable)[NumEntries]) const noexcept + { + static_assert (NumEntries != 0); + createLookupTable (resultLookupTable, NumEntries); + } + /** Returns true if all colours are opaque. */ bool isOpaque() const noexcept; diff --git a/modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.cpp b/modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.cpp index 1ec0f17fc7..38074a69bc 100644 --- a/modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.cpp +++ b/modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.cpp @@ -1139,7 +1139,7 @@ struct StateHelpers JUCE_CHECK_OPENGL_ERROR; PixelARGB lookup[gradientTextureSize]; - gradient.createLookupTable (lookup, gradientTextureSize); + gradient.createLookupTable (lookup); gradientTextures.getUnchecked (activeGradientIndex)->loadARGB (lookup, gradientTextureSize, 1); }