From 4c31b704edb845f4af963a3d491f924eb2ac4a02 Mon Sep 17 00:00:00 2001 From: Julian Storer Date: Thu, 3 Dec 2009 12:14:21 +0000 Subject: [PATCH] Fix for Graphics::drawImage and small change to the parameters of Graphics::drawImageTransformed - if you were using subregions of images, note that this method now treats them slightly differently. Previously, the transform was relative to the origin of the image, but now it's relative to the origin of the subregion. --- .../src/demos/RenderingTestComponent.cpp | 6 +- juce_amalgamated.cpp | 63 +++++++++---------- juce_amalgamated.h | 13 ++-- src/gui/graphics/contexts/juce_Graphics.cpp | 22 +++---- src/gui/graphics/contexts/juce_Graphics.h | 13 ++-- .../juce_LowLevelGraphicsSoftwareRenderer.cpp | 15 ++--- .../graphics/drawables/juce_DrawableImage.cpp | 6 +- .../mac/juce_mac_CoreGraphicsContext.mm | 10 +-- 8 files changed, 69 insertions(+), 79 deletions(-) diff --git a/extras/juce demo/src/demos/RenderingTestComponent.cpp b/extras/juce demo/src/demos/RenderingTestComponent.cpp index 0cb133d3f8..14b1736798 100644 --- a/extras/juce demo/src/demos/RenderingTestComponent.cpp +++ b/extras/juce demo/src/demos/RenderingTestComponent.cpp @@ -271,9 +271,7 @@ private: .followedBy (getTransform())); g.setOpacity ((float) owner.opacitySlider->getValue()); - g.drawImageTransformed (image, 0, 0, - image->getWidth(), - image->getHeight(), + g.drawImageTransformed (image, image->getBounds(), transform, false); } @@ -327,7 +325,7 @@ private: g.drawHorizontalLine (y, x - width, x + width); } - g.setColour (Colours::yellow.withAlpha ((float) owner.opacitySlider->getValue())); + g.setColour (Colours::red.withAlpha ((float) owner.opacitySlider->getValue())); g.drawLine (bouncingPointX[0], bouncingPointY[0], bouncingPointX[1], bouncingPointY[1]); g.drawLine (getWidth() - bouncingPointX[0], getHeight() - bouncingPointY[0], getWidth() - bouncingPointX[1], getHeight() - bouncingPointY[1]); diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index 292b72ee82..1b270c3a8b 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -80009,27 +80009,23 @@ void Graphics::drawImage (const Image* const imageToDraw, ASSERT_COORDS_ARE_SENSIBLE_NUMBERS (dx, dy, dw, dh); ASSERT_COORDS_ARE_SENSIBLE_NUMBERS (sx, sy, sw, sh); - if (! context->clipRegionIntersects (Rectangle (dx, dy, dw, dh))) - return; - - drawImageTransformed (imageToDraw, sx, sy, sw, sh, - AffineTransform::translation ((float) -sx, (float) -sy) - .scaled (dw / (float) sw, dh / (float) sh) - .translated ((float) dx, (float) dy), - fillAlphaChannelWithCurrentBrush); + if (context->clipRegionIntersects (Rectangle (dx, dy, dw, dh))) + { + drawImageTransformed (imageToDraw, Rectangle (sx, sy, sw, sh), + AffineTransform::scale (dw / (float) sw, dh / (float) sh) + .translated ((float) dx, (float) dy), + fillAlphaChannelWithCurrentBrush); + } } void Graphics::drawImageTransformed (const Image* const imageToDraw, - int sourceClipX, - int sourceClipY, - int sourceClipWidth, - int sourceClipHeight, + const Rectangle& imageSubRegion, const AffineTransform& transform, const bool fillAlphaChannelWithCurrentBrush) const throw() { if (imageToDraw != 0 && ! context->isClipEmpty()) { - const Rectangle srcClip (Rectangle (sourceClipX, sourceClipY, sourceClipWidth, sourceClipHeight)); + const Rectangle srcClip (imageSubRegion.getIntersection (imageToDraw->getBounds())); if (fillAlphaChannelWithCurrentBrush) { @@ -81567,24 +81563,25 @@ public: if (transform.isOnlyTranslation()) { // If our translation doesn't involve any distortion, just use a simple blit.. - const int tx = (int) (transform.getTranslationX() * 256.0f); - const int ty = (int) (transform.getTranslationY() * 256.0f); + int tx = (int) (transform.getTranslationX() * 256.0f); + int ty = (int) (transform.getTranslationY() * 256.0f); if ((! betterQuality) || ((tx | ty) & 224) == 0) { - const Rectangle srcRect (srcClip.translated ((tx + 128) >> 8, (ty + 128) >> 8)); + tx = ((tx + 128) >> 8); + ty = ((ty + 128) >> 8); if (tiledFillClipRegion != 0) { - blittedRenderImage3 (sourceImage, destImage, *tiledFillClipRegion, destData, srcData, alpha, srcRect.getX(), srcRect.getY()); + blittedRenderImage3 (sourceImage, destImage, *tiledFillClipRegion, destData, srcData, alpha, tx, ty); } else { - EdgeTable et (srcRect.getIntersection (destImage.getBounds())); + EdgeTable et (Rectangle (tx, ty, srcClip.getWidth(), srcClip.getHeight()).getIntersection (destImage.getBounds())); et.clipToEdgeTable (edgeTable->edgeTable); if (! et.isEmpty()) - blittedRenderImage3 (sourceImage, destImage, et, destData, srcData, alpha, srcRect.getX(), srcRect.getY()); + blittedRenderImage3 (sourceImage, destImage, et, destData, srcData, alpha, tx, ty); } return; @@ -81601,7 +81598,7 @@ public: else { Path p; - p.addRectangle (srcClip); + p.addRectangle (0.0f, 0.0f, (float) srcClip.getWidth(), (float) srcClip.getHeight()); EdgeTable et (edgeTable->edgeTable.getMaximumBounds(), p, transform); et.clipToEdgeTable (edgeTable->edgeTable); @@ -82834,16 +82831,14 @@ void DrawableImage::render (const Drawable::RenderingContext& context) const if (opacity > 0.0f && ! overlayColour.isOpaque()) { context.g.setOpacity (context.opacity * opacity); - context.g.drawImageTransformed (image, - 0, 0, image->getWidth(), image->getHeight(), + context.g.drawImageTransformed (image, image->getBounds(), context.transform, false); } if (! overlayColour.isTransparent()) { context.g.setColour (overlayColour.withMultipliedAlpha (context.opacity)); - context.g.drawImageTransformed (image, - 0, 0, image->getWidth(), image->getHeight(), + context.g.drawImageTransformed (image, image->getBounds(), context.transform, true); } } @@ -261712,7 +261707,7 @@ public: if (srcClip != sourceImage.getBounds()) { - image = CGImageCreateWithImageInRect (fullImage, CGRectMake (srcClip.getX(), sourceImage.getHeight() - srcClip.getBottom(), + image = CGImageCreateWithImageInRect (fullImage, CGRectMake (srcClip.getX(), srcClip.getY(), srcClip.getWidth(), srcClip.getHeight())); CGImageRelease (fullImage); } @@ -261721,8 +261716,8 @@ public: CGContextSetAlpha (context, state->fillType.getOpacity()); flip(); - applyTransform (AffineTransform::scale (1.0f, -1.0f).translated (0, sourceImage.getHeight()).followedBy (transform)); - CGRect imageRect = CGRectMake (0, 0, sourceImage.getWidth(), sourceImage.getHeight()); + applyTransform (AffineTransform::scale (1.0f, -1.0f).translated (0, srcClip.getHeight()).followedBy (transform)); + CGRect imageRect = CGRectMake (0, 0, srcClip.getWidth(), srcClip.getHeight()); if (fillEntireClipAsTiles) { @@ -261737,8 +261732,8 @@ public: { // Fallback to manually doing a tiled fill on 10.4 CGRect clip = CGRectIntegral (CGContextGetClipBoundingBox (context)); - const int iw = sourceImage.getWidth(); - const int ih = sourceImage.getHeight(); + const int iw = srcClip.getWidth(); + const int ih = srcClip.getHeight(); int x = 0, y = 0; while (x > clip.origin.x) x -= iw; @@ -266169,7 +266164,7 @@ public: if (srcClip != sourceImage.getBounds()) { - image = CGImageCreateWithImageInRect (fullImage, CGRectMake (srcClip.getX(), sourceImage.getHeight() - srcClip.getBottom(), + image = CGImageCreateWithImageInRect (fullImage, CGRectMake (srcClip.getX(), srcClip.getY(), srcClip.getWidth(), srcClip.getHeight())); CGImageRelease (fullImage); } @@ -266178,8 +266173,8 @@ public: CGContextSetAlpha (context, state->fillType.getOpacity()); flip(); - applyTransform (AffineTransform::scale (1.0f, -1.0f).translated (0, sourceImage.getHeight()).followedBy (transform)); - CGRect imageRect = CGRectMake (0, 0, sourceImage.getWidth(), sourceImage.getHeight()); + applyTransform (AffineTransform::scale (1.0f, -1.0f).translated (0, srcClip.getHeight()).followedBy (transform)); + CGRect imageRect = CGRectMake (0, 0, srcClip.getWidth(), srcClip.getHeight()); if (fillEntireClipAsTiles) { @@ -266194,8 +266189,8 @@ public: { // Fallback to manually doing a tiled fill on 10.4 CGRect clip = CGRectIntegral (CGContextGetClipBoundingBox (context)); - const int iw = sourceImage.getWidth(); - const int ih = sourceImage.getHeight(); + const int iw = srcClip.getWidth(); + const int ih = srcClip.getHeight(); int x = 0, y = 0; while (x > clip.origin.x) x -= iw; diff --git a/juce_amalgamated.h b/juce_amalgamated.h index 2c8278f1cc..d442fea595 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -20598,8 +20598,12 @@ public: This lets you throw the image around in some wacky ways, rotate it, shear, scale it, etc. - A clipping subregion is specified within the source image and no pixels - outside this region will be used. + A subregion is specified within the source image, and all transformations + will be treated as relative to the origin of this sub-region. So, for example if + your subregion is (50, 50, 100, 100), and your transform is a translation of (20, 20), + the resulting pixel drawn at (20, 20) in the destination context is from (50, 50) in + your image. If you want to use the whole image, then Image::getBounds() returns a + suitable rectangle to use as the imageSubRegion parameter. Images are composited using the context's current opacity, so if you don't want it to be drawn semi-transparently, be sure to call setOpacity (1.0f) @@ -20611,10 +20615,7 @@ public: @see setImageResamplingQuality, drawImage */ void drawImageTransformed (const Image* const imageToDraw, - int sourceClipX, - int sourceClipY, - int sourceClipWidth, - int sourceClipHeight, + const Rectangle& imageSubRegion, const AffineTransform& transform, const bool fillAlphaChannelWithCurrentBrush = false) const throw(); diff --git a/src/gui/graphics/contexts/juce_Graphics.cpp b/src/gui/graphics/contexts/juce_Graphics.cpp index b31345ad65..fb162b2795 100644 --- a/src/gui/graphics/contexts/juce_Graphics.cpp +++ b/src/gui/graphics/contexts/juce_Graphics.cpp @@ -760,27 +760,23 @@ void Graphics::drawImage (const Image* const imageToDraw, ASSERT_COORDS_ARE_SENSIBLE_NUMBERS (dx, dy, dw, dh); ASSERT_COORDS_ARE_SENSIBLE_NUMBERS (sx, sy, sw, sh); - if (! context->clipRegionIntersects (Rectangle (dx, dy, dw, dh))) - return; - - drawImageTransformed (imageToDraw, sx, sy, sw, sh, - AffineTransform::translation ((float) -sx, (float) -sy) - .scaled (dw / (float) sw, dh / (float) sh) - .translated ((float) dx, (float) dy), - fillAlphaChannelWithCurrentBrush); + if (context->clipRegionIntersects (Rectangle (dx, dy, dw, dh))) + { + drawImageTransformed (imageToDraw, Rectangle (sx, sy, sw, sh), + AffineTransform::scale (dw / (float) sw, dh / (float) sh) + .translated ((float) dx, (float) dy), + fillAlphaChannelWithCurrentBrush); + } } void Graphics::drawImageTransformed (const Image* const imageToDraw, - int sourceClipX, - int sourceClipY, - int sourceClipWidth, - int sourceClipHeight, + const Rectangle& imageSubRegion, const AffineTransform& transform, const bool fillAlphaChannelWithCurrentBrush) const throw() { if (imageToDraw != 0 && ! context->isClipEmpty()) { - const Rectangle srcClip (Rectangle (sourceClipX, sourceClipY, sourceClipWidth, sourceClipHeight)); + const Rectangle srcClip (imageSubRegion.getIntersection (imageToDraw->getBounds())); if (fillAlphaChannelWithCurrentBrush) { diff --git a/src/gui/graphics/contexts/juce_Graphics.h b/src/gui/graphics/contexts/juce_Graphics.h index ba82d0f25d..d59e7f40de 100644 --- a/src/gui/graphics/contexts/juce_Graphics.h +++ b/src/gui/graphics/contexts/juce_Graphics.h @@ -559,8 +559,12 @@ public: This lets you throw the image around in some wacky ways, rotate it, shear, scale it, etc. - A clipping subregion is specified within the source image and no pixels - outside this region will be used. + A subregion is specified within the source image, and all transformations + will be treated as relative to the origin of this sub-region. So, for example if + your subregion is (50, 50, 100, 100), and your transform is a translation of (20, 20), + the resulting pixel drawn at (20, 20) in the destination context is from (50, 50) in + your image. If you want to use the whole image, then Image::getBounds() returns a + suitable rectangle to use as the imageSubRegion parameter. Images are composited using the context's current opacity, so if you don't want it to be drawn semi-transparently, be sure to call setOpacity (1.0f) @@ -572,10 +576,7 @@ public: @see setImageResamplingQuality, drawImage */ void drawImageTransformed (const Image* const imageToDraw, - int sourceClipX, - int sourceClipY, - int sourceClipWidth, - int sourceClipHeight, + const Rectangle& imageSubRegion, const AffineTransform& transform, const bool fillAlphaChannelWithCurrentBrush = false) const throw(); diff --git a/src/gui/graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.cpp b/src/gui/graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.cpp index 8d57cc3daf..418cb26339 100644 --- a/src/gui/graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.cpp +++ b/src/gui/graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.cpp @@ -1005,24 +1005,25 @@ public: if (transform.isOnlyTranslation()) { // If our translation doesn't involve any distortion, just use a simple blit.. - const int tx = (int) (transform.getTranslationX() * 256.0f); - const int ty = (int) (transform.getTranslationY() * 256.0f); + int tx = (int) (transform.getTranslationX() * 256.0f); + int ty = (int) (transform.getTranslationY() * 256.0f); if ((! betterQuality) || ((tx | ty) & 224) == 0) { - const Rectangle srcRect (srcClip.translated ((tx + 128) >> 8, (ty + 128) >> 8)); + tx = ((tx + 128) >> 8); + ty = ((ty + 128) >> 8); if (tiledFillClipRegion != 0) { - blittedRenderImage3 (sourceImage, destImage, *tiledFillClipRegion, destData, srcData, alpha, srcRect.getX(), srcRect.getY()); + blittedRenderImage3 (sourceImage, destImage, *tiledFillClipRegion, destData, srcData, alpha, tx, ty); } else { - EdgeTable et (srcRect.getIntersection (destImage.getBounds())); + EdgeTable et (Rectangle (tx, ty, srcClip.getWidth(), srcClip.getHeight()).getIntersection (destImage.getBounds())); et.clipToEdgeTable (edgeTable->edgeTable); if (! et.isEmpty()) - blittedRenderImage3 (sourceImage, destImage, et, destData, srcData, alpha, srcRect.getX(), srcRect.getY()); + blittedRenderImage3 (sourceImage, destImage, et, destData, srcData, alpha, tx, ty); } return; @@ -1039,7 +1040,7 @@ public: else { Path p; - p.addRectangle (srcClip); + p.addRectangle (0.0f, 0.0f, (float) srcClip.getWidth(), (float) srcClip.getHeight()); EdgeTable et (edgeTable->edgeTable.getMaximumBounds(), p, transform); et.clipToEdgeTable (edgeTable->edgeTable); diff --git a/src/gui/graphics/drawables/juce_DrawableImage.cpp b/src/gui/graphics/drawables/juce_DrawableImage.cpp index 5581327156..55457b7871 100644 --- a/src/gui/graphics/drawables/juce_DrawableImage.cpp +++ b/src/gui/graphics/drawables/juce_DrawableImage.cpp @@ -94,16 +94,14 @@ void DrawableImage::render (const Drawable::RenderingContext& context) const if (opacity > 0.0f && ! overlayColour.isOpaque()) { context.g.setOpacity (context.opacity * opacity); - context.g.drawImageTransformed (image, - 0, 0, image->getWidth(), image->getHeight(), + context.g.drawImageTransformed (image, image->getBounds(), context.transform, false); } if (! overlayColour.isTransparent()) { context.g.setColour (overlayColour.withMultipliedAlpha (context.opacity)); - context.g.drawImageTransformed (image, - 0, 0, image->getWidth(), image->getHeight(), + context.g.drawImageTransformed (image, image->getBounds(), context.transform, true); } } diff --git a/src/native/mac/juce_mac_CoreGraphicsContext.mm b/src/native/mac/juce_mac_CoreGraphicsContext.mm index f5ab79fa03..992a694686 100644 --- a/src/native/mac/juce_mac_CoreGraphicsContext.mm +++ b/src/native/mac/juce_mac_CoreGraphicsContext.mm @@ -379,7 +379,7 @@ public: if (srcClip != sourceImage.getBounds()) { - image = CGImageCreateWithImageInRect (fullImage, CGRectMake (srcClip.getX(), sourceImage.getHeight() - srcClip.getBottom(), + image = CGImageCreateWithImageInRect (fullImage, CGRectMake (srcClip.getX(), srcClip.getY(), srcClip.getWidth(), srcClip.getHeight())); CGImageRelease (fullImage); } @@ -388,8 +388,8 @@ public: CGContextSetAlpha (context, state->fillType.getOpacity()); flip(); - applyTransform (AffineTransform::scale (1.0f, -1.0f).translated (0, sourceImage.getHeight()).followedBy (transform)); - CGRect imageRect = CGRectMake (0, 0, sourceImage.getWidth(), sourceImage.getHeight()); + applyTransform (AffineTransform::scale (1.0f, -1.0f).translated (0, srcClip.getHeight()).followedBy (transform)); + CGRect imageRect = CGRectMake (0, 0, srcClip.getWidth(), srcClip.getHeight()); if (fillEntireClipAsTiles) { @@ -404,8 +404,8 @@ public: { // Fallback to manually doing a tiled fill on 10.4 CGRect clip = CGRectIntegral (CGContextGetClipBoundingBox (context)); - const int iw = sourceImage.getWidth(); - const int ih = sourceImage.getHeight(); + const int iw = srcClip.getWidth(); + const int ih = srcClip.getHeight(); int x = 0, y = 0; while (x > clip.origin.x) x -= iw;