mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-20 01:14:20 +00:00
Direct2DRenderer: added transformations.
This commit is contained in:
parent
d4fb934a26
commit
7cd30ec175
1 changed files with 60 additions and 59 deletions
|
|
@ -85,19 +85,17 @@ public:
|
|||
|
||||
void setOrigin (int x, int y)
|
||||
{
|
||||
currentState->origin.addXY (x, y);
|
||||
addTransform (AffineTransform::translation ((float) x, (float) y));
|
||||
}
|
||||
|
||||
void addTransform (const AffineTransform& /*transform*/)
|
||||
void addTransform (const AffineTransform& transform)
|
||||
{
|
||||
//xxx todo
|
||||
jassertfalse;
|
||||
currentState->transform = transform.followedBy (currentState->transform);
|
||||
}
|
||||
|
||||
float getScaleFactor()
|
||||
{
|
||||
//xxx
|
||||
return 1.0f;
|
||||
return currentState->transform.getScaleFactor();
|
||||
}
|
||||
|
||||
bool clipToRectangle (const Rectangle<int>& r)
|
||||
|
|
@ -119,24 +117,23 @@ public:
|
|||
|
||||
void clipToPath (const Path& path, const AffineTransform& transform)
|
||||
{
|
||||
currentState->clipToPath (pathToPathGeometry (path, transform, currentState->origin));
|
||||
currentState->clipToPath (pathToPathGeometry (path, transform));
|
||||
}
|
||||
|
||||
void clipToImageAlpha (const Image& sourceImage, const AffineTransform& transform)
|
||||
{
|
||||
currentState->clipToImage (sourceImage,transform);
|
||||
currentState->clipToImage (sourceImage, transform);
|
||||
}
|
||||
|
||||
bool clipRegionIntersects (const Rectangle<int>& r)
|
||||
{
|
||||
const Rectangle<int> r2 (r + currentState->origin);
|
||||
return currentState->clipRect.intersects (r2);
|
||||
return currentState->clipRect.intersects (r.toFloat().transformed (currentState->transform).getSmallestIntegerContainer());
|
||||
}
|
||||
|
||||
Rectangle<int> getClipBounds() const
|
||||
{
|
||||
// xxx could this take into account complex clip regions?
|
||||
return currentState->clipRect - currentState->origin;
|
||||
return currentState->clipRect.toFloat().transformed (currentState->transform.inverted()).getSmallestIntegerContainer();
|
||||
}
|
||||
|
||||
bool isClipEmpty() const
|
||||
|
|
@ -183,14 +180,16 @@ public:
|
|||
|
||||
void fillRect (const Rectangle<int>& r, bool /*replaceExistingContents*/)
|
||||
{
|
||||
renderingTarget->SetTransform (transformToMatrix (currentState->transform));
|
||||
currentState->createBrush();
|
||||
renderingTarget->FillRectangle (rectangleToRectF (r + currentState->origin), currentState->currentBrush);
|
||||
renderingTarget->FillRectangle (rectangleToRectF (r), currentState->currentBrush);
|
||||
renderingTarget->SetTransform (D2D1::IdentityMatrix());
|
||||
}
|
||||
|
||||
void fillPath (const Path& p, const AffineTransform& transform)
|
||||
{
|
||||
currentState->createBrush();
|
||||
ComSmartPtr <ID2D1Geometry> geometry (pathToPathGeometry (p, transform, currentState->origin));
|
||||
ComSmartPtr <ID2D1Geometry> geometry (pathToPathGeometry (p, transform.followedBy (currentState->transform)));
|
||||
|
||||
if (renderingTarget != nullptr)
|
||||
renderingTarget->FillGeometry (geometry, currentState->currentBrush);
|
||||
|
|
@ -198,10 +197,7 @@ public:
|
|||
|
||||
void drawImage (const Image& image, const AffineTransform& transform)
|
||||
{
|
||||
const int x = currentState->origin.getX();
|
||||
const int y = currentState->origin.getY();
|
||||
|
||||
renderingTarget->SetTransform (transformToMatrix (transform) * D2D1::Matrix3x2F::Translation ((FLOAT) x, (FLOAT) y));
|
||||
renderingTarget->SetTransform (transformToMatrix (transform.followedBy (currentState->transform)));
|
||||
|
||||
D2D1_SIZE_U size;
|
||||
size.width = image.getWidth();
|
||||
|
|
@ -227,40 +223,37 @@ public:
|
|||
void drawLine (const Line <float>& line)
|
||||
{
|
||||
// xxx doesn't seem to be correctly aligned, may need nudging by 0.5 to match the software renderer's behaviour
|
||||
const Line<float> l (line.getStart() + currentState->origin.toFloat(),
|
||||
line.getEnd() + currentState->origin.toFloat());
|
||||
|
||||
renderingTarget->SetTransform (transformToMatrix (currentState->transform));
|
||||
currentState->createBrush();
|
||||
|
||||
renderingTarget->DrawLine (D2D1::Point2F (l.getStartX(), l.getStartY()),
|
||||
D2D1::Point2F (l.getEndX(), l.getEndY()),
|
||||
renderingTarget->DrawLine (D2D1::Point2F (line.getStartX(), line.getStartY()),
|
||||
D2D1::Point2F (line.getEndX(), line.getEndY()),
|
||||
currentState->currentBrush);
|
||||
renderingTarget->SetTransform (D2D1::IdentityMatrix());
|
||||
}
|
||||
|
||||
void drawVerticalLine (int x, float top, float bottom)
|
||||
{
|
||||
// xxx doesn't seem to be correctly aligned, may need nudging by 0.5 to match the software renderer's behaviour
|
||||
renderingTarget->SetTransform (transformToMatrix (currentState->transform));
|
||||
currentState->createBrush();
|
||||
|
||||
x += currentState->origin.getX();
|
||||
const int y = currentState->origin.getY();
|
||||
|
||||
renderingTarget->DrawLine (D2D1::Point2F ((FLOAT) x, y + top),
|
||||
D2D1::Point2F ((FLOAT) x, y + bottom),
|
||||
renderingTarget->DrawLine (D2D1::Point2F ((FLOAT) x, top),
|
||||
D2D1::Point2F ((FLOAT) x, bottom),
|
||||
currentState->currentBrush);
|
||||
renderingTarget->SetTransform (D2D1::IdentityMatrix());
|
||||
}
|
||||
|
||||
void drawHorizontalLine (int y, float left, float right)
|
||||
{
|
||||
// xxx doesn't seem to be correctly aligned, may need nudging by 0.5 to match the software renderer's behaviour
|
||||
renderingTarget->SetTransform (transformToMatrix (currentState->transform));
|
||||
currentState->createBrush();
|
||||
|
||||
y += currentState->origin.getY();
|
||||
const int x = currentState->origin.getX();
|
||||
|
||||
renderingTarget->DrawLine (D2D1::Point2F (x + left, (FLOAT) y),
|
||||
D2D1::Point2F (x + right, (FLOAT) y),
|
||||
renderingTarget->DrawLine (D2D1::Point2F (left, (FLOAT) y),
|
||||
D2D1::Point2F (right, (FLOAT) y),
|
||||
currentState->currentBrush);
|
||||
renderingTarget->SetTransform (D2D1::IdentityMatrix());
|
||||
}
|
||||
|
||||
void setFont (const Font& newFont)
|
||||
|
|
@ -275,15 +268,14 @@ public:
|
|||
|
||||
void drawGlyph (int glyphNumber, const AffineTransform& transform)
|
||||
{
|
||||
const float x = (float) currentState->origin.getX();
|
||||
const float y = (float) currentState->origin.getY();
|
||||
|
||||
currentState->createBrush();
|
||||
currentState->createFont();
|
||||
|
||||
float hScale = currentState->font.getHorizontalScale();
|
||||
|
||||
renderingTarget->SetTransform (D2D1::Matrix3x2F::Scale (hScale, 1) * transformToMatrix (transform) * D2D1::Matrix3x2F::Translation (x, y));
|
||||
renderingTarget->SetTransform (transformToMatrix (AffineTransform::scale (hScale, 1.0f)
|
||||
.followedBy (transform)
|
||||
.followedBy (currentState->transform)));
|
||||
|
||||
const UINT16 glyphIndices = (UINT16) glyphNumber;
|
||||
const FLOAT glyphAdvances = 0;
|
||||
|
|
@ -305,6 +297,18 @@ public:
|
|||
renderingTarget->SetTransform (D2D1::IdentityMatrix());
|
||||
}
|
||||
|
||||
bool drawTextLayout (const AttributedString& text, const Rectangle<float>& area)
|
||||
{
|
||||
renderingTarget->SetTransform (transformToMatrix (currentState->transform));
|
||||
|
||||
const Direct2DFactories& factories = Direct2DFactories::getInstance();
|
||||
DirectWriteTypeLayout::drawToD2DContext (text, area, renderingTarget, factories.directWriteFactory,
|
||||
factories.d2dFactory, factories.systemFonts);
|
||||
|
||||
renderingTarget->SetTransform (D2D1::IdentityMatrix());
|
||||
return true;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class SavedState
|
||||
{
|
||||
|
|
@ -323,8 +327,8 @@ public:
|
|||
// bottleneck.. Can the same internal objects be shared by multiple state objects, maybe using copy-on-write?
|
||||
setFill (owner.currentState->fillType);
|
||||
currentBrush = owner.currentState->currentBrush;
|
||||
origin = owner.currentState->origin;
|
||||
clipRect = owner.currentState->clipRect;
|
||||
transform = owner.currentState->transform;
|
||||
|
||||
font = owner.currentState->font;
|
||||
currentFontFace = owner.currentState->currentFontFace;
|
||||
|
|
@ -357,7 +361,7 @@ public:
|
|||
void clipToRectangle (const Rectangle<int>& r)
|
||||
{
|
||||
clearClip();
|
||||
clipRect = r + origin;
|
||||
clipRect = r.toFloat().transformed (transform).getSmallestIntegerContainer();
|
||||
shouldClipRect = true;
|
||||
pushClips();
|
||||
}
|
||||
|
|
@ -569,9 +573,6 @@ public:
|
|||
{
|
||||
if (currentBrush == 0)
|
||||
{
|
||||
const int x = origin.getX();
|
||||
const int y = origin.getY();
|
||||
|
||||
if (fillType.isColour())
|
||||
{
|
||||
D2D1_COLOR_F colour = colourToD2D (fillType.colour);
|
||||
|
|
@ -610,7 +611,7 @@ public:
|
|||
|
||||
D2D1_BRUSH_PROPERTIES brushProps;
|
||||
brushProps.opacity = fillType.getOpacity();
|
||||
brushProps.transform = transformToMatrix (fillType.transform);
|
||||
brushProps.transform = transformToMatrix (fillType.transform.followedBy (transform));
|
||||
|
||||
const int numColors = fillType.gradient->getNumColours();
|
||||
|
||||
|
|
@ -633,7 +634,7 @@ public:
|
|||
float r = p1.getDistanceFrom (p2);
|
||||
|
||||
D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES props =
|
||||
D2D1::RadialGradientBrushProperties (D2D1::Point2F (p1.getX() + x, p1.getY() + y),
|
||||
D2D1::RadialGradientBrushProperties (D2D1::Point2F (p1.x, p1.y),
|
||||
D2D1::Point2F (0, 0),
|
||||
r, r);
|
||||
|
||||
|
|
@ -648,8 +649,8 @@ public:
|
|||
const Point<float>& p2 = fillType.gradient->point2;
|
||||
|
||||
D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES props =
|
||||
D2D1::LinearGradientBrushProperties (D2D1::Point2F (p1.getX() + x, p1.getY() + y),
|
||||
D2D1::Point2F (p2.getX() + x, p2.getY() + y));
|
||||
D2D1::LinearGradientBrushProperties (D2D1::Point2F (p1.x, p1.y),
|
||||
D2D1::Point2F (p2.x, p2.y));
|
||||
|
||||
owner.renderingTarget->CreateLinearGradientBrush (props, brushProps, gradientStops, linearGradient.resetAndGetPointerAddress());
|
||||
|
||||
|
|
@ -664,7 +665,7 @@ public:
|
|||
|
||||
Direct2DLowLevelGraphicsContext& owner;
|
||||
|
||||
Point<int> origin;
|
||||
AffineTransform transform;
|
||||
|
||||
Font font;
|
||||
float fontHeightToEmSizeFactor;
|
||||
|
|
@ -722,12 +723,12 @@ private:
|
|||
return D2D1::RectF ((float) r.getX(), (float) r.getY(), (float) r.getRight(), (float) r.getBottom());
|
||||
}
|
||||
|
||||
static const D2D1_COLOR_F colourToD2D (const Colour& c)
|
||||
static D2D1_COLOR_F colourToD2D (const Colour& c)
|
||||
{
|
||||
return D2D1::ColorF::ColorF (c.getFloatRed(), c.getFloatGreen(), c.getFloatBlue(), c.getFloatAlpha());
|
||||
}
|
||||
|
||||
static const D2D1_POINT_2F pointTransformed (int x, int y, const AffineTransform& transform = AffineTransform::identity)
|
||||
static D2D1_POINT_2F pointTransformed (int x, int y, const AffineTransform& transform)
|
||||
{
|
||||
transform.transformPoint (x, y);
|
||||
return D2D1::Point2F ((FLOAT) x, (FLOAT) y);
|
||||
|
|
@ -758,7 +759,7 @@ private:
|
|||
return p;
|
||||
}
|
||||
|
||||
static void pathToGeometrySink (const Path& path, ID2D1GeometrySink* sink, const AffineTransform& transform, int x, int y)
|
||||
static void pathToGeometrySink (const Path& path, ID2D1GeometrySink* sink, const AffineTransform& transform)
|
||||
{
|
||||
Path::Iterator it (path);
|
||||
|
||||
|
|
@ -771,13 +772,13 @@ private:
|
|||
D2D1_BEZIER_SEGMENT seg;
|
||||
|
||||
transform.transformPoint (it.x1, it.y1);
|
||||
seg.point1 = D2D1::Point2F (it.x1 + x, it.y1 + y);
|
||||
seg.point1 = D2D1::Point2F (it.x1, it.y1);
|
||||
|
||||
transform.transformPoint (it.x2, it.y2);
|
||||
seg.point2 = D2D1::Point2F (it.x2 + x, it.y2 + y);
|
||||
seg.point2 = D2D1::Point2F (it.x2, it.y2);
|
||||
|
||||
transform.transformPoint(it.x3, it.y3);
|
||||
seg.point3 = D2D1::Point2F (it.x3 + x, it.y3 + y);
|
||||
seg.point3 = D2D1::Point2F (it.x3, it.y3);
|
||||
|
||||
sink->AddBezier (seg);
|
||||
break;
|
||||
|
|
@ -786,7 +787,7 @@ private:
|
|||
case Path::Iterator::lineTo:
|
||||
{
|
||||
transform.transformPoint (it.x1, it.y1);
|
||||
sink->AddLine (D2D1::Point2F (it.x1 + x, it.y1 + y));
|
||||
sink->AddLine (D2D1::Point2F (it.x1, it.y1));
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -795,10 +796,10 @@ private:
|
|||
D2D1_QUADRATIC_BEZIER_SEGMENT seg;
|
||||
|
||||
transform.transformPoint (it.x1, it.y1);
|
||||
seg.point1 = D2D1::Point2F (it.x1 + x, it.y1 + y);
|
||||
seg.point1 = D2D1::Point2F (it.x1, it.y1);
|
||||
|
||||
transform.transformPoint (it.x2, it.y2);
|
||||
seg.point2 = D2D1::Point2F (it.x2 + x, it.y2 + y);
|
||||
seg.point2 = D2D1::Point2F (it.x2, it.y2);
|
||||
|
||||
sink->AddQuadraticBezier (seg);
|
||||
break;
|
||||
|
|
@ -813,14 +814,14 @@ private:
|
|||
case Path::Iterator::startNewSubPath:
|
||||
{
|
||||
transform.transformPoint (it.x1, it.y1);
|
||||
sink->BeginFigure (D2D1::Point2F (it.x1 + x, it.y1 + y), D2D1_FIGURE_BEGIN_FILLED);
|
||||
sink->BeginFigure (D2D1::Point2F (it.x1, it.y1), D2D1_FIGURE_BEGIN_FILLED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static ID2D1PathGeometry* pathToPathGeometry (const Path& path, const AffineTransform& transform, const Point<int>& point)
|
||||
static ID2D1PathGeometry* pathToPathGeometry (const Path& path, const AffineTransform& transform)
|
||||
{
|
||||
ID2D1PathGeometry* p = nullptr;
|
||||
Direct2DFactories::getInstance().d2dFactory->CreatePathGeometry (&p);
|
||||
|
|
@ -829,13 +830,13 @@ private:
|
|||
HRESULT hr = p->Open (sink.resetAndGetPointerAddress());
|
||||
sink->SetFillMode (D2D1_FILL_MODE_WINDING); // xxx need to check Path::isUsingNonZeroWinding()
|
||||
|
||||
pathToGeometrySink (path, sink, transform, point.getX(), point.getY());
|
||||
pathToGeometrySink (path, sink, transform);
|
||||
|
||||
hr = sink->Close();
|
||||
return p;
|
||||
}
|
||||
|
||||
static const D2D1::Matrix3x2F transformToMatrix (const AffineTransform& transform)
|
||||
static D2D1::Matrix3x2F transformToMatrix (const AffineTransform& transform)
|
||||
{
|
||||
D2D1::Matrix3x2F matrix;
|
||||
matrix._11 = transform.mat00;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue