1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-24 01:54:22 +00:00

Created a new method Graphics::beginTransparencyLayer(), to help with compositing semi-transparent rendering.

This commit is contained in:
Julian Storer 2010-11-26 17:29:27 +00:00
parent 640a335537
commit 1629f9f66a
20 changed files with 1202 additions and 993 deletions

File diff suppressed because it is too large Load diff

View file

@ -64,7 +64,7 @@
*/
#define JUCE_MAJOR_VERSION 1
#define JUCE_MINOR_VERSION 52
#define JUCE_BUILDNUMBER 95
#define JUCE_BUILDNUMBER 97
/** Current Juce version number.
@ -4764,7 +4764,7 @@ public:
if (howManyToRemove > numUsed)
howManyToRemove = numUsed;
for (int i = 0; i < howManyToRemove; ++i)
for (int i = 1; i <= howManyToRemove; ++i)
data.elements [numUsed - i].~ElementType();
numUsed -= howManyToRemove;
@ -19586,11 +19586,12 @@ public:
float pivotX, float pivotY) throw();
/** Returns a transform which is the same as this one followed by a shear.
The shear is centred around the origin (0, 0).
*/
const AffineTransform sheared (float shearX,
float shearY) const throw();
const AffineTransform sheared (float shearX, float shearY) const throw();
/** Returns a shear transform, centred around the origin (0, 0). */
static const AffineTransform shear (float shearX, float shearY) throw();
/** Returns a matrix which is the inverse operation of this one.
@ -19648,11 +19649,6 @@ public:
float mat10, mat11, mat12;
juce_UseDebuggingNewOperator
private:
const AffineTransform followedBy (float mat00, float mat01, float mat02,
float mat10, float mat11, float mat12) const throw();
};
#endif // __JUCE_AFFINETRANSFORM_JUCEHEADER__
@ -24949,6 +24945,23 @@ public:
*/
void restoreState();
/** Begins rendering to an off-screen bitmap which will later be flattened onto the current
context with the given opacity.
The context uses an internal stack of temporary image layers to do this. When you've
finished drawing to the layer, call endTransparencyLayer() to complete the operation and
composite the finished layer. Every call to beginTransparencyLayer() MUST be matched
by a corresponding call to endTransparencyLayer()!
This call also saves the current state, and endTransparencyLayer() restores it.
*/
void beginTransparencyLayer (float layerOpacity);
/** Completes a drawing operation to a temporary semi-transparent buffer.
See beginTransparencyLayer() for more details.
*/
void endTransparencyLayer();
/** Moves the position of the context's origin.
This changes the position that the context considers to be (0, 0) to
@ -26182,6 +26195,15 @@ public:
*/
const Rectangle<int> getLocalBounds() const throw();
/** Returns the area of this component's parent which this component covers.
The returned area is relative to the parent's coordinate space.
If the component has an affine transform specified, then the resulting area will be
the smallest rectangle that fully covers the component's transformed bounding box.
If this component has no parent, the return value will simply be the same as getBounds().
*/
const Rectangle<int> getBoundsInParent() const throw();
/** Returns the region of this component that's not obscured by other, opaque components.
The RectangleList that is returned represents the area of this component
@ -27136,7 +27158,18 @@ public:
*/
virtual void enablementChanged();
/** Changes the transparency of this component.
When painted, the entire component and all its children will be rendered
with this as the overall opacity level, where 0 is completely invisible, and
1.0 is fully opaque (i.e. normal).
@see getAlpha
*/
void setAlpha (float newAlpha);
/** Returns the component's current transparancy level.
See setAlpha() for more details.
*/
float getAlpha() const;
/** Changes the mouse cursor shape to use when the mouse is over this component.
@ -37094,14 +37127,15 @@ public:
This is the same as show(), but uses a specific location (in global screen
co-ordinates) rather than the current mouse position.
Note that the co-ordinates don't specify the top-left of the menu - they
indicate a point of interest, and the menu will position itself nearby to
this point, trying to keep it fully on-screen.
The screenAreaToAttachTo parameter indicates a screen area to which the menu
will be adjacent. Depending on where this is, the menu will decide which edge to
attach itself to, in order to fit itself fully on-screen. If you just want to
trigger a menu at a specific point, you can pass in a rectangle of size (0, 0)
with the position that you want.
@see show()
*/
int showAt (int screenX,
int screenY,
int showAt (const Rectangle<int>& screenAreaToAttachTo,
int itemIdThatMustBeVisible = 0,
int minimumWidth = 0,
int maximumNumColumns = 0,
@ -37229,14 +37263,9 @@ private:
void addSeparatorIfPending();
int showMenu (const Rectangle<int>& target,
int itemIdThatMustBeVisible,
int minimumWidth,
int maximumNumColumns,
int standardItemHeight,
bool alignToRectangle,
Component* componentAttachedTo,
ModalComponentManager::Callback* callback);
int showMenu (const Rectangle<int>& target, int itemIdThatMustBeVisible,
int minimumWidth, int maximumNumColumns, int standardItemHeight,
Component* componentAttachedTo, ModalComponentManager::Callback* callback);
};
#endif // __JUCE_POPUPMENU_JUCEHEADER__
@ -40605,6 +40634,12 @@ public:
/** The name of the plugin. */
String name;
/** A more descriptive name for the plugin.
This may be the same as the 'name' field, but some plugins may provide an
alternative name.
*/
String descriptiveName;
/** The plugin format, e.g. "VST", "AudioUnit", etc.
*/
String pluginFormatName;
@ -44814,7 +44849,7 @@ class DrawableComposite;
@see DrawableComposite, DrawableImage, DrawablePath, DrawableText
*/
class JUCE_API Drawable
class JUCE_API Drawable : public Component
{
protected:
@ -44835,6 +44870,11 @@ public:
virtual Drawable* createCopy() const = 0;
/** Renders this Drawable object.
Note that the preferred way to render a drawable in future is by using it
as a component and adding it to a parent, so you might want to consider that
before using this method.
@see drawWithin
*/
void draw (Graphics& g, float opacity,
@ -44848,10 +44888,12 @@ public:
@code
draw (g, AffineTransform::translation (x, y)).
@endcode
Note that the preferred way to render a drawable in future is by using it
as a component and adding it to a parent, so you might want to consider that
before using this method.
*/
void drawAt (Graphics& g,
float x, float y,
float opacity) const;
void drawAt (Graphics& g, float x, float y, float opacity) const;
/** Renders the Drawable within a rectangle, scaling it to fit neatly inside without
changing its aspect-ratio.
@ -44859,6 +44901,10 @@ public:
The object can placed arbitrarily within the rectangle based on a Justification type,
and can either be made as big as possible, or just reduced to fit.
Note that the preferred way to render a drawable in future is by using it
as a component and adding it to a parent, so you might want to consider that
before using this method.
@param g the graphics context to render onto
@param destArea the target rectangle to fit the drawable into
@param placement defines the alignment and rescaling to use to fit
@ -44870,49 +44916,18 @@ public:
const RectanglePlacement& placement,
float opacity) const;
/** Holds the information needed when telling a drawable to render itself.
@see Drawable::draw
/** Resets any transformations on this drawable, and positions its origin within
its parent component.
*/
class RenderingContext
{
public:
RenderingContext (Graphics& g, const AffineTransform& transform, float opacity) throw();
void setOriginWithOriginalSize (const Point<float>& originWithinParent);
Graphics& g;
AffineTransform transform;
float opacity;
private:
RenderingContext& operator= (const RenderingContext&);
};
/** Renders this Drawable object.
@see draw
/** Sets a transform for this drawable that will position it within the specified
area of its parent component.
*/
virtual void render (const RenderingContext& context) const = 0;
/** Returns the smallest rectangle that can contain this Drawable object.
Co-ordinates are relative to the object's own origin.
*/
virtual const Rectangle<float> getBounds() const = 0;
/** Returns true if the given point is somewhere inside this Drawable.
Co-ordinates are relative to the object's own origin.
*/
virtual bool hitTest (float x, float y) const = 0;
/** Returns the name given to this drawable.
@see setName
*/
const String& getName() const throw() { return name; }
/** Assigns a name to this drawable. */
void setName (const String& newName) throw() { name = newName; }
void setTransformToFit (const Rectangle<float>& areaInParent, const RectanglePlacement& placement);
/** Returns the DrawableComposite that contains this object, if there is one. */
DrawableComposite* getParent() const throw() { return parent; }
DrawableComposite* getParent() const;
/** Tries to turn some kind of image file into a drawable.
@ -44982,7 +44997,7 @@ public:
/** Tries to refresh a Drawable from the same ValueTree that was used to create it.
@returns the damage rectangle that will need repainting due to any changes that were made.
*/
virtual const Rectangle<float> refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider) = 0;
virtual void refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider) = 0;
/** Creates a ValueTree to represent this Drawable.
The VarTree that is returned can be turned back into a Drawable with
@ -44995,6 +45010,12 @@ public:
/** Returns the tag ID that is used for a ValueTree that stores this type of drawable. */
virtual const Identifier getValueTreeType() const = 0;
/** Returns the area that this drawble covers.
The result is expressed in this drawable's own coordinate space, and does not take
into account any transforms that may be applied to the component.
*/
virtual const Rectangle<float> getDrawableBounds() const = 0;
/** Internal class used to manage ValueTrees that represent Drawables. */
class ValueTreeWrapperBase
{
@ -45015,15 +45036,23 @@ public:
protected:
friend class DrawableComposite;
/** @internal */
DrawableComposite* parent;
/** @internal */
virtual void invalidatePoints() = 0;
friend class DrawableShape;
/** @internal */
static Drawable* createChildFromValueTree (DrawableComposite* parent, const ValueTree& tree, ImageProvider* imageProvider);
/** @internal */
void transformContextToCorrectOrigin (Graphics& g);
/** @internal */
void markerHasMoved();
/** @internal */
void parentHierarchyChanged();
/** @internal */
void setBoundsToEnclose (const Rectangle<float>& area);
Point<int> originRelativeToComponent;
private:
String name;
void nonConstDraw (Graphics& g, float opacity, const AffineTransform& transform);
Drawable (const Drawable&);
Drawable& operator= (const Drawable&);
@ -45143,10 +45172,10 @@ public:
void setEdgeIndent (int numPixelsIndent);
/** Returns the image that the button is currently displaying. */
const Drawable* getCurrentImage() const throw();
const Drawable* getNormalImage() const throw();
const Drawable* getOverImage() const throw();
const Drawable* getDownImage() const throw();
Drawable* getCurrentImage() const throw();
Drawable* getNormalImage() const throw();
Drawable* getOverImage() const throw();
Drawable* getDownImage() const throw();
/** A set of colour IDs to use to change the colour of various aspects of the link.
@ -45167,16 +45196,20 @@ protected:
void paintButton (Graphics& g,
bool isMouseOverButton,
bool isButtonDown);
/** @internal */
void buttonStateChanged();
/** @internal */
void resized();
private:
ButtonStyle style;
ScopedPointer <Drawable> normalImage, overImage, downImage, disabledImage;
ScopedPointer <Drawable> normalImageOn, overImageOn, downImageOn, disabledImageOn;
Drawable* currentImage;
Colour backgroundOff, backgroundOn;
int edgeIndent;
void deleteImages();
DrawableButton (const DrawableButton&);
DrawableButton& operator= (const DrawableButton&);
};
@ -46347,11 +46380,20 @@ public:
void paintButtonArea (Graphics& g, int width, int height, bool isMouseOver, bool isMouseDown);
/** @internal */
void contentAreaChanged (const Rectangle<int>& newBounds);
/** @internal */
void buttonStateChanged();
/** @internal */
void resized();
/** @internal */
void enablementChanged();
juce_UseDebuggingNewOperator
private:
ScopedPointer <Drawable> normalImage, toggledOnImage;
ScopedPointer<Drawable> normalImage, toggledOnImage;
Drawable* currentImage;
void updateDrawable();
ToolbarButton (const ToolbarButton&);
ToolbarButton& operator= (const ToolbarButton&);
@ -59940,10 +59982,10 @@ public:
/** Destructor. */
~EdgeTable();
void clipToRectangle (const Rectangle<int>& r) throw();
void excludeRectangle (const Rectangle<int>& r) throw();
void clipToRectangle (const Rectangle<int>& r);
void excludeRectangle (const Rectangle<int>& r);
void clipToEdgeTable (const EdgeTable& other);
void clipLineToMask (int x, int y, const uint8* mask, int maskStride, int numPixels) throw();
void clipLineToMask (int x, int y, const uint8* mask, int maskStride, int numPixels);
bool isEmpty() throw();
const Rectangle<int>& getMaximumBounds() const throw() { return bounds; }
void translate (float dx, int dy) throw();
@ -59953,7 +59995,7 @@ public:
This will shrink the table down to use as little memory as possible - useful for
read-only tables that get stored and re-used for rendering.
*/
void optimiseTable() throw();
void optimiseTable();
/** Iterates the lines in the table, for rendering.
@ -60061,9 +60103,9 @@ private:
int maxEdgesPerLine, lineStrideElements;
bool needToCheckEmptinesss;
void addEdgePoint (int x, int y, int winding) throw();
void remapTableForNumEdges (int newNumEdgesPerLine) throw();
void intersectWithEdgeTableLine (int y, const int* otherLine) throw();
void addEdgePoint (int x, int y, int winding);
void remapTableForNumEdges (int newNumEdgesPerLine);
void intersectWithEdgeTableLine (int y, const int* otherLine);
void clipEdgeTableLineToRange (int* line, int x1, int x2) throw();
void sanitiseLevels (bool useNonZeroWinding) throw();
static void copyEdgeTableData (int* dest, int destLineStride, const int* src, int srcLineStride, int numLines) throw();
@ -60247,6 +60289,9 @@ public:
virtual void saveState() = 0;
virtual void restoreState() = 0;
virtual void beginTransparencyLayer (float opacity) = 0;
virtual void endTransparencyLayer() = 0;
virtual void setFill (const FillType& fillType) = 0;
virtual void setOpacity (float newOpacity) = 0;
virtual void setInterpolationQuality (Graphics::ResamplingQuality quality) = 0;
@ -60305,6 +60350,9 @@ public:
void saveState();
void restoreState();
void beginTransparencyLayer (float opacity);
void endTransparencyLayer();
bool clipRegionIntersects (const Rectangle<int>& r);
const Rectangle<int> getClipBounds() const;
bool isClipEmpty() const;
@ -60407,6 +60455,9 @@ public:
void saveState();
void restoreState();
void beginTransparencyLayer (float opacity);
void endTransparencyLayer();
void setFill (const FillType& fillType);
void setOpacity (float opacity);
void setInterpolationQuality (Graphics::ResamplingQuality quality);
@ -60524,7 +60575,7 @@ public:
@see getDrawable
*/
int getNumDrawables() const throw() { return drawables.size(); }
int getNumDrawables() const throw();
/** Returns one of the drawables that are contained in this one.
@ -60536,7 +60587,7 @@ public:
@see getNumDrawables
*/
Drawable* getDrawable (int index) const throw() { return drawables [index]; }
Drawable* getDrawable (int index) const;
/** Looks for a child drawable with the specified name. */
Drawable* getDrawableWithName (const String& name) const throw();
@ -60549,20 +60600,6 @@ public:
*/
void bringToFront (int index);
/** Returns the main content rectangle.
The content area is actually defined by the markers named "left", "right", "top" and
"bottom", but this method is a shortcut that returns them all at once.
@see contentLeftMarkerName, contentRightMarkerName, contentTopMarkerName, contentBottomMarkerName
*/
const RelativeRectangle getContentArea() const;
/** Changes the main content area.
The content area is actually defined by the markers named "left", "right", "top" and
"bottom", but this method is a shortcut that sets them all at once.
@see setBoundingBox, contentLeftMarkerName, contentRightMarkerName, contentTopMarkerName, contentBottomMarkerName
*/
void setContentArea (const RelativeRectangle& newArea);
/** Sets the parallelogram that defines the target position of the content rectangle when the drawable is rendered.
@see setContentArea
*/
@ -60578,6 +60615,20 @@ public:
*/
void resetBoundingBoxToContentArea();
/** Returns the main content rectangle.
The content area is actually defined by the markers named "left", "right", "top" and
"bottom", but this method is a shortcut that returns them all at once.
@see contentLeftMarkerName, contentRightMarkerName, contentTopMarkerName, contentBottomMarkerName
*/
const RelativeRectangle getContentArea() const;
/** Changes the main content area.
The content area is actually defined by the markers named "left", "right", "top" and
"bottom", but this method is a shortcut that sets them all at once.
@see setBoundingBox, contentLeftMarkerName, contentRightMarkerName, contentTopMarkerName, contentBottomMarkerName
*/
void setContentArea (const RelativeRectangle& newArea);
/** Resets the content area and the bounding transform to fit around the area occupied
by the child components (ignoring any markers).
*/
@ -60610,18 +60661,10 @@ public:
/** The name of the marker that defines the bottom edge of the content area. */
static const char* const contentBottomMarkerName;
/** @internal */
void render (const Drawable::RenderingContext& context) const;
/** @internal */
const Rectangle<float> getBounds() const;
/** @internal */
bool hitTest (float x, float y) const;
/** @internal */
Drawable* createCopy() const;
/** @internal */
void invalidatePoints();
/** @internal */
const Rectangle<float> refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider);
void refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider);
/** @internal */
const ValueTree createValueTree (ImageProvider* imageProvider) const;
/** @internal */
@ -60630,6 +60673,16 @@ public:
const Identifier getValueTreeType() const { return valueTreeType; }
/** @internal */
const Expression getSymbolValue (const String& symbol, const String& member) const;
/** @internal */
const Rectangle<float> getDrawableBounds() const;
/** @internal */
void markerHasMoved();
/** @internal */
void childBoundsChanged (Component*);
/** @internal */
void childrenChanged();
/** @internal */
void parentHierarchyChanged();
/** Internally-used class for wrapping a DrawableComposite's state into a ValueTree. */
class ValueTreeWrapper : public Drawable::ValueTreeWrapperBase
@ -60674,12 +60727,12 @@ public:
juce_UseDebuggingNewOperator
private:
OwnedArray <Drawable> drawables;
RelativeParallelogram bounds;
OwnedArray <Marker> markersX, markersY;
bool updateBoundsReentrant;
const Rectangle<float> getUntransformedBounds (bool includeMarkers) const;
const AffineTransform calculateTransform() const;
void refreshTransformFromBounds();
void updateBoundsToFitChildren();
DrawableComposite& operator= (const DrawableComposite&);
};
@ -60746,17 +60799,15 @@ public:
const RelativeParallelogram& getBoundingBox() const throw() { return bounds; }
/** @internal */
void render (const Drawable::RenderingContext& context) const;
void paint (Graphics& g);
/** @internal */
const Rectangle<float> getBounds() const;
/** @internal */
bool hitTest (float x, float y) const;
bool hitTest (int x, int y) const;
/** @internal */
Drawable* createCopy() const;
/** @internal */
void invalidatePoints();
const Rectangle<float> getDrawableBounds() const;
/** @internal */
const Rectangle<float> refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider);
void refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider);
/** @internal */
const ValueTree createValueTree (ImageProvider* imageProvider) const;
/** @internal */
@ -60796,7 +60847,7 @@ private:
Colour overlayColour;
RelativeParallelogram bounds;
const AffineTransform calculateTransform() const;
void refreshTransformFromBounds();
DrawableImage& operator= (const DrawableImage&);
};
@ -60910,13 +60961,11 @@ public:
};
/** @internal */
void invalidatePoints();
const Rectangle<float> getDrawableBounds() const;
/** @internal */
void render (const Drawable::RenderingContext& context) const;
void paint (Graphics& g);
/** @internal */
const Rectangle<float> getBounds() const;
/** @internal */
bool hitTest (float x, float y) const;
bool hitTest (int x, int y) const;
protected:
@ -60939,19 +60988,11 @@ protected:
/** Writes the stroke and fill details to a FillAndStrokeState object. */
void writeTo (FillAndStrokeState& state, ImageProvider* imageProvider, UndoManager* undoManager) const;
/** Returns the current cached path outline. */
const Path& getCachedPath() const;
/** Returns the current cached stroke outline. */
const Path& getCachedStrokePath() const;
PathStrokeType strokeType;
mutable Path cachedPath, cachedStroke;
Path path, strokePath;
private:
FillType mainFill, strokeFill;
mutable bool pathNeedsUpdating, strokeNeedsUpdating;
static void setBrush (const Drawable::RenderingContext& context, const FillType& type);
DrawableShape& operator= (const DrawableShape&);
};
@ -60991,7 +61032,7 @@ public:
/** @internal */
Drawable* createCopy() const;
/** @internal */
const Rectangle<float> refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider);
void refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider);
/** @internal */
const ValueTree createValueTree (ImageProvider* imageProvider) const;
/** @internal */
@ -61105,7 +61146,7 @@ public:
/** @internal */
Drawable* createCopy() const;
/** @internal */
const Rectangle<float> refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider);
void refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider);
/** @internal */
const ValueTree createValueTree (ImageProvider* imageProvider) const;
/** @internal */
@ -61211,23 +61252,19 @@ public:
void setFontSizeControlPoint (const RelativePoint& newPoint);
/** @internal */
void render (const Drawable::RenderingContext& context) const;
/** @internal */
const Rectangle<float> getBounds() const;
/** @internal */
bool hitTest (float x, float y) const;
void paint (Graphics& g);
/** @internal */
Drawable* createCopy() const;
/** @internal */
void invalidatePoints();
/** @internal */
const Rectangle<float> refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider);
void refreshFromValueTree (const ValueTree& tree, ImageProvider* imageProvider);
/** @internal */
const ValueTree createValueTree (ImageProvider* imageProvider) const;
/** @internal */
static const Identifier valueTreeType;
/** @internal */
const Identifier getValueTreeType() const { return valueTreeType; }
/** @internal */
const Rectangle<float> getDrawableBounds() const;
/** Internally-used class for wrapping a DrawableText's state into a ValueTree. */
class ValueTreeWrapper : public Drawable::ValueTreeWrapperBase
@ -61268,6 +61305,8 @@ private:
Colour colour;
Justification justification;
void refreshBounds();
DrawableText& operator= (const DrawableText&);
};

