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;