Browse Source

ColourGradient: Create lookup tables using non-premultiplied colours

The OpenGL renderer uses ColourGradient::createLookupTable to generate
gradient textures. However, the tweening method used was different to
the tweening used by CoreGraphics gradients, and by the software
renderer.

Gradient tweening is now computed using non-premultiplied colours, to
ensure consistency between gradients rendered using OpenGL, and with
other renderers.
v7.0.9
reuk 2 years ago
parent
commit
a59cba010b
No known key found for this signature in database GPG Key ID: FCB43929F012EE5C
6 changed files with 61 additions and 17 deletions
  1. +25
    -0
      BREAKING-CHANGES.txt
  2. +6
    -1
      modules/juce_graphics/colour/juce_Colour.cpp
  3. +5
    -1
      modules/juce_graphics/colour/juce_Colour.h
  4. +13
    -14
      modules/juce_graphics/colour/juce_ColourGradient.cpp
  5. +11
    -0
      modules/juce_graphics/colour/juce_ColourGradient.h
  6. +1
    -1
      modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.cpp

+ 25
- 0
BREAKING-CHANGES.txt View File

@@ -4,6 +4,31 @@ JUCE breaking changes
develop 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 Change
------ ------
Projucer-generated MSVC projects now build VST3s as bundles, rather than as Projucer-generated MSVC projects now build VST3s as bundles, rather than as


+ 6
- 1
modules/juce_graphics/colour/juce_Colour.cpp View File

@@ -291,13 +291,18 @@ Colour::Colour (PixelAlpha alpha) noexcept
} }
//============================================================================== //==============================================================================
const PixelARGB Colour::getPixelARGB() const noexcept
PixelARGB Colour::getPixelARGB() const noexcept
{ {
PixelARGB p (argb); PixelARGB p (argb);
p.premultiply(); p.premultiply();
return p; return p;
} }
PixelARGB Colour::getNonPremultipliedPixelARGB() const noexcept
{
return argb;
}
uint32 Colour::getARGB() const noexcept uint32 Colour::getARGB() const noexcept
{ {
return argb.getInARGBMaskOrder(); return argb.getInARGBMaskOrder();


+ 5
- 1
modules/juce_graphics/colour/juce_Colour.h View File

@@ -194,7 +194,11 @@ public:
/** Returns a premultiplied ARGB pixel object that represents this colour. /** 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. /** Returns a 32-bit integer that represents this colour.


+ 13
- 14
modules/juce_graphics/colour/juce_ColourGradient.cpp View File

@@ -201,29 +201,28 @@ void ColourGradient::createLookupTable (PixelARGB* const lookupTable, const int
jassert (numEntries > 0); jassert (numEntries > 0);
jassert (colours.getReference(0).position == 0.0); // The first colour specified has to go at position 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; 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<PixelARGB>& lookupTable) const int ColourGradient::createLookupTable (const AffineTransform& transform, HeapBlock<PixelARGB>& lookupTable) const


+ 11
- 0
modules/juce_graphics/colour/juce_ColourGradient.h View File

@@ -185,6 +185,17 @@ public:
*/ */
void createLookupTable (PixelARGB* resultLookupTable, int numEntries) const noexcept; 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 <size_t NumEntries>
void createLookupTable (PixelARGB (&resultLookupTable)[NumEntries]) const noexcept
{
static_assert (NumEntries != 0);
createLookupTable (resultLookupTable, NumEntries);
}
/** Returns true if all colours are opaque. */ /** Returns true if all colours are opaque. */
bool isOpaque() const noexcept; bool isOpaque() const noexcept;


+ 1
- 1
modules/juce_opengl/opengl/juce_OpenGLGraphicsContext.cpp View File

@@ -1139,7 +1139,7 @@ struct StateHelpers
JUCE_CHECK_OPENGL_ERROR; JUCE_CHECK_OPENGL_ERROR;
PixelARGB lookup[gradientTextureSize]; PixelARGB lookup[gradientTextureSize];
gradient.createLookupTable (lookup, gradientTextureSize);
gradient.createLookupTable (lookup);
gradientTextures.getUnchecked (activeGradientIndex)->loadARGB (lookup, gradientTextureSize, 1); gradientTextures.getUnchecked (activeGradientIndex)->loadARGB (lookup, gradientTextureSize, 1);
} }


Loading…
Cancel
Save