View file

@ -779,7 +779,7 @@ public:
if (howManyToRemove > numUsed)
howManyToRemove = numUsed;
for (int i = 0; i < howManyToRemove; ++i)
for (int i = 1; i <= howManyToRemove; ++i)
data.elements [numUsed - i].~ElementType();
numUsed -= howManyToRemove;

View file

@ -33,7 +33,7 @@
*/
#define JUCE_MAJOR_VERSION 1
#define JUCE_MINOR_VERSION 52
#define JUCE_BUILDNUMBER 96
#define JUCE_BUILDNUMBER 97
/** Current Juce version number.

View file

@ -431,7 +431,7 @@ void Button::mouseUp (const MouseEvent& e)
internalClickCallback (e.mods);
}
void Button::mouseDrag (const MouseEvent& e)
void Button::mouseDrag (const MouseEvent&)
{
const ButtonState oldState = buttonState;
updateState (isMouseOver(), true);

View file

@ -1836,7 +1836,7 @@ void Component::paintComponentAndChildren (Graphics& g)
g.saveState();
g.addTransform (*child.affineTransform_);
if (child.flags.dontClipGraphicsFlag || g.reduceClipRegion (child.getBounds()))
if ((child.flags.dontClipGraphicsFlag && ! g.isClipEmpty()) || g.reduceClipRegion (child.getBounds()))
child.paintWithinParentContext (g);
g.restoreState();
@ -1904,17 +1904,9 @@ void Component::paintEntireComponent (Graphics& g, const bool ignoreAlphaLevel)
{
if (componentTransparency < 255)
{
Image temp (flags.opaqueFlag ? Image::RGB : Image::ARGB,
getWidth(), getHeight(), ! flags.opaqueFlag, Image::NativeImage);
{
Graphics tempG (temp);
tempG.reduceClipRegion (g.getClipBounds());
paintEntireComponent (tempG, true);
}
g.setColour (Colours::black.withAlpha (getAlpha()));
g.drawImageAt (temp, 0, 0);
g.beginTransparencyLayer (getAlpha());
paintComponentAndChildren (g);
g.endTransparencyLayer();
}
}
else

View file

@ -329,7 +329,7 @@ void EdgeTable::sanitiseLevels (const bool useNonZeroWinding) throw()
}
}
void EdgeTable::remapTableForNumEdges (const int newNumEdgesPerLine) throw()
void EdgeTable::remapTableForNumEdges (const int newNumEdgesPerLine)
{
if (newNumEdgesPerLine != maxEdgesPerLine)
{
@ -347,7 +347,7 @@ void EdgeTable::remapTableForNumEdges (const int newNumEdgesPerLine) throw()
}
}
void EdgeTable::optimiseTable() throw()
void EdgeTable::optimiseTable()
{
int maxLineElements = 0;
@ -357,7 +357,7 @@ void EdgeTable::optimiseTable() throw()
remapTableForNumEdges (maxLineElements);
}
void EdgeTable::addEdgePoint (const int x, const int y, const int winding) throw()
void EdgeTable::addEdgePoint (const int x, const int y, const int winding)
{
jassert (y >= 0 && y < bounds.getHeight());
@ -421,7 +421,7 @@ void EdgeTable::translate (float dx, const int dy) throw()
}
}
void EdgeTable::intersectWithEdgeTableLine (const int y, const int* otherLine) throw()
void EdgeTable::intersectWithEdgeTableLine (const int y, const int* otherLine)
{
jassert (y >= 0 && y < bounds.getHeight());
@ -588,7 +588,7 @@ void EdgeTable::clipEdgeTableLineToRange (int* dest, const int x1, const int x2)
//==============================================================================
void EdgeTable::clipToRectangle (const Rectangle<int>& r) throw()
void EdgeTable::clipToRectangle (const Rectangle<int>& r)
{
const Rectangle<int> clipped (r.getIntersection (bounds));
@ -630,7 +630,7 @@ void EdgeTable::clipToRectangle (const Rectangle<int>& r) throw()
}
}
void EdgeTable::excludeRectangle (const Rectangle<int>& r) throw()
void EdgeTable::excludeRectangle (const Rectangle<int>& r)
{
const Rectangle<int> clipped (r.getIntersection (bounds));
@ -689,7 +689,7 @@ void EdgeTable::clipToEdgeTable (const EdgeTable& other)
}
}
void EdgeTable::clipLineToMask (int x, int y, const uint8* mask, int maskStride, int numPixels) throw()
void EdgeTable::clipLineToMask (int x, int y, const uint8* mask, int maskStride, int numPixels)
{
y -= bounds.getY();

View file

@ -79,10 +79,10 @@ public:
~EdgeTable();
//==============================================================================
void clipToRectangle (const Rectangle<int>& r) throw();
void excludeRectangle (const Rectangle<int>& r) throw();
void clipToRectangle (const Rectangle<int>& r);
void excludeRectangle (const Rectangle<int>& r);
void clipToEdgeTable (const EdgeTable& other);
void clipLineToMask (int x, int y, const uint8* mask, int maskStride, int numPixels) throw();
void clipLineToMask (int x, int y, const uint8* mask, int maskStride, int numPixels);
bool isEmpty() throw();
const Rectangle<int>& getMaximumBounds() const throw() { return bounds; }
void translate (float dx, int dy) throw();
@ -92,7 +92,7 @@ public:
This will shrink the table down to use as little memory as possible - useful for
read-only tables that get stored and re-used for rendering.
*/
void optimiseTable() throw();
void optimiseTable();
//==============================================================================
@ -203,9 +203,9 @@ private:
int maxEdgesPerLine, lineStrideElements;
bool needToCheckEmptinesss;
void addEdgePoint (int x, int y, int winding) throw();
void remapTableForNumEdges (int newNumEdgesPerLine) throw();
void intersectWithEdgeTableLine (int y, const int* otherLine) throw();
void addEdgePoint (int x, int y, int winding);
void remapTableForNumEdges (int newNumEdgesPerLine);
void intersectWithEdgeTableLine (int y, const int* otherLine);
void clipEdgeTableLineToRange (int* line, int x1, int x2) throw();
void sanitiseLevels (bool useNonZeroWinding) throw();
static void copyEdgeTableData (int* dest, int destLineStride, const int* src, int srcLineStride, int numLines) throw();

