Browse Source

Fixes to deal with effect rendering in retina displays, e.g. drop-shadows, etc.

tags/2021-05-28
jules 13 years ago
parent
commit
ceb556876a
14 changed files with 98 additions and 62 deletions
  1. +2
    -0
      modules/juce_graphics/contexts/juce_LowLevelGraphicsContext.h
  2. +35
    -30
      modules/juce_graphics/effects/juce_DropShadowEffect.cpp
  3. +4
    -1
      modules/juce_graphics/effects/juce_DropShadowEffect.h
  4. +2
    -2
      modules/juce_graphics/effects/juce_GlowEffect.cpp
  5. +1
    -1
      modules/juce_graphics/effects/juce_GlowEffect.h
  6. +4
    -0
      modules/juce_graphics/effects/juce_ImageEffectFilter.h
  7. +3
    -1
      modules/juce_graphics/native/juce_mac_CoreGraphicsContext.h
  8. +3
    -2
      modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm
  9. +8
    -2
      modules/juce_gui_basics/components/juce_Component.cpp
  10. +24
    -11
      modules/juce_gui_basics/lookandfeel/juce_LookAndFeel.cpp
  11. +1
    -1
      modules/juce_gui_basics/lookandfeel/juce_LookAndFeel.h
  12. +1
    -1
      modules/juce_gui_basics/native/juce_ios_UIViewComponentPeer.mm
  13. +9
    -1
      modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm
  14. +1
    -9
      modules/juce_gui_basics/windows/juce_CallOutBox.cpp

+ 2
- 0
modules/juce_graphics/contexts/juce_LowLevelGraphicsContext.h View File

@@ -69,6 +69,8 @@ public:
virtual void addTransform (const AffineTransform& transform) = 0;
virtual float getScaleFactor() = 0;
virtual float getTargetDeviceScaleFactor() { return 1.0f; }
virtual bool clipToRectangle (const Rectangle<int>& r) = 0;
virtual bool clipToRectangleList (const RectangleList& clipRegion) = 0;
virtual void excludeClipRectangle (const Rectangle<int>& r) = 0;


+ 35
- 30
modules/juce_graphics/effects/juce_DropShadowEffect.cpp View File

