1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-02-01 03:10:06 +00:00
JUCE/src/gui/graphics/contexts/juce_Graphics.cpp

983 lines
34 KiB
C++

/*
==============================================================================
This file is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-9 by Raw Material Software Ltd.
------------------------------------------------------------------------------
JUCE can be redistributed and/or modified under the terms of the GNU General
Public License (Version 2), as published by the Free Software Foundation.
A copy of the license is included in the JUCE distribution, or can be found
online at www.gnu.org/licenses.
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.rawmaterialsoftware.com/juce for more information.
==============================================================================
*/
#include "../../../core/juce_StandardHeader.h"
BEGIN_JUCE_NAMESPACE
#include "juce_Graphics.h"
#include "../fonts/juce_GlyphArrangement.h"
#include "../geometry/juce_PathStrokeType.h"
#include "juce_EdgeTable.h"
#include "juce_LowLevelGraphicsContext.h"
#include "../brushes/juce_GradientBrush.h"
#include "../brushes/juce_ImageBrush.h"
static const Graphics::ResamplingQuality defaultQuality = Graphics::mediumResamplingQuality;
//==============================================================================
#define MINIMUM_COORD -0x3fffffff
#define MAXIMUM_COORD 0x3fffffff
#undef ASSERT_COORDS_ARE_SENSIBLE_NUMBERS
#define ASSERT_COORDS_ARE_SENSIBLE_NUMBERS(x, y, w, h) \
jassert ((int) x >= MINIMUM_COORD \
&& (int) x <= MAXIMUM_COORD \
&& (int) y >= MINIMUM_COORD \
&& (int) y <= MAXIMUM_COORD \
&& (int) w >= MINIMUM_COORD \
&& (int) w <= MAXIMUM_COORD \
&& (int) h >= MINIMUM_COORD \
&& (int) h <= MAXIMUM_COORD);
//==============================================================================
LowLevelGraphicsContext::LowLevelGraphicsContext()
{
}
LowLevelGraphicsContext::~LowLevelGraphicsContext()
{
}
//==============================================================================
Graphics::Graphics (Image& imageToDrawOnto) throw()
: context (imageToDrawOnto.createLowLevelContext()),
ownsContext (true),
state (new GraphicsState()),
saveStatePending (false)
{
}
Graphics::Graphics (LowLevelGraphicsContext* const internalContext) throw()
: context (internalContext),
ownsContext (false),
state (new GraphicsState()),
saveStatePending (false)
{
}
Graphics::~Graphics() throw()
{
delete state;
if (ownsContext)
delete context;
}
//==============================================================================
void Graphics::resetToDefaultState() throw()
{
setColour (Colours::black);
state->font.resetToDefaultState();
state->quality = defaultQuality;
}
bool Graphics::isVectorDevice() const throw()
{
return context->isVectorDevice();
}
bool Graphics::reduceClipRegion (const int x, const int y,
const int w, const int h) throw()
{
saveStateIfPending();
return context->reduceClipRegion (x, y, w, h);
}
bool Graphics::reduceClipRegion (const RectangleList& clipRegion) throw()
{
saveStateIfPending();
return context->reduceClipRegion (clipRegion);
}
void Graphics::excludeClipRegion (const int x, const int y,
const int w, const int h) throw()
{
saveStateIfPending();
context->excludeClipRegion (x, y, w, h);
}
bool Graphics::isClipEmpty() const throw()
{
return context->isClipEmpty();
}
const Rectangle Graphics::getClipBounds() const throw()
{
return context->getClipBounds();
}
void Graphics::saveState() throw()
{
saveStateIfPending();
saveStatePending = true;
}
void Graphics::restoreState() throw()
{
if (saveStatePending)
{
saveStatePending = false;
}
else
{
const int stackSize = stateStack.size();
if (stackSize > 0)
{
context->restoreState();
delete state;
state = stateStack.getUnchecked (stackSize - 1);
stateStack.removeLast (1, false);
}
else
{
// Trying to call restoreState() more times than you've called saveState() !
// Be careful to correctly match each saveState() with exactly one call to restoreState().
jassertfalse
}
}
}
void Graphics::saveStateIfPending() throw()
{
if (saveStatePending)
{
saveStatePending = false;
context->saveState();
stateStack.add (new GraphicsState (*state));
}
}
void Graphics::setOrigin (const int newOriginX,
const int newOriginY) throw()
{
saveStateIfPending();
context->setOrigin (newOriginX, newOriginY);
}
bool Graphics::clipRegionIntersects (const int x, const int y,
const int w, const int h) const throw()
{
return context->clipRegionIntersects (x, y, w, h);
}
//==============================================================================
void Graphics::setColour (const Colour& newColour) throw()
{
saveStateIfPending();
state->colour = newColour;
deleteAndZero (state->brush);
}
void Graphics::setOpacity (const float newOpacity) throw()
{
saveStateIfPending();
state->colour = state->colour.withAlpha (newOpacity);
}
void Graphics::setBrush (const Brush* const newBrush) throw()
{
saveStateIfPending();
delete state->brush;
if (newBrush != 0)
state->brush = newBrush->createCopy();
else
state->brush = 0;
}
void Graphics::setGradientFill (const ColourGradient& gradient) throw()
{
saveStateIfPending();
delete state->brush;
state->brush = new GradientBrush (gradient);
}
void Graphics::setTiledImageFill (Image& imageToUse,
const int anchorX,
const int anchorY,
const float opacity) throw()
{
saveStateIfPending();
delete state->brush;
state->brush = new ImageBrush (&imageToUse, anchorX, anchorY, opacity);
}
//==============================================================================
Graphics::GraphicsState::GraphicsState() throw()
: colour (Colours::black),
brush (0),
quality (defaultQuality)
{
}
Graphics::GraphicsState::GraphicsState (const GraphicsState& other) throw()
: colour (other.colour),
brush (other.brush != 0 ? other.brush->createCopy() : 0),
font (other.font),
quality (other.quality)
{
}
Graphics::GraphicsState::~GraphicsState() throw()
{
delete brush;
}
//==============================================================================
void Graphics::setFont (const Font& newFont) throw()
{
saveStateIfPending();
state->font = newFont;
}
void Graphics::setFont (const float newFontHeight,
const int newFontStyleFlags) throw()
{
saveStateIfPending();
state->font.setSizeAndStyle (newFontHeight, newFontStyleFlags, 1.0f, 0.0f);
}
//==============================================================================
void Graphics::drawSingleLineText (const String& text,
const int startX,
const int baselineY) const throw()
{
if (text.isNotEmpty()
&& startX < context->getClipBounds().getRight())
{
GlyphArrangement arr;
arr.addLineOfText (state->font, text, (float) startX, (float) baselineY);
arr.draw (*this);
}
}
void Graphics::drawTextAsPath (const String& text,
const AffineTransform& transform) const throw()
{
if (text.isNotEmpty())
{
GlyphArrangement arr;
arr.addLineOfText (state->font, text, 0.0f, 0.0f);
arr.draw (*this, transform);
}
}
void Graphics::drawMultiLineText (const String& text,
const int startX,
const int baselineY,
const int maximumLineWidth) const throw()
{
if (text.isNotEmpty()
&& startX < context->getClipBounds().getRight())
{
GlyphArrangement arr;
arr.addJustifiedText (state->font, text,
(float) startX, (float) baselineY, (float) maximumLineWidth,
Justification::left);
arr.draw (*this);
}
}
void Graphics::drawText (const String& text,
const int x,
const int y,
const int width,
const int height,
const Justification& justificationType,
const bool useEllipsesIfTooBig) const throw()
{
if (text.isNotEmpty() && context->clipRegionIntersects (x, y, width, height))
{
GlyphArrangement arr;
arr.addCurtailedLineOfText (state->font, text,
0.0f, 0.0f, (float)width,
useEllipsesIfTooBig);
arr.justifyGlyphs (0, arr.getNumGlyphs(),
(float) x, (float) y,
(float) width, (float) height,
justificationType);
arr.draw (*this);
}
}
void Graphics::drawFittedText (const String& text,
const int x,
const int y,
const int width,
const int height,
const Justification& justification,
const int maximumNumberOfLines,
const float minimumHorizontalScale) const throw()
{
if (text.isNotEmpty()
&& width > 0 && height > 0
&& context->clipRegionIntersects (x, y, width, height))
{
GlyphArrangement arr;
arr.addFittedText (state->font, text,
(float) x, (float) y,
(float) width, (float) height,
justification,
maximumNumberOfLines,
minimumHorizontalScale);
arr.draw (*this);
}
}
//==============================================================================
void Graphics::fillRect (int x,
int y,
int width,
int height) const throw()
{
// passing in a silly number can cause maths problems in rendering!
ASSERT_COORDS_ARE_SENSIBLE_NUMBERS (x, y, width, height);
SolidColourBrush colourBrush (state->colour);
(state->brush != 0 ? *(state->brush) : (Brush&) colourBrush).paintRectangle (*context, x, y, width, height);
}
void Graphics::fillRect (const Rectangle& r) const throw()
{
fillRect (r.getX(),
r.getY(),
r.getWidth(),
r.getHeight());
}
void Graphics::fillRect (const float x,
const float y,
const float width,
const float height) const throw()
{
// passing in a silly number can cause maths problems in rendering!
ASSERT_COORDS_ARE_SENSIBLE_NUMBERS (x, y, width, height);
Path p;
p.addRectangle (x, y, width, height);
fillPath (p);
}
void Graphics::setPixel (int x, int y) const throw()
{
if (context->clipRegionIntersects (x, y, 1, 1))
{
SolidColourBrush colourBrush (state->colour);
(state->brush != 0 ? *(state->brush) : (Brush&) colourBrush).paintRectangle (*context, x, y, 1, 1);
}
}
void Graphics::fillAll() const throw()
{
fillRect (context->getClipBounds());
}
void Graphics::fillAll (const Colour& colourToUse) const throw()
{
if (! colourToUse.isTransparent())
{
const Rectangle clip (context->getClipBounds());
context->fillRectWithColour (clip.getX(), clip.getY(), clip.getWidth(), clip.getHeight(),
colourToUse, false);
}
}
//==============================================================================
void Graphics::fillPath (const Path& path,
const AffineTransform& transform) const throw()
{
if ((! context->isClipEmpty()) && ! path.isEmpty())
{
SolidColourBrush colourBrush (state->colour);
(state->brush != 0 ? *(state->brush) : (Brush&) colourBrush).paintPath (*context, path, transform);
}
}
void Graphics::strokePath (const Path& path,
const PathStrokeType& strokeType,
const AffineTransform& transform) const throw()
{
if ((! state->colour.isTransparent()) || state->brush != 0)
{
Path stroke;
strokeType.createStrokedPath (stroke, path, transform);
fillPath (stroke);
}
}
//==============================================================================
void Graphics::drawRect (const int x,
const int y,
const int width,
const int height,
const int lineThickness) const throw()
{
// passing in a silly number can cause maths problems in rendering!
ASSERT_COORDS_ARE_SENSIBLE_NUMBERS (x, y, width, height);
SolidColourBrush colourBrush (state->colour);
Brush& b = (state->brush != 0 ? *(state->brush) : (Brush&) colourBrush);
b.paintRectangle (*context, x, y, width, lineThickness);
b.paintRectangle (*context, x, y + lineThickness, lineThickness, height - lineThickness * 2);
b.paintRectangle (*context, x + width - lineThickness, y + lineThickness, lineThickness, height - lineThickness * 2);
b.paintRectangle (*context, x, y + height - lineThickness, width, lineThickness);
}
void Graphics::drawRect (const float x,
const float y,
const float width,
const float height,
const float lineThickness) const throw()
{
// passing in a silly number can cause maths problems in rendering!
ASSERT_COORDS_ARE_SENSIBLE_NUMBERS (x, y, width, height);
Path p;
p.addRectangle (x, y, width, lineThickness);
p.addRectangle (x, y + lineThickness, lineThickness, height - lineThickness * 2.0f);
p.addRectangle (x + width - lineThickness, y + lineThickness, lineThickness, height - lineThickness * 2.0f);
p.addRectangle (x, y + height - lineThickness, width, lineThickness);
fillPath (p);
}
void Graphics::drawRect (const Rectangle& r,
const int lineThickness) const throw()
{
drawRect (r.getX(), r.getY(),
r.getWidth(), r.getHeight(),
lineThickness);
}
void Graphics::drawBevel (const int x,
const int y,
const int width,
const int height,
const int bevelThickness,
const Colour& topLeftColour,
const Colour& bottomRightColour,
const bool useGradient,
const bool sharpEdgeOnOutside) const throw()
{
// passing in a silly number can cause maths problems in rendering!
ASSERT_COORDS_ARE_SENSIBLE_NUMBERS (x, y, width, height);
if (clipRegionIntersects (x, y, width, height))
{
const float oldOpacity = state->colour.getFloatAlpha();
const float ramp = oldOpacity / bevelThickness;
for (int i = bevelThickness; --i >= 0;)
{
const float op = useGradient ? ramp * (sharpEdgeOnOutside ? bevelThickness - i : i)
: oldOpacity;
context->fillRectWithColour (x + i, y + i, width - i * 2, 1, topLeftColour.withMultipliedAlpha (op), false);
context->fillRectWithColour (x + i, y + i + 1, 1, height - i * 2 - 2, topLeftColour.withMultipliedAlpha (op * 0.75f), false);
context->fillRectWithColour (x + i, y + height - i - 1, width - i * 2, 1, bottomRightColour.withMultipliedAlpha (op), false);
context->fillRectWithColour (x + width - i - 1, y + i + 1, 1, height - i * 2 - 2, bottomRightColour.withMultipliedAlpha (op * 0.75f), false);
}
}
}
//==============================================================================
void Graphics::fillEllipse (const float x,
const float y,
const float width,
const float height) const throw()
{
// passing in a silly number can cause maths problems in rendering!
ASSERT_COORDS_ARE_SENSIBLE_NUMBERS (x, y, width, height);
Path p;
p.addEllipse (x, y, width, height);
fillPath (p);
}
void Graphics::drawEllipse (const float x,
const float y,
const float width,
const float height,
const float lineThickness) const throw()
{
// passing in a silly number can cause maths problems in rendering!
ASSERT_COORDS_ARE_SENSIBLE_NUMBERS (x, y, width, height);
Path p;
p.addEllipse (x, y, width, height);
strokePath (p, PathStrokeType (lineThickness));
}
void Graphics::fillRoundedRectangle (const float x,
const float y,
const float width,
const float height,
const float cornerSize) const throw()
{
// passing in a silly number can cause maths problems in rendering!
ASSERT_COORDS_ARE_SENSIBLE_NUMBERS (x, y, width, height);
Path p;
p.addRoundedRectangle (x, y, width, height, cornerSize);
fillPath (p);
}
void Graphics::fillRoundedRectangle (const Rectangle& r,
const float cornerSize) const throw()
{
fillRoundedRectangle ((float) r.getX(),
(float) r.getY(),
(float) r.getWidth(),
(float) r.getHeight(),
cornerSize);
}
void Graphics::drawRoundedRectangle (const float x,
const float y,
const float width,
const float height,
const float cornerSize,
const float lineThickness) const throw()
{
// passing in a silly number can cause maths problems in rendering!
ASSERT_COORDS_ARE_SENSIBLE_NUMBERS (x, y, width, height);
Path p;
p.addRoundedRectangle (x, y, width, height, cornerSize);
strokePath (p, PathStrokeType (lineThickness));
}
void Graphics::drawRoundedRectangle (const Rectangle& r,
const float cornerSize,
const float lineThickness) const throw()
{
drawRoundedRectangle ((float) r.getX(),
(float) r.getY(),
(float) r.getWidth(),
(float) r.getHeight(),
cornerSize, lineThickness);
}
void Graphics::drawArrow (const float startX,
const float startY,
const float endX,
const float endY,
const float lineThickness,
const float arrowheadWidth,
const float arrowheadLength) const throw()
{
Path p;
p.addArrow (startX, startY, endX, endY,
lineThickness, arrowheadWidth, arrowheadLength);
fillPath (p);
}
void Graphics::fillCheckerBoard (int x, int y,
int width, int height,
const int checkWidth,
const int checkHeight,
const Colour& colour1,
const Colour& colour2) const throw()
{
jassert (checkWidth > 0 && checkHeight > 0); // can't be zero or less!
if (checkWidth > 0 && checkHeight > 0)
{
if (colour1 == colour2)
{
context->fillRectWithColour (x, y, width, height, colour1, false);
}
else
{
const Rectangle clip (context->getClipBounds());
const int right = jmin (x + width, clip.getRight());
const int bottom = jmin (y + height, clip.getBottom());
int cy = 0;
while (y < bottom)
{
int cx = cy;
for (int xx = x; xx < right; xx += checkWidth)
context->fillRectWithColour (xx, y,
jmin (checkWidth, right - xx),
jmin (checkHeight, bottom - y),
((cx++ & 1) == 0) ? colour1 : colour2,
false);
++cy;
y += checkHeight;
}
}
}
}
//==============================================================================
void Graphics::drawVerticalLine (const int x, float top, float bottom) const throw()
{
SolidColourBrush colourBrush (state->colour);
(state->brush != 0 ? *(state->brush) : (Brush&) colourBrush).paintVerticalLine (*context, x, top, bottom);
}
void Graphics::drawHorizontalLine (const int y, float left, float right) const throw()
{
SolidColourBrush colourBrush (state->colour);
(state->brush != 0 ? *(state->brush) : (Brush&) colourBrush).paintHorizontalLine (*context, y, left, right);
}
void Graphics::drawLine (float x1, float y1,
float x2, float y2) const throw()
{
if (! context->isClipEmpty())
{
SolidColourBrush colourBrush (state->colour);
(state->brush != 0 ? *(state->brush) : (Brush&) colourBrush).paintLine (*context, x1, y1, x2, y2);
}
}
void Graphics::drawLine (const float startX,
const float startY,
const float endX,
const float endY,
const float lineThickness) const throw()
{
Path p;
p.addLineSegment (startX, startY, endX, endY, lineThickness);
fillPath (p);
}
void Graphics::drawLine (const Line& line) const throw()
{
drawLine (line.getStartX(), line.getStartY(), line.getEndX(), line.getEndY());
}
void Graphics::drawLine (const Line& line,
const float lineThickness) const throw()
{
drawLine (line.getStartX(), line.getStartY(), line.getEndX(), line.getEndY(), lineThickness);
}
void Graphics::drawDashedLine (const float startX,
const float startY,
const float endX,
const float endY,
const float* const dashLengths,
const int numDashLengths,
const float lineThickness) const throw()
{
const double dx = endX - startX;
const double dy = endY - startY;
const double totalLen = juce_hypot (dx, dy);
if (totalLen >= 0.5)
{
const double onePixAlpha = 1.0 / totalLen;
double alpha = 0.0;
float x = startX;
float y = startY;
int n = 0;
while (alpha < 1.0f)
{
alpha = jmin (1.0, alpha + dashLengths[n++] * onePixAlpha);
n = n % numDashLengths;
const float oldX = x;
const float oldY = y;
x = (float) (startX + dx * alpha);
y = (float) (startY + dy * alpha);
if ((n & 1) != 0)
{
if (lineThickness != 1.0f)
drawLine (oldX, oldY, x, y, lineThickness);
else
drawLine (oldX, oldY, x, y);
}
}
}
}
//==============================================================================
void Graphics::setImageResamplingQuality (const Graphics::ResamplingQuality newQuality) throw()
{
saveStateIfPending();
state->quality = newQuality;
}
//==============================================================================
void Graphics::drawImageAt (const Image* const imageToDraw,
const int topLeftX,
const int topLeftY,
const bool fillAlphaChannelWithCurrentBrush) const throw()
{
if (imageToDraw != 0)
{
const int imageW = imageToDraw->getWidth();
const int imageH = imageToDraw->getHeight();
drawImage (imageToDraw,
topLeftX, topLeftY, imageW, imageH,
0, 0, imageW, imageH,
fillAlphaChannelWithCurrentBrush);
}
}
void Graphics::drawImageWithin (const Image* const imageToDraw,
const int destX,
const int destY,
const int destW,
const int destH,
const RectanglePlacement& placementWithinTarget,
const bool fillAlphaChannelWithCurrentBrush) const throw()
{
// passing in a silly number can cause maths problems in rendering!
ASSERT_COORDS_ARE_SENSIBLE_NUMBERS (destX, destY, destW, destH);
if (imageToDraw != 0)
{
const int imageW = imageToDraw->getWidth();
const int imageH = imageToDraw->getHeight();
if (imageW > 0 && imageH > 0)
{
double newX = 0.0, newY = 0.0;
double newW = imageW;
double newH = imageH;
placementWithinTarget.applyTo (newX, newY, newW, newH,
destX, destY, destW, destH);
if (newW > 0 && newH > 0)
{
drawImage (imageToDraw,
roundDoubleToInt (newX), roundDoubleToInt (newY),
roundDoubleToInt (newW), roundDoubleToInt (newH),
0, 0, imageW, imageH,
fillAlphaChannelWithCurrentBrush);
}
}
}
}
void Graphics::drawImage (const Image* const imageToDraw,
int dx, int dy, int dw, int dh,
int sx, int sy, int sw, int sh,
const bool fillAlphaChannelWithCurrentBrush) const throw()
{
// passing in a silly number can cause maths problems in rendering!
ASSERT_COORDS_ARE_SENSIBLE_NUMBERS (dx, dy, dw, dh);
ASSERT_COORDS_ARE_SENSIBLE_NUMBERS (sx, sy, sw, sh);
if (imageToDraw == 0 || ! context->clipRegionIntersects (dx, dy, dw, dh))
return;
if (sw == dw && sh == dh)
{
if (sx < 0)
{
dx -= sx;
dw += sx;
sw += sx;
sx = 0;
}
if (sx + sw > imageToDraw->getWidth())
{
const int amount = sx + sw - imageToDraw->getWidth();
dw -= amount;
sw -= amount;
}
if (sy < 0)
{
dy -= sy;
dh += sy;
sh += sy;
sy = 0;
}
if (sy + sh > imageToDraw->getHeight())
{
const int amount = sy + sh - imageToDraw->getHeight();
dh -= amount;
sh -= amount;
}
if (dw <= 0 || dh <= 0 || sw <= 0 || sh <= 0)
return;
if (fillAlphaChannelWithCurrentBrush)
{
SolidColourBrush colourBrush (state->colour);
(state->brush != 0 ? *(state->brush) : (Brush&) colourBrush)
.paintAlphaChannel (*context, *imageToDraw,
dx - sx, dy - sy,
dx, dy,
dw, dh);
}
else
{
context->blendImage (*imageToDraw,
dx, dy, dw, dh, sx, sy,
state->colour.getFloatAlpha());
}
}
else
{
if (dw <= 0 || dh <= 0 || sw <= 0 || sh <= 0)
return;
if (fillAlphaChannelWithCurrentBrush)
{
if (imageToDraw->isRGB())
{
fillRect (dx, dy, dw, dh);
}
else
{
int tx = dx;
int ty = dy;
int tw = dw;
int th = dh;
if (context->getClipBounds().intersectRectangle (tx, ty, tw, th))
{
Image temp (imageToDraw->getFormat(), tw, th, true);
Graphics g (temp);
g.setImageResamplingQuality (state->quality);
g.setOrigin (dx - tx, dy - ty);
g.drawImage (imageToDraw,
0, 0, dw, dh,
sx, sy, sw, sh,
false);
SolidColourBrush colourBrush (state->colour);
(state->brush != 0 ? *(state->brush) : (Brush&) colourBrush)
.paintAlphaChannel (*context, temp, tx, ty, tx, ty, tw, th);
}
}
}
else
{
context->blendImageWarping (*imageToDraw,
sx, sy, sw, sh,
AffineTransform::translation ((float) -sx,
(float) -sy)
.scaled (dw / (float) sw,
dh / (float) sh)
.translated ((float) dx,
(float) dy),
state->colour.getFloatAlpha(),
state->quality);
}
}
}
void Graphics::drawImageTransformed (const Image* const imageToDraw,
int sourceClipX,
int sourceClipY,
int sourceClipWidth,
int sourceClipHeight,
const AffineTransform& transform,
const bool fillAlphaChannelWithCurrentBrush) const throw()
{
if (imageToDraw != 0
&& (! context->isClipEmpty())
&& ! transform.isSingularity())
{
if (transform.isIdentity())
{
drawImage (imageToDraw,
sourceClipX, sourceClipY, sourceClipWidth, sourceClipHeight,
sourceClipX, sourceClipY, sourceClipWidth, sourceClipHeight,
fillAlphaChannelWithCurrentBrush);
}
else if (fillAlphaChannelWithCurrentBrush)
{
Path p;
p.addRectangle ((float) sourceClipX, (float) sourceClipY,
(float) sourceClipWidth, (float) sourceClipHeight);
p.applyTransform (transform);
float dx, dy, dw, dh;
p.getBounds (dx, dy, dw, dh);
int tx = (int) dx;
int ty = (int) dy;
int tw = roundFloatToInt (dw) + 2;
int th = roundFloatToInt (dh) + 2;
if (context->getClipBounds().intersectRectangle (tx, ty, tw, th))
{
Image temp (imageToDraw->getFormat(), tw, th, true);
Graphics g (temp);
g.setImageResamplingQuality (state->quality);
g.drawImageTransformed (imageToDraw,
sourceClipX,
sourceClipY,
sourceClipWidth,
sourceClipHeight,
transform.translated ((float) -tx, (float) -ty),
false);
SolidColourBrush colourBrush (state->colour);
(state->brush != 0 ? *(state->brush) : (Brush&) colourBrush).paintAlphaChannel (*context, temp, tx, ty, tx, ty, tw, th);
}
}
else
{
context->blendImageWarping (*imageToDraw,
sourceClipX,
sourceClipY,
sourceClipWidth,
sourceClipHeight,
transform,
state->colour.getFloatAlpha(),
state->quality);
}
}
}
END_JUCE_NAMESPACE