View file

@ -176,6 +176,17 @@ bool Graphics::clipRegionIntersects (const Rectangle<int>& area) const
return context->clipRegionIntersects (area);
}
void Graphics::beginTransparencyLayer (float layerOpacity)
{
saveStateIfPending();
context->beginTransparencyLayer (layerOpacity);
}
void Graphics::endTransparencyLayer()
{
context->endTransparencyLayer();
}
//==============================================================================
void Graphics::setColour (const Colour& newColour)
{

View file

@ -613,6 +613,23 @@ public:
*/
void restoreState();
/** Begins rendering to an off-screen bitmap which will later be flattened onto the current
context with the given opacity.
The context uses an internal stack of temporary image layers to do this. When you've
finished drawing to the layer, call endTransparencyLayer() to complete the operation and
composite the finished layer. Every call to beginTransparencyLayer() MUST be matched
by a corresponding call to endTransparencyLayer()!
This call also saves the current state, and endTransparencyLayer() restores it.
*/
void beginTransparencyLayer (float layerOpacity);
/** Completes a drawing operation to a temporary semi-transparent buffer.
See beginTransparencyLayer() for more details.
*/
void endTransparencyLayer();
/** Moves the position of the context's origin.
This changes the position that the context considers to be (0, 0) to

View file

@ -81,6 +81,9 @@ public:
virtual void saveState() = 0;
virtual void restoreState() = 0;
virtual void beginTransparencyLayer (float opacity) = 0;
virtual void endTransparencyLayer() = 0;
//==============================================================================
virtual void setFill (const FillType& fillType) = 0;
virtual void setOpacity (float newOpacity) = 0;

View file

@ -192,6 +192,14 @@ void LowLevelGraphicsPostScriptRenderer::restoreState()
stateStack.removeLast();
}
void LowLevelGraphicsPostScriptRenderer::beginTransparencyLayer (float)
{
}
void LowLevelGraphicsPostScriptRenderer::endTransparencyLayer()
{
}
//==============================================================================
void LowLevelGraphicsPostScriptRenderer::writeClip()
{

View file

@ -60,6 +60,9 @@ public:
void saveState();
void restoreState();
void beginTransparencyLayer (float opacity);
void endTransparencyLayer();
bool clipRegionIntersects (const Rectangle<int>& r);
const Rectangle<int> getClipBounds() const;
bool isClipEmpty() const;

View file

@ -1045,6 +1045,7 @@ public:
virtual const Ptr clipToPath (const Path& p, const AffineTransform& transform) = 0;
virtual const Ptr clipToEdgeTable (const EdgeTable& et) = 0;
virtual const Ptr clipToImageAlpha (const Image& image, const AffineTransform& t, const bool betterQuality) = 0;
virtual const Ptr translated (const Point<int>& delta) = 0;
virtual bool clipRegionIntersects (const Rectangle<int>& r) const = 0;
virtual const Rectangle<int> getClipBounds() const = 0;
@ -1327,6 +1328,12 @@ public:
return edgeTable.isEmpty() ? 0 : this;
}
const Ptr translated (const Point<int>& delta)
{
edgeTable.translate ((float) delta.getX(), delta.getY());
return edgeTable.isEmpty() ? 0 : this;
}
bool clipRegionIntersects (const Rectangle<int>& r) const
{
return edgeTable.getMaximumBounds().intersects (r);
@ -1479,6 +1486,12 @@ public:
return Ptr (new ClipRegion_EdgeTable (clip))->clipToImageAlpha (image, transform, betterQuality);
}
const Ptr translated (const Point<int>& delta)
{
clip.offsetAll (delta.getX(), delta.getY());
return clip.isEmpty() ? 0 : this;
}
bool clipRegionIntersects (const Rectangle<int>& r) const
{
return clip.intersects (r);
@ -1788,21 +1801,25 @@ private:
class LowLevelGraphicsSoftwareRenderer::SavedState
{
public:
SavedState (const Rectangle<int>& clip_, const int xOffset_, const int yOffset_)
: clip (new SoftwareRendererClasses::ClipRegion_RectangleList (clip_)),
xOffset (xOffset_), yOffset (yOffset_), isOnlyTranslated (true), interpolationQuality (Graphics::mediumResamplingQuality)
SavedState (const Image& image_, const Rectangle<int>& clip_, const int xOffset_, const int yOffset_)
: image (image_), clip (new SoftwareRendererClasses::ClipRegion_RectangleList (clip_)),
xOffset (xOffset_), yOffset (yOffset_), compositionAlpha (1.0f),
isOnlyTranslated (true), interpolationQuality (Graphics::mediumResamplingQuality)
{
}
SavedState (const RectangleList& clip_, const int xOffset_, const int yOffset_)
: clip (new SoftwareRendererClasses::ClipRegion_RectangleList (clip_)),
xOffset (xOffset_), yOffset (yOffset_), isOnlyTranslated (true), interpolationQuality (Graphics::mediumResamplingQuality)
SavedState (const Image& image_, const RectangleList& clip_, const int xOffset_, const int yOffset_)
: image (image_), clip (new SoftwareRendererClasses::ClipRegion_RectangleList (clip_)),
xOffset (xOffset_), yOffset (yOffset_), compositionAlpha (1.0f),
isOnlyTranslated (true), interpolationQuality (Graphics::mediumResamplingQuality)
{
}
SavedState (const SavedState& other)
: clip (other.clip), complexTransform (other.complexTransform), xOffset (other.xOffset), yOffset (other.yOffset),
isOnlyTranslated (other.isOnlyTranslated), font (other.font), fillType (other.fillType), interpolationQuality (other.interpolationQuality)
: image (other.image), clip (other.clip), complexTransform (other.complexTransform),
xOffset (other.xOffset), yOffset (other.yOffset), compositionAlpha (other.compositionAlpha),
isOnlyTranslated (other.isOnlyTranslated), font (other.font), fillType (other.fillType),
interpolationQuality (other.interpolationQuality)
{
}
@ -1937,6 +1954,11 @@ public:
return false;
}
const Rectangle<int> getUntransformedClipBounds() const
{
return clip != 0 ? clip->getClipBounds() : Rectangle<int>();
}
const Rectangle<int> getClipBounds() const
{
if (clip != 0)
@ -1950,8 +1972,41 @@ public:
return Rectangle<int>();
}
SavedState* beginTransparencyLayer (float opacity)
{
const Rectangle<int> clip (getUntransformedClipBounds());
SavedState* s = new SavedState (*this);
s->image = Image (Image::ARGB, clip.getWidth(), clip.getHeight(), true);
s->compositionAlpha = opacity;
if (s->isOnlyTranslated)
{
s->xOffset -= clip.getX();
s->yOffset -= clip.getY();
}
else
{
s->complexTransform = s->complexTransform.followedBy (AffineTransform::translation ((float) -clip.getX(), (float) -clip.getY()));
}
s->cloneClipIfMultiplyReferenced();
s->clip = s->clip->translated (-clip.getPosition());
return s;
}
void endTransparencyLayer (SavedState& layerState)
{
const Rectangle<int> clip (getUntransformedClipBounds());
const ScopedPointer<LowLevelGraphicsContext> g (image.createLowLevelContext());
g->setOpacity (layerState.compositionAlpha);
g->drawImage (layerState.image, AffineTransform::translation ((float) clip.getX(),
(float) clip.getY()), false);
}
//==============================================================================
void fillRect (Image& image, const Rectangle<int>& r, const bool replaceContents)
void fillRect (const Rectangle<int>& r, const bool replaceContents)
{
if (clip != 0)
{
@ -1968,19 +2023,19 @@ public:
const Rectangle<int> clipped (totalClip.getIntersection (r.translated (xOffset, yOffset)));
if (! clipped.isEmpty())
fillShape (image, new SoftwareRendererClasses::ClipRegion_RectangleList (clipped), false);
fillShape (new SoftwareRendererClasses::ClipRegion_RectangleList (clipped), false);
}
}
else
{
Path p;
p.addRectangle (r);
fillPath (image, p, AffineTransform::identity);
fillPath (p, AffineTransform::identity);
}
}
}
void fillRect (Image& image, const Rectangle<float>& r)
void fillRect (const Rectangle<float>& r)
{
if (clip != 0)
{
@ -1997,25 +2052,25 @@ public:
const Rectangle<float> clipped (totalClip.getIntersection (r.translated ((float) xOffset, (float) yOffset)));
if (! clipped.isEmpty())
fillShape (image, new SoftwareRendererClasses::ClipRegion_EdgeTable (clipped), false);
fillShape (new SoftwareRendererClasses::ClipRegion_EdgeTable (clipped), false);
}
}
else
{
Path p;
p.addRectangle (r);
fillPath (image, p, AffineTransform::identity);
fillPath (p, AffineTransform::identity);
}
}
}
void fillPath (Image& image, const Path& path, const AffineTransform& transform)
void fillPath (const Path& path, const AffineTransform& transform)
{
if (clip != 0)
fillShape (image, new SoftwareRendererClasses::ClipRegion_EdgeTable (clip->getClipBounds(), path, getTransformWith (transform)), false);
fillShape (new SoftwareRendererClasses::ClipRegion_EdgeTable (clip->getClipBounds(), path, getTransformWith (transform)), false);
}
void fillEdgeTable (Image& image, const EdgeTable& edgeTable, const float x, const int y)
void fillEdgeTable (const EdgeTable& edgeTable, const float x, const int y)
{
jassert (isOnlyTranslated);
@ -2024,11 +2079,11 @@ public:
SoftwareRendererClasses::ClipRegion_EdgeTable* edgeTableClip = new SoftwareRendererClasses::ClipRegion_EdgeTable (edgeTable);
SoftwareRendererClasses::ClipRegionBase::Ptr shapeToFill (edgeTableClip);
edgeTableClip->edgeTable.translate (x + xOffset, y + yOffset);
fillShape (image, shapeToFill, false);
fillShape (shapeToFill, false);
}
}
void fillShape (Image& image, SoftwareRendererClasses::ClipRegionBase::Ptr shapeToFill, const bool replaceContents)
void fillShape (SoftwareRendererClasses::ClipRegionBase::Ptr shapeToFill, const bool replaceContents)
{
jassert (clip != 0);
@ -2060,7 +2115,7 @@ public:
}
else if (fillType.isTiledImage())
{
renderImage (image, fillType.image, fillType.transform, shapeToFill);
renderImage (fillType.image, fillType.transform, shapeToFill);
}
else
{
@ -2070,11 +2125,11 @@ public:
}
//==============================================================================
void renderImage (Image& destImage, const Image& sourceImage, const AffineTransform& t, const SoftwareRendererClasses::ClipRegionBase* const tiledFillClipRegion)
void renderImage (const Image& sourceImage, const AffineTransform& t, const SoftwareRendererClasses::ClipRegionBase* const tiledFillClipRegion)
{
const AffineTransform transform (getTransformWith (t));
const Image::BitmapData destData (destImage, true);
const Image::BitmapData destData (image, true);
const Image::BitmapData srcData (sourceImage, false);
const int alpha = fillType.colour.getAlpha();
const bool betterQuality = (interpolationQuality != Graphics::lowResamplingQuality);
@ -2096,7 +2151,7 @@ public:
}
else
{
SoftwareRendererClasses::ClipRegionBase::Ptr c (new SoftwareRendererClasses::ClipRegion_EdgeTable (Rectangle<int> (tx, ty, sourceImage.getWidth(), sourceImage.getHeight()).getIntersection (destImage.getBounds())));
SoftwareRendererClasses::ClipRegionBase::Ptr c (new SoftwareRendererClasses::ClipRegion_EdgeTable (Rectangle<int> (tx, ty, sourceImage.getWidth(), sourceImage.getHeight()).getIntersection (image.getBounds())));
c = clip->applyClipTo (c);
if (c != 0)
@ -2128,11 +2183,13 @@ public:
}
//==============================================================================
Image image;
SoftwareRendererClasses::ClipRegionBase::Ptr clip;
private:
AffineTransform complexTransform;
int xOffset, yOffset;
float compositionAlpha;
public:
bool isOnlyTranslated;
@ -2170,16 +2227,16 @@ private:
//==============================================================================
LowLevelGraphicsSoftwareRenderer::LowLevelGraphicsSoftwareRenderer (const Image& image_)
: image (image_)
: image (image_),
currentState (new SavedState (image_, image_.getBounds(), 0, 0))
{
currentState = new SavedState (image_.getBounds(), 0, 0);
}
LowLevelGraphicsSoftwareRenderer::LowLevelGraphicsSoftwareRenderer (const Image& image_, const int xOffset, const int yOffset,
const RectangleList& initialClip)
: image (image_)
: image (image_),
currentState (new SavedState (image_, initialClip, xOffset, yOffset))
{
currentState = new SavedState (initialClip, xOffset, yOffset);
}
LowLevelGraphicsSoftwareRenderer::~LowLevelGraphicsSoftwareRenderer()
@ -2263,6 +2320,19 @@ void LowLevelGraphicsSoftwareRenderer::restoreState()
}
}
void LowLevelGraphicsSoftwareRenderer::beginTransparencyLayer (float opacity)
{
saveState();
currentState = currentState->beginTransparencyLayer (opacity);
}
void LowLevelGraphicsSoftwareRenderer::endTransparencyLayer()
{
const ScopedPointer<SavedState> layer (currentState);
restoreState();
currentState->endTransparencyLayer (*layer);
}
//==============================================================================
void LowLevelGraphicsSoftwareRenderer::setFill (const FillType& fillType)
{
@ -2282,18 +2352,17 @@ void LowLevelGraphicsSoftwareRenderer::setInterpolationQuality (Graphics::Resamp
//==============================================================================
void LowLevelGraphicsSoftwareRenderer::fillRect (const Rectangle<int>& r, const bool replaceExistingContents)
{
currentState->fillRect (image, r, replaceExistingContents);
currentState->fillRect (r, replaceExistingContents);
}
void LowLevelGraphicsSoftwareRenderer::fillPath (const Path& path, const AffineTransform& transform)
{
currentState->fillPath (image, path, transform);
currentState->fillPath (path, transform);
}
void LowLevelGraphicsSoftwareRenderer::drawImage (const Image& sourceImage, const AffineTransform& transform, const bool fillEntireClipAsTiles)
{
currentState->renderImage (image, sourceImage, transform,
fillEntireClipAsTiles ? currentState->clip : 0);
currentState->renderImage (sourceImage, transform, fillEntireClipAsTiles ? currentState->clip : 0);
}
void LowLevelGraphicsSoftwareRenderer::drawLine (const Line <float>& line)
@ -2306,13 +2375,13 @@ void LowLevelGraphicsSoftwareRenderer::drawLine (const Line <float>& line)
void LowLevelGraphicsSoftwareRenderer::drawVerticalLine (const int x, float top, float bottom)
{
if (bottom > top)
currentState->fillRect (image, Rectangle<float> ((float) x, top, 1.0f, bottom - top));
currentState->fillRect (Rectangle<float> ((float) x, top, 1.0f, bottom - top));
}
void LowLevelGraphicsSoftwareRenderer::drawHorizontalLine (const int y, float left, float right)
{
if (right > left)
currentState->fillRect (image, Rectangle<float> (left, (float) y, right - left, 1.0f));
currentState->fillRect (Rectangle<float> (left, (float) y, right - left, 1.0f));
}
//==============================================================================
@ -2322,10 +2391,10 @@ public:
CachedGlyph() : glyph (0), lastAccessCount (0) {}
~CachedGlyph() {}
void draw (SavedState& state, Image& image, const float x, const float y) const
void draw (SavedState& state, const float x, const float y) const
{
if (edgeTable != 0)
state.fillEdgeTable (image, *edgeTable, x, roundToInt (y));
state.fillEdgeTable (*edgeTable, x, roundToInt (y));
}
void generate (const Font& newFont, const int glyphNumber)
@ -2383,7 +2452,7 @@ public:
juce_DeclareSingleton_SingleThreaded_Minimal (GlyphCache);
//==============================================================================
void drawGlyph (SavedState& state, Image& image, const Font& font, const int glyphNumber, float x, float y)
void drawGlyph (SavedState& state, const Font& font, const int glyphNumber, float x, float y)
{
++accessCounter;
int oldestCounter = std::numeric_limits<int>::max();
@ -2397,7 +2466,7 @@ public:
{
++hits;
glyph->lastAccessCount = accessCounter;
glyph->draw (state, image, x, y);
glyph->draw (state, x, y);
return;
}
@ -2423,7 +2492,7 @@ public:
jassert (oldest != 0);
oldest->lastAccessCount = accessCounter;
oldest->generate (font, glyphNumber);
oldest->draw (state, image, x, y);
oldest->draw (state, x, y);
}
//==============================================================================
@ -2457,7 +2526,7 @@ void LowLevelGraphicsSoftwareRenderer::drawGlyph (int glyphNumber, const AffineT
if (transform.isOnlyTranslation() && currentState->isOnlyTranslated)
{
GlyphCache::getInstance()->drawGlyph (*currentState, image, f, glyphNumber,
GlyphCache::getInstance()->drawGlyph (*currentState, f, glyphNumber,
transform.getTranslationX(),
transform.getTranslationY());
}

View file

@ -64,6 +64,9 @@ public:
void saveState();
void restoreState();
void beginTransparencyLayer (float opacity);
void endTransparencyLayer();
//==============================================================================
void setFill (const FillType& fillType);
void setOpacity (float opacity);

View file

@ -61,8 +61,8 @@ void Drawable::nonConstDraw (Graphics& g, float opacity, const AffineTransform&
g.saveState();
const float oldOpacity = getAlpha();
setAlpha (opacity);
g.addTransform (AffineTransform::translation (-originRelativeToComponent.getX(),
-originRelativeToComponent.getY())
g.addTransform (AffineTransform::translation ((float) -originRelativeToComponent.getX(),
(float) -originRelativeToComponent.getY())
.followedBy (getTransform())
.followedBy (transform));

View file

@ -216,19 +216,22 @@ void DrawableComposite::childrenChanged()
updateBoundsToFitChildren();
}
struct RentrancyCheckSetter
{
RentrancyCheckSetter (bool& b_) : b (b_) { b_ = true; }
~RentrancyCheckSetter() { b = false; }
private:
bool& b;
RentrancyCheckSetter (const RentrancyCheckSetter&);
RentrancyCheckSetter& operator= (const RentrancyCheckSetter&);
};
void DrawableComposite::updateBoundsToFitChildren()
{
if (! updateBoundsReentrant)
{
struct RentrancyCheckSetter
{
RentrancyCheckSetter (bool& b_) : b (b_) { b_ = true; }
~RentrancyCheckSetter() { b = false; }
private:
bool& b;
};
const RentrancyCheckSetter checkSetter (updateBoundsReentrant);
Rectangle<int> childArea;

View file

@ -151,8 +151,8 @@ const Rectangle<float> DrawableShape::getDrawableBounds() const
bool DrawableShape::hitTest (int x, int y) const
{
const float globalX = x - originRelativeToComponent.getX();
const float globalY = y - originRelativeToComponent.getY();
const float globalX = (float) (x - originRelativeToComponent.getX());
const float globalY = (float) (y - originRelativeToComponent.getY());
return path.contains (globalX, globalY)
|| (isStrokeVisible() && strokePath.contains (globalX, globalY));

View file

@ -325,6 +325,19 @@ public:
}
}
void beginTransparencyLayer (float opacity)
{
saveState();
CGContextSetAlpha (context, opacity);
CGContextBeginTransparencyLayer (context, 0);
}
void endTransparencyLayer()
{
CGContextEndTransparencyLayer (context);
restoreState();
}
//==============================================================================
void setFill (const FillType& fillType)
{

View file

@ -182,6 +182,16 @@ public:
currentState = states.getLast();
}
void beginTransparencyLayer (float opacity)
{
jassertfalse; //xxx todo
}
void endTransparencyLayer()
{
jassertfalse; //xxx todo
}
void setFill (const FillType& fillType)
{
currentState->setFill (fillType);