@@ -51,52 +51,57 @@ void DropShadowEffect::setShadowProperties (const float newRadius,
opacity = newOpacity;
}
void DropShadowEffect::applyEffect (Image& image, Graphics& g, float alpha)
void DropShadowEffect::drawShadow (Graphics& g, const Image& srcImage,
float radius, float alpha, int offsetX, int offsetY)
{
const int w = image.getWidth();
const int h = image.getHeight();
const int w = srcImage.getWidth();
const int h = srcImage.getHeight();
Image shadowImage (Image::SingleChannel, w, h, false);
{
const Image::BitmapData srcData (image, Image::BitmapData::readOnly);
const Image::BitmapData destData (shadowImage, Image::BitmapData::readWrite);
const Image::BitmapData srcData (srcImage, Image::BitmapData::readOnly);
const Image::BitmapData destData (shadowImage, Image::BitmapData::readWrite);
const int filter = roundToInt (63.0f / radius);
const int radiusMinus1 = roundToInt ((radius - 1.0f) * 63.0f);
const int filter = roundToInt (63.0f / radius);
const int radiusMinus1 = roundToInt ((radius - 1.0f) * 63.0f);
for (int x = w; --x >= 0;)
{
int shadowAlpha = 0;
for (int x = w; --x >= 0;)
{
int shadowAlpha = 0;
const PixelARGB* src = ((const PixelARGB*) srcData.data) + x;
uint8* shadowPix = destData.data + x;
const PixelARGB* src = ((const PixelARGB*) srcData.data) + x;
uint8* shadowPix = destData.data + x;
for (int y = h; --y >= 0;)
{
shadowAlpha = ((shadowAlpha * radiusMinus1 + (src->getAlpha() << 6)) * filter) >> 12;
for (int y = h; --y >= 0;)
{
shadowAlpha = ((shadowAlpha * radiusMinus1 + (src->getAlpha() << 6)) * filter) >> 12;
*shadowPix = (uint8) shadowAlpha;
src = addBytesToPointer (src, srcData.lineStride);
shadowPix += destData.lineStride;
}
*shadowPix = (uint8) shadowAlpha;
src = addBytesToPointer (src, srcData.lineStride);
shadowPix += destData.lineStride;
}
}
for (int y = h; --y >= 0;)
for (int y = h; --y >= 0;)
{
int shadowAlpha = 0;
uint8* shadowPix = destData.getLinePointer (y);
for (int x = w; --x >= 0;)
{
int shadowAlpha = 0;
uint8* shadowPix = destData.getLinePointer (y);
for (int x = w; --x >= 0;)
{
shadowAlpha = ((shadowAlpha * radiusMinus1 + (*shadowPix << 6)) * filter) >> 12;
*shadowPix++ = (uint8) shadowAlpha;
}
shadowAlpha = ((shadowAlpha * radiusMinus1 + (*shadowPix << 6)) * filter) >> 12;
*shadowPix++ = (uint8) shadowAlpha;
}
}
g.setColour (Colours::black.withAlpha (opacity * alpha));
g.setColour (Colours::black.withAlpha (alpha));
g.drawImageAt (shadowImage, offsetX, offsetY, true);
}
void DropShadowEffect::applyEffect (Image& image, Graphics& g, float scaleFactor, float alpha)
{
drawShadow (g, image, radius * scaleFactor, opacity * alpha,
(int) (offsetX * scaleFactor), (int) (offsetY * scaleFactor));
g.setOpacity (alpha);
g.drawImageAt (image, 0, 0);


+ 4
- 1
modules/juce_graphics/effects/juce_DropShadowEffect.h View File

@@ -75,9 +75,12 @@ public:
int newShadowOffsetY);
static void drawShadow (Graphics& g, const Image& srcImage,
float radius, float alpha, int offsetX, int offsetY);
//==============================================================================
/** @internal */
void applyEffect (Image& sourceImage, Graphics& destContext, float alpha);
void applyEffect (Image& sourceImage, Graphics& destContext, float scaleFactor, float alpha);
private:


+ 2
- 2
modules/juce_graphics/effects/juce_GlowEffect.cpp View File

@@ -40,11 +40,11 @@ void GlowEffect::setGlowProperties (const float newRadius,
colour = newColour;
}
void GlowEffect::applyEffect (Image& image, Graphics& g, float alpha)
void GlowEffect::applyEffect (Image& image, Graphics& g, float scaleFactor, float alpha)
{
Image temp (image.getFormat(), image.getWidth(), image.getHeight(), true);
ImageConvolutionKernel blurKernel (roundToInt (radius * 2.0f));
ImageConvolutionKernel blurKernel (roundToInt (radius * scaleFactor * 2.0f));
blurKernel.createGaussianBlur (radius);
blurKernel.rescaleAllValues (radius);


+ 1
- 1
modules/juce_graphics/effects/juce_GlowEffect.h View File

@@ -63,7 +63,7 @@ public:
//==============================================================================
/** @internal */
void applyEffect (Image& sourceImage, Graphics& destContext, float alpha);
void applyEffect (Image& sourceImage, Graphics& destContext, float scaleFactor, float alpha);
private:
//==============================================================================


+ 4
- 0
modules/juce_graphics/effects/juce_ImageEffectFilter.h View File

@@ -53,11 +53,15 @@ public:
its paint() method. The image may or may not have an alpha
channel, depending on whether the component is opaque.
@param destContext the graphics context to use to draw the resultant image.
@param scaleFactor a scale factor that has been applied to the image - e.g. if
this is 2, then the image is actually scaled-up to twice the
original resolution
@param alpha the alpha with which to draw the resultant image to the
target context
*/
virtual void applyEffect (Image& sourceImage,
Graphics& destContext,
float scaleFactor,
float alpha) = 0;
/** Destructor. */


+ 3
- 1
modules/juce_graphics/native/juce_mac_CoreGraphicsContext.h View File

@@ -30,7 +30,7 @@
class CoreGraphicsContext : public LowLevelGraphicsContext
{
public:
CoreGraphicsContext (CGContextRef context_, const float flipHeight_);
CoreGraphicsContext (CGContextRef context_, const float flipHeight_, const float targetScale_);
~CoreGraphicsContext();
//==============================================================================
@@ -39,6 +39,7 @@ public:
void setOrigin (int x, int y);
void addTransform (const AffineTransform& transform);
float getScaleFactor();
float getTargetDeviceScaleFactor() { return targetScale; }
bool clipToRectangle (const Rectangle<int>& r);
bool clipToRectangleList (const RectangleList& clipRegion);
void excludeClipRectangle (const Rectangle<int>& r);
@@ -77,6 +78,7 @@ public:
private:
CGContextRef context;
const CGFloat flipHeight;
float targetScale;
CGColorSpaceRef rgbColourSpace, greyColourSpace;
CGFunctionCallbacks gradientCallbacks;
mutable Rectangle<int> lastClipRect;


+ 3
- 2
modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm View File

@@ -53,7 +53,7 @@ public:
LowLevelGraphicsContext* createLowLevelContext()
{
return new CoreGraphicsContext (context, height);
return new CoreGraphicsContext (context, height, 1.0f);
}
void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode)
@@ -124,9 +124,10 @@ ImagePixelData* NativeImageType::create (Image::PixelFormat format, int width, i
}
//==============================================================================
CoreGraphicsContext::CoreGraphicsContext (CGContextRef context_, const float flipHeight_)
CoreGraphicsContext::CoreGraphicsContext (CGContextRef context_, const float flipHeight_, const float targetScale_)
: context (context_),
flipHeight (flipHeight_),
targetScale (targetScale_),
lastClipRectIsValid (false),
state (new SavedState())
{


+ 8
- 2
modules/juce_gui_basics/components/juce_Component.cpp View File

@@ -1946,14 +1946,20 @@ void Component::paintEntireComponent (Graphics& g, const bool ignoreAlphaLevel)
if (effect != nullptr)
{
const float scale = g.getInternalContext()->getTargetDeviceScaleFactor();
Image effectImage (flags.opaqueFlag ? Image::RGB : Image::ARGB,
getWidth(), getHeight(), ! flags.opaqueFlag);
(int) (scale * getWidth()), (int) (scale * getHeight()), ! flags.opaqueFlag);
{
Graphics g2 (effectImage);
g2.addTransform (AffineTransform::scale (scale, scale));
paintComponentAndChildren (g2);
}
effect->applyEffect (effectImage, g, ignoreAlphaLevel ? 1.0f : getAlpha());
g.saveState();
g.addTransform (AffineTransform::scale (1.0f / scale, 1.0f / scale));
effect->applyEffect (effectImage, g, scale, ignoreAlphaLevel ? 1.0f : getAlpha());
g.restoreState();
}
else if (componentTransparency > 0 && ! ignoreAlphaLevel)
{


+ 24
- 11
modules/juce_gui_basics/lookandfeel/juce_LookAndFeel.cpp View File

@@ -2533,23 +2533,36 @@ const Rectangle<int> LookAndFeel::getPropertyComponentContentPosition (PropertyC
}
//==============================================================================
void LookAndFeel::drawCallOutBoxBackground (CallOutBox& box, Graphics& g, const Path& path)
void LookAndFeel::drawCallOutBoxBackground (CallOutBox& box, Graphics& g,
const Path& path, Image& cachedImage)
{
Image content (Image::ARGB, box.getWidth(), box.getHeight(), true);
if (cachedImage.isNull())
{
Graphics g2 (content);
const int w = box.getWidth();
const int h = box.getHeight();
Image renderedPath (Image::ARGB, w, h, true);
g2.setColour (Colour::greyLevel (0.23f).withAlpha (0.9f));
g2.fillPath (path);
{
Graphics g2 (renderedPath);
g2.setColour (Colour::greyLevel (0.23f).withAlpha (0.9f));
g2.fillPath (path);
}
g2.setColour (Colours::white.withAlpha (0.8f));
g2.strokePath (path, PathStrokeType (2.0f));
cachedImage = Image (Image::ARGB, w, h, true);
Graphics g2 (cachedImage);
DropShadowEffect::drawShadow (g2, renderedPath, 5.0f, 0.4f, 0, 2);
}
DropShadowEffect shadow;
shadow.setShadowProperties (5.0f, 0.4f, 0, 2);
shadow.applyEffect (content, g, 1.0f);
g.setColour (Colours::black);
g.drawImageAt (cachedImage, 0, 0);
g.setColour (Colour::greyLevel (0.23f).withAlpha (0.9f));
g.fillPath (path);
g.setColour (Colours::white.withAlpha (0.8f));
g.strokePath (path, PathStrokeType (2.0f));
}


+ 1
- 1
modules/juce_gui_basics/lookandfeel/juce_LookAndFeel.h View File

@@ -611,7 +611,7 @@ public:
virtual const Rectangle<int> getPropertyComponentContentPosition (PropertyComponent& component);
//==============================================================================
virtual void drawCallOutBoxBackground (CallOutBox& box, Graphics& g, const Path& path);
virtual void drawCallOutBoxBackground (CallOutBox& box, Graphics& g, const Path& path, Image& cachedImage);
//==============================================================================
virtual void drawLevelMeter (Graphics& g, int width, int height, float level);


+ 1
- 1
modules/juce_gui_basics/native/juce_ios_UIViewComponentPeer.mm View File

@@ -901,7 +901,7 @@ void UIViewComponentPeer::drawRect (CGRect r)
CGContextClearRect (cg, CGContextGetClipBoundingBox (cg));
CGContextConcatCTM (cg, CGAffineTransformMake (1, 0, 0, -1, 0, view.bounds.size.height));
CoreGraphicsContext g (cg, view.bounds.size.height);
CoreGraphicsContext g (cg, view.bounds.size.height, [UIScreen mainScreen].scale);
insideDrawRect = true;
handlePaint (g);


+ 9
- 1
modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm View File

@@ -681,7 +681,15 @@ public:
#if USE_COREGRAPHICS_RENDERING
if (usingCoreGraphics)
{
CoreGraphicsContext context (cg, (float) [view frame].size.height);
float displayScale = 1.0f;
#if defined (MAC_OS_X_VERSION_10_7) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7)
NSScreen* screen = [[view window] screen];
if ([screen respondsToSelector: @selector (backingScaleFactor)])
displayScale = screen.backingScaleFactor;
#endif
CoreGraphicsContext context (cg, (float) [view frame].size.height, displayScale);
insideDrawRect = true;
handlePaint (context);


+ 1
- 9
modules/juce_gui_basics/windows/juce_CallOutBox.cpp View File

@@ -65,15 +65,7 @@ void CallOutBox::setArrowSize (const float newSize)
void CallOutBox::paint (Graphics& g)
{
if (background.isNull())
{
background = Image (Image::ARGB, getWidth(), getHeight(), true);
Graphics g2 (background);
getLookAndFeel().drawCallOutBoxBackground (*this, g2, outline);
}
g.setColour (Colours::black);
g.drawImageAt (background, 0, 0);
getLookAndFeel().drawCallOutBoxBackground (*this, g, outline, background);
}
void CallOutBox::resized()


Loading…
Cancel
Save