mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-06 22:18:15 +02:00
fpvectorial: Render horizontal and vertical gradients for TPath (straight edges, no "holes")
git-svn-id: trunk@50912 -
This commit is contained in:
parent
08f907306b
commit
7b7e9630a7
@ -566,6 +566,7 @@ type
|
||||
procedure AppendLineToSegment(AX, AY: Double);
|
||||
procedure AppendEllipticalArc(ARadX, ARadY, AXAxisRotation, ADestX, ADestY: Double; ALeftmostEllipse, AClockwiseArcFlag: Boolean); // See http://www.w3.org/TR/SVG/paths.html#PathDataEllipticalArcCommands
|
||||
procedure AppendEllipticalArcWithCenter(ARadX, ARadY, AXAxisRotation, ADestX, ADestY, ACenterX, ACenterY: Double; AClockwiseArcFlag: Boolean); // See http://www.w3.org/TR/SVG/paths.html#PathDataEllipticalArcCommands
|
||||
function GetLineIntersectionPoints(ACoord: Double; ACoordIsX: Boolean): TDoubleDynArray; override;
|
||||
procedure Move(ADeltaX, ADeltaY: Double); override;
|
||||
procedure MoveSubpart(ADeltaX, ADeltaY: Double; ASubpart: Cardinal); override;
|
||||
function MoveToSubpart(ASubpart: Cardinal): TPathSegment;
|
||||
@ -3429,7 +3430,7 @@ procedure TvEntityWithPenAndBrush.DrawBrushGradient(ADest: TFPCustomCanvas;
|
||||
end;
|
||||
|
||||
var
|
||||
i: Integer;
|
||||
i, j: Integer;
|
||||
lPoints: TDoubleDynArray;
|
||||
lCanvasPts: array[0..1] of Integer;
|
||||
lColor, lColor1, lColor2: TFPColor;
|
||||
@ -3444,11 +3445,17 @@ begin
|
||||
begin
|
||||
lPoints := GetLineIntersectionPoints(CanvasToCoordY(i), False);
|
||||
if Length(lPoints) < 2 then Continue;
|
||||
lCanvasPts[0] := CoordToCanvasX(lPoints[0]); lCanvasPts[1] := CoordToCanvasX(lPoints[1]);
|
||||
lColor := MixColors(lColor1, lColor2, i-y1, y2-y1);
|
||||
ADest.Pen.FPColor := lColor;
|
||||
ADest.Pen.Style := psSolid;
|
||||
ADest.Line(lCanvasPts[0], i, lCanvasPts[1], i);
|
||||
j := 0;
|
||||
while j < Length(lPoints) do
|
||||
begin
|
||||
lCanvasPts[0] := CoordToCanvasX(lPoints[j]);
|
||||
lCanvasPts[1] := CoordToCanvasX(lPoints[j+1]);
|
||||
ADest.Line(lCanvasPts[0], i, lCanvasPts[1], i);
|
||||
inc(j, 2);
|
||||
end;
|
||||
end;
|
||||
end
|
||||
else if Brush.Kind = bkHorizontalGradient then
|
||||
@ -3457,11 +3464,17 @@ begin
|
||||
begin
|
||||
lPoints := GetLineIntersectionPoints(CanvasToCoordX(i), True);
|
||||
if Length(lPoints) < 2 then Continue;
|
||||
lCanvasPts[0] := CoordToCanvasY(lPoints[0]); lCanvasPts[1] := CoordToCanvasY(lPoints[1]);
|
||||
lColor := MixColors(lColor1, lColor2, i-x1, x2-x1);
|
||||
ADest.Pen.FPColor := lColor;
|
||||
ADest.Pen.Style := psSolid;
|
||||
ADest.Line(i, lCanvasPts[0], i, lCanvasPts[1]);
|
||||
j := 0;
|
||||
while (j+1 < Length(lPoints)) do
|
||||
begin
|
||||
lCanvasPts[0] := CoordToCanvasY(lPoints[j]);
|
||||
lCanvasPts[1] := CoordToCanvasY(lPoints[j+1]);
|
||||
ADest.Line(i, lCanvasPts[0], i, lCanvasPts[1]);
|
||||
inc(j , 2);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
@ -3915,17 +3928,96 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
{ Only correct for straight segments. This must have been checked before! }
|
||||
function TPath.GetLineIntersectionPoints(ACoord: Double;
|
||||
ACoordIsX: Boolean): TDoubleDynArray;
|
||||
const
|
||||
COUNT = 100;
|
||||
var
|
||||
seg: TPathSegment;
|
||||
seg2D: T2DSegment; // absolute seg;
|
||||
j: Integer;
|
||||
p, p1, p2: T3DPoint;
|
||||
n: Integer;
|
||||
begin
|
||||
SetLength(Result, COUNT);
|
||||
PrepareForSequentialReading;
|
||||
n := 0;
|
||||
if ACoordIsX then
|
||||
for j:=0 to Len-1 do
|
||||
begin
|
||||
seg := TPathSegment(Next);
|
||||
if seg.GetStartPoint(p) and (seg is T2DSegment) then
|
||||
begin
|
||||
seg2D := T2DSegment(seg);
|
||||
if p.X < seg2D.X then begin
|
||||
p1 := Make2DPoint(p.X, p.Y);
|
||||
p2 := Make2DPoint(seg2D.X, seg2D.Y);
|
||||
end else
|
||||
begin
|
||||
p1 := Make2DPoint(seg2D.X, seg2D.Y);
|
||||
p2 := Make2DPoint(p.X, p.Y);
|
||||
end;
|
||||
if (p1.X < ACoord) and (ACoord <= p2.X) then
|
||||
begin
|
||||
if n >= Length(Result) then
|
||||
SetLength(Result, Length(Result) + COUNT);
|
||||
if (p1.X = p2.X) then
|
||||
Result[n] := p1.Y else
|
||||
Result[n] := p1.Y + (ACoord - p1.X) * (p2.Y - p1.Y) / (p2.X - p1.X);
|
||||
inc(n);
|
||||
end;
|
||||
end;
|
||||
end
|
||||
else
|
||||
for j := 0 to Len-1 do
|
||||
begin
|
||||
seg := TPathSegment(Next);
|
||||
if seg.GetStartPoint(p) and (seg is T2DSegment) then
|
||||
begin
|
||||
seg2D := T2DSegment(seg);
|
||||
if p.Y < seg2D.Y then
|
||||
begin
|
||||
p1 := Make2DPoint(p.X, p.Y);
|
||||
p2 := Make2DPoint(seg2D.X, seg2D.Y);
|
||||
end else
|
||||
begin
|
||||
p1 := Make2DPoint(seg2D.X, seg2D.Y);
|
||||
p2 := Make2DPoint(p.X, p.Y);
|
||||
end;
|
||||
if (p1.Y < ACoord) and (ACoord <= p2.Y) then
|
||||
begin
|
||||
if n >= Length(Result) then
|
||||
SetLength(Result, Length(Result) + COUNT);
|
||||
if (p1.Y = p2.Y) then
|
||||
Result[n] := p1.X else
|
||||
Result[n] := p1.X + (ACoord - p1.Y) * (p2.X - p1.x) / (p2.Y - p1.Y);
|
||||
inc(n);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
SetLength(Result, n);
|
||||
end;
|
||||
|
||||
procedure TPath.Render(ADest: TFPCustomCanvas; var ARenderInfo: TvRenderInfo; ADestX: Integer;
|
||||
ADestY: Integer; AMulX: Double; AMulY: Double; ADoDraw: Boolean);
|
||||
|
||||
function CoordToCanvasX(ACoord: Double): Integer;
|
||||
function HasStraightSegmentsOnly: Boolean;
|
||||
var
|
||||
seg: TPathSegment;
|
||||
j: Integer;
|
||||
begin
|
||||
Result := Round(ADestX + AmulX * ACoord);
|
||||
end;
|
||||
|
||||
function CoordToCanvasY(ACoord: Double): Integer;
|
||||
begin
|
||||
Result := Round(ADestY + AmulY * ACoord);
|
||||
Result := true;
|
||||
PrepareForSequentialReading;
|
||||
for j := 0 to Len - 1 do
|
||||
begin
|
||||
seg := TPathSegment(Next());
|
||||
if seg.SegmentType in [st2DBezier, st3dBezier, st2DEllipticalArc] then
|
||||
begin
|
||||
Result := false;
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
var
|
||||
@ -3936,6 +4028,7 @@ var
|
||||
Cur2DSegment: T2DSegment absolute CurSegment;
|
||||
Cur2DBSegment: T2DBezierSegment absolute CurSegment;
|
||||
Cur2DArcSegment: T2DEllipticalArcSegment absolute CurSegment;
|
||||
x1, y1, x2, y2: Integer;
|
||||
// For bezier
|
||||
CoordX2, CoordY2, CoordX3, CoordY3, CoordX4, CoordY4: Integer;
|
||||
//t: Double;
|
||||
@ -3954,7 +4047,7 @@ begin
|
||||
|
||||
PosX := 0;
|
||||
PosY := 0;
|
||||
ADest.Brush.Style := bsClear;
|
||||
// ADest.Brush.Style := bsClear;
|
||||
|
||||
ADest.MoveTo(ADestX, ADestY);
|
||||
{
|
||||
@ -3992,6 +4085,29 @@ begin
|
||||
if ADoDraw then
|
||||
RenderInternalPolygon(ADest, ARenderInfo, ADestX, ADestY, AMulX, AMulY);
|
||||
|
||||
{$IFDEF USE_LCL_CANVAS}
|
||||
if ADoDraw and (Brush.Kind in [bkHorizontalGradient, bkVerticalGradient]) and
|
||||
HasStraightSegmentsOnly then
|
||||
begin
|
||||
x1 := MaxInt;
|
||||
y1 := MaxInt;
|
||||
x2 := -MaxInt;
|
||||
y2 := -MaxInt;
|
||||
PrepareForSequentialReading;
|
||||
for j := 0 to Len - 1 do
|
||||
begin
|
||||
CurSegment := TPathSegment(Next);
|
||||
CoordX := CoordToCanvasX(Cur2DSegment.X, ADestX, AMulX);
|
||||
CoordY := CoordToCanvasY(Cur2DSegment.Y, ADestY, AMulY);
|
||||
x1 := Min(x1, CoordX);
|
||||
y1 := Min(y1, CoordY);
|
||||
x2 := Max(x2, CoordX);
|
||||
y2 := Max(y2, CoordY);
|
||||
end;
|
||||
DrawBrushGradient(ADest, ARenderInfo, x1, y1, x2, y2, ADestX, ADestY, AMulX, AMulY);
|
||||
end;
|
||||
{$ENDIF}
|
||||
|
||||
//
|
||||
// For other paths, draw more carefully
|
||||
//
|
||||
@ -4006,8 +4122,8 @@ begin
|
||||
case CurSegment.SegmentType of
|
||||
stMoveTo:
|
||||
begin
|
||||
CoordX := CoordToCanvasX(Cur2DSegment.X);
|
||||
CoordY := CoordToCanvasY(Cur2DSegment.Y);
|
||||
CoordX := CoordToCanvasX(Cur2DSegment.X, ADestX, AMulX);
|
||||
CoordY := CoordToCanvasY(Cur2DSegment.Y, ADestY, AMulY);
|
||||
if ADoDraw then
|
||||
ADest.MoveTo(CoordX, CoordY);
|
||||
CalcEntityCanvasMinMaxXY(ARenderInfo, CoordX, CoordY);
|
||||
@ -4021,11 +4137,10 @@ begin
|
||||
st2DLineWithPen:
|
||||
begin
|
||||
ADest.Pen.FPColor := AdjustColorToBackground(T2DSegmentWithPen(Cur2DSegment).Pen.Color, ARenderInfo);
|
||||
|
||||
CoordX := CoordToCanvasX(PosX);
|
||||
CoordY := CoordToCanvasY(PosY);
|
||||
CoordX2 := CoordToCanvasX(Cur2DSegment.X);
|
||||
CoordY2 := CoordToCanvasY(Cur2DSegment.Y);
|
||||
CoordX := CoordToCanvasX(PosX, ADestX, AMulX);
|
||||
CoordY := CoordToCanvasY(PosY, ADestY, AMulY);
|
||||
CoordX2 := CoordToCanvasX(Cur2DSegment.X, ADestX, AMulX);
|
||||
CoordY2 := CoordToCanvasY(Cur2DSegment.Y, ADestY, AMulY);
|
||||
CalcEntityCanvasMinMaxXY_With2Points(ARenderInfo, CoordX, CoordY, CoordX2, CoordY2);
|
||||
if ADoDraw then
|
||||
ADest.Line(CoordX, CoordY, CoordX2, CoordY2);
|
||||
@ -4041,10 +4156,10 @@ begin
|
||||
end;
|
||||
st2DLine, st3DLine:
|
||||
begin
|
||||
CoordX := CoordToCanvasX(PosX);
|
||||
CoordY := CoordToCanvasY(PosY);
|
||||
CoordX2 := CoordToCanvasX(Cur2DSegment.X);
|
||||
CoordY2 := CoordToCanvasY(Cur2DSegment.Y);
|
||||
CoordX := CoordToCanvasX(PosX, ADestX, AMulX);
|
||||
CoordY := CoordToCanvasY(PosY, ADestY, AMulY);
|
||||
CoordX2 := CoordToCanvasX(Cur2DSegment.X, ADestX, AMulX);
|
||||
CoordY2 := CoordToCanvasY(Cur2DSegment.Y, ADestY, AMulY);
|
||||
CalcEntityCanvasMinMaxXY_With2Points(ARenderInfo, CoordX, CoordY, CoordX2, CoordY2);
|
||||
if ADoDraw then
|
||||
ADest.Line(CoordX, CoordY, CoordX2, CoordY2);
|
||||
@ -4058,14 +4173,14 @@ begin
|
||||
lines between this parts }
|
||||
st2DBezier, st3DBezier:
|
||||
begin
|
||||
CoordX := CoordToCanvasX(PosX);
|
||||
CoordY := CoordToCanvasY(PosY);
|
||||
CoordX2 := CoordToCanvasX(Cur2DBSegment.X2);
|
||||
CoordY2 := CoordToCanvasY(Cur2DBSegment.Y2);
|
||||
CoordX3 := CoordToCanvasX(Cur2DBSegment.X3);
|
||||
CoordY3 := CoordToCanvasY(Cur2DBSegment.Y3);
|
||||
CoordX4 := CoordToCanvasX(Cur2DBSegment.X);
|
||||
CoordY4 := CoordToCanvasY(Cur2DBSegment.Y);
|
||||
CoordX := CoordToCanvasX(PosX, ADestX, AMulX);
|
||||
CoordY := CoordToCanvasY(PosY, ADestY, AMulY);
|
||||
CoordX2 := CoordToCanvasX(Cur2DBSegment.X2, ADestX, AMulX);
|
||||
CoordY2 := CoordToCanvasY(Cur2DBSegment.Y2, ADestY, AMulY);
|
||||
CoordX3 := CoordToCanvasX(Cur2DBSegment.X3, ADestX, AMulX);
|
||||
CoordY3 := CoordToCanvasY(Cur2DBSegment.Y3, ADestY, AMulY);
|
||||
CoordX4 := CoordToCanvasX(Cur2DBSegment.X, ADestX, AMulX);
|
||||
CoordY4 := CoordToCanvasY(Cur2DBSegment.Y, ADestY, AMulY);
|
||||
SetLength(lPoints, 0);
|
||||
CalcEntityCanvasMinMaxXY_With2Points(ARenderInfo, CoordX, CoordY, CoordX2, CoordY2);
|
||||
CalcEntityCanvasMinMaxXY_With2Points(ARenderInfo, CoordX3, CoordY3, CoordX4, CoordY4);
|
||||
@ -4112,21 +4227,21 @@ begin
|
||||
// done!
|
||||
st2DEllipticalArc:
|
||||
begin
|
||||
CoordX := CoordToCanvasX(PosX);
|
||||
CoordY := CoordToCanvasY(PosY);
|
||||
CoordX2 := CoordToCanvasX(Cur2DArcSegment.RX);
|
||||
CoordY2 := CoordToCanvasY(Cur2DArcSegment.RY);
|
||||
CoordX3 := CoordToCanvasX(Cur2DArcSegment.XRotation);
|
||||
CoordX4 := CoordToCanvasX(Cur2DArcSegment.X);
|
||||
CoordY4 := CoordToCanvasY(Cur2DArcSegment.Y);
|
||||
CoordX := CoordToCanvasX(PosX, ADestX, AMulX);
|
||||
CoordY := CoordToCanvasY(PosY, ADestY, AMulY);
|
||||
CoordX2 := CoordToCanvasX(Cur2DArcSegment.RX, ADestX, AMulX);
|
||||
CoordY2 := CoordToCanvasY(Cur2DArcSegment.RY, ADestY, AMulY);
|
||||
CoordX3 := CoordToCanvasX(Cur2DArcSegment.XRotation, ADestX, AMulX);
|
||||
CoordX4 := CoordToCanvasX(Cur2DArcSegment.X, ADestX, AMulX);
|
||||
CoordY4 := CoordToCanvasY(Cur2DArcSegment.Y, ADestY, AMulY);
|
||||
SetLength(lPoints, 0);
|
||||
|
||||
Cur2DArcSegment.CalculateEllipseBoundingBox(nil, BoxLeft, BoxTop, BoxRight, BoxBottom);
|
||||
|
||||
EllipseRect.Left := CoordToCanvasX(BoxLeft);
|
||||
EllipseRect.Top := CoordToCanvasY(BoxTop);
|
||||
EllipseRect.Right := CoordToCanvasX(BoxRight);
|
||||
EllipseRect.Bottom := CoordToCanvasY(BoxBottom);
|
||||
EllipseRect.Left := CoordToCanvasX(BoxLeft, ADestX, AMulX);
|
||||
EllipseRect.Top := CoordToCanvasY(BoxTop, ADestY, AMulY);
|
||||
EllipseRect.Right := CoordToCanvasX(BoxRight, ADestX, AMulX);
|
||||
EllipseRect.Bottom := CoordToCanvasY(BoxBottom, ADestY, AMulY);
|
||||
|
||||
{$ifdef FPVECTORIAL_TOCANVAS_ELLIPSE_VISUALDEBUG}
|
||||
ACanvas.Pen.Color := clRed;
|
||||
|
Loading…
Reference in New Issue
Block a user