mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Fixes to deal with effect rendering in retina displays, e.g. drop-shadows, etc.
This commit is contained in:
parent
2fe73f6ebe
commit
ceb556876a
14 changed files with 100 additions and 64 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 (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);
|
||||
|
||||
for (int x = w; --x >= 0;)
|
||||
{
|
||||
const Image::BitmapData srcData (image, Image::BitmapData::readOnly);
|
||||
const Image::BitmapData destData (shadowImage, Image::BitmapData::readWrite);
|
||||
int shadowAlpha = 0;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
*shadowPix = (uint8) shadowAlpha;
|
||||
src = addBytesToPointer (src, srcData.lineStride);
|
||||
shadowPix += destData.lineStride;
|
||||
}
|
||||
}
|
||||
const PixelARGB* src = ((const PixelARGB*) srcData.data) + x;
|
||||
uint8* shadowPix = destData.data + x;
|
||||
|
||||
for (int y = h; --y >= 0;)
|
||||
{
|
||||
int shadowAlpha = 0;
|
||||
uint8* shadowPix = destData.getLinePointer (y);
|
||||
shadowAlpha = ((shadowAlpha * radiusMinus1 + (src->getAlpha() << 6)) * filter) >> 12;
|
||||
|
||||
for (int x = w; --x >= 0;)
|
||||
{
|
||||
shadowAlpha = ((shadowAlpha * radiusMinus1 + (*shadowPix << 6)) * filter) >> 12;
|
||||
*shadowPix++ = (uint8) shadowAlpha;
|
||||
}
|
||||
*shadowPix = (uint8) shadowAlpha;
|
||||
src = addBytesToPointer (src, srcData.lineStride);
|
||||
shadowPix += destData.lineStride;
|
||||
}
|
||||
}
|
||||
|
||||
g.setColour (Colours::black.withAlpha (opacity * alpha));
|
||||
for (int y = h; --y >= 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;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
//==============================================================================
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
g2.setColour (Colour::greyLevel (0.23f).withAlpha (0.9f));
|
||||
g2.fillPath (path);
|
||||
Image renderedPath (Image::ARGB, w, h, true);
|
||||
|
||||
g2.setColour (Colours::white.withAlpha (0.8f));
|
||||
g2.strokePath (path, PathStrokeType (2.0f));
|
||||
{
|
||||
Graphics g2 (renderedPath);
|
||||
|
||||
g2.setColour (Colour::greyLevel (0.23f).withAlpha (0.9f));
|
||||
g2.fillPath (path);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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…
Add table
Add a link
Reference in a new issue