mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-10-17 14:36:15 +02:00
fpvectorial: Initial implementation of radial gradient drawing
git-svn-id: trunk@51537 -
This commit is contained in:
parent
934fed7ee5
commit
458c26d88f
@ -37,7 +37,7 @@ uses
|
|||||||
// lazutils
|
// lazutils
|
||||||
laz2_dom,
|
laz2_dom,
|
||||||
// LCL
|
// LCL
|
||||||
lazutf8
|
lazutf8, lazregions
|
||||||
{$ifdef USE_LCL_CANVAS}
|
{$ifdef USE_LCL_CANVAS}
|
||||||
, Graphics, LCLIntf, LCLType, intfgraphics, graphtype
|
, Graphics, LCLIntf, LCLType, intfgraphics, graphtype
|
||||||
{$endif}
|
{$endif}
|
||||||
@ -547,6 +547,8 @@ type
|
|||||||
AMulX: Double = 1.0; AMulY: Double = 1.0);
|
AMulX: Double = 1.0; AMulY: Double = 1.0);
|
||||||
procedure DrawPolygonBrushGradient(ADest: TFPCustomCanvas; var ARenderInfo: TvRenderInfo;
|
procedure DrawPolygonBrushGradient(ADest: TFPCustomCanvas; var ARenderInfo: TvRenderInfo;
|
||||||
const APoints: TPointsArray; ARect: TRect; AGradientStart, AGradientEnd: T2DPoint);
|
const APoints: TPointsArray; ARect: TRect; AGradientStart, AGradientEnd: T2DPoint);
|
||||||
|
procedure DrawPolygonBrushRadialGradient(ADest: TFPCustomCanvas; var ARenderInfo: TvRenderInfo;
|
||||||
|
const APoints: TPointsArray; ARect: TRect);
|
||||||
public
|
public
|
||||||
{@@ The global Brush for the entire entity. In the case of paths, individual
|
{@@ The global Brush for the entire entity. In the case of paths, individual
|
||||||
elements might be able to override this setting. }
|
elements might be able to override this setting. }
|
||||||
@ -554,8 +556,8 @@ type
|
|||||||
WindingRule: TvClipMode;
|
WindingRule: TvClipMode;
|
||||||
constructor Create(APage: TvPage); override;
|
constructor Create(APage: TvPage); override;
|
||||||
procedure ApplyBrushToCanvas(ADest: TFPCustomCanvas); overload;
|
procedure ApplyBrushToCanvas(ADest: TFPCustomCanvas); overload;
|
||||||
procedure ApplyBrushToCanvas(ADest: TFPCustomCanvas; ABrush: TvBrush); overload;
|
procedure ApplyBrushToCanvas(ADest: TFPCustomCanvas; ABrush: PvBrush); overload;
|
||||||
procedure AssignBrush(ABrush: TvBrush);
|
procedure AssignBrush(ABrush: PvBrush);
|
||||||
procedure DrawBrush(ADest: TFPCustomCanvas; var ARenderInfo: TvRenderInfo;
|
procedure DrawBrush(ADest: TFPCustomCanvas; var ARenderInfo: TvRenderInfo;
|
||||||
ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
|
ADestX: Integer = 0; ADestY: Integer = 0; AMulX: Double = 1.0; AMulY: Double = 1.0);
|
||||||
procedure DrawBrushGradient(ADest: TFPCustomCanvas; var ARenderInfo: TvRenderInfo;
|
procedure DrawBrushGradient(ADest: TFPCustomCanvas; var ARenderInfo: TvRenderInfo;
|
||||||
@ -3717,20 +3719,19 @@ end;
|
|||||||
|
|
||||||
procedure TvEntityWithPenAndBrush.ApplyBrushToCanvas(ADest: TFPCustomCanvas);
|
procedure TvEntityWithPenAndBrush.ApplyBrushToCanvas(ADest: TFPCustomCanvas);
|
||||||
begin
|
begin
|
||||||
ApplyBrushToCanvas(ADest, Brush);
|
ApplyBrushToCanvas(ADest, @Brush);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TvEntityWithPenAndBrush.ApplyBrushToCanvas(ADest: TFPCustomCanvas;
|
procedure TvEntityWithPenAndBrush.ApplyBrushToCanvas(ADest: TFPCustomCanvas;
|
||||||
ABrush: TvBrush);
|
ABrush: PvBrush);
|
||||||
begin
|
begin
|
||||||
ADest.Brush.FPColor := ABrush.Color;
|
ADest.Brush.FPColor := ABrush^.Color;
|
||||||
ADest.Brush.Style := ABrush.Style;
|
ADest.Brush.Style := ABrush^.Style;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TvEntityWithPenAndBrush.AssignBrush(ABrush: TvBrush);
|
procedure TvEntityWithPenAndBrush.AssignBrush(ABrush: PvBrush);
|
||||||
begin
|
begin
|
||||||
Brush.Style := ABrush.Style;
|
Brush := ABrush^;
|
||||||
Brush.Color := ABrush.Color;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ Calculates the canvas coordinates of the gradient vector (i.e. x,y of start
|
{ Calculates the canvas coordinates of the gradient vector (i.e. x,y of start
|
||||||
@ -3780,9 +3781,10 @@ end;
|
|||||||
{ Fills the entity with a gradient.
|
{ Fills the entity with a gradient.
|
||||||
Assumes that the boundary is already in canvas units and is specified by
|
Assumes that the boundary is already in canvas units and is specified by
|
||||||
polygon APoints. }
|
polygon APoints. }
|
||||||
procedure TvEntityWithPenAndBrush.DrawPolygonBrushGradient(ADest: TFPCustomCanvas;
|
procedure TvEntityWithPenAndBrush.DrawPolygonBrushGradient(
|
||||||
var ARenderInfo: TvRenderInfo; const APoints: TPointsArray; ARect: TRect;
|
ADest: TFPCustomCanvas; var ARenderInfo: TvRenderInfo;
|
||||||
AGradientStart, AGradientEnd: T2dPoint);
|
const APoints: TPointsArray; ARect: TRect; AGradientStart,
|
||||||
|
AGradientEnd: T2DPoint);
|
||||||
var
|
var
|
||||||
lPoints, pts: T2DPointsArray;
|
lPoints, pts: T2DPointsArray;
|
||||||
i, j: Integer;
|
i, j: Integer;
|
||||||
@ -3798,6 +3800,11 @@ var
|
|||||||
gstart: Double; // Gradient start point (1-dim)
|
gstart: Double; // Gradient start point (1-dim)
|
||||||
dir: Integer;
|
dir: Integer;
|
||||||
begin
|
begin
|
||||||
|
if Brush.Kind = bkRadialGradient then
|
||||||
|
begin
|
||||||
|
DrawPolygonBrushRadialGradient(ADest, ARenderInfo, APoints, ARect);
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
if not (Brush.Kind in [bkVerticalGradient, bkHorizontalGradient, bkOtherLinearGradient]) then
|
if not (Brush.Kind in [bkVerticalGradient, bkHorizontalGradient, bkOtherLinearGradient]) then
|
||||||
Exit;
|
Exit;
|
||||||
|
|
||||||
@ -3938,9 +3945,89 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TvEntityWithPenAndBrush.DrawPolygonBrushRadialGradient(
|
||||||
|
ADest: TFPCustomCanvas; var ARenderInfo: TvRenderInfo;
|
||||||
|
const APoints: TPointsArray; ARect: TRect);
|
||||||
|
var
|
||||||
|
i, j: Integer;
|
||||||
|
lx, ly: Integer;
|
||||||
|
lDist: Double;
|
||||||
|
lGradient_cx_px, lGradient_cy_px, lGradient_r_px, lGradient_fx_px, lGradient_fy_px: Double;
|
||||||
|
lWidth, lHeight, lBiggestHalfSide: Integer;
|
||||||
|
lBiggestSizeIsY: Boolean;
|
||||||
|
lColor: TFPColor;
|
||||||
|
|
||||||
|
function Gradient_value_to_px(AValue: Double; AUnit: TvCoordinateUnit; AIsY: Boolean): Integer;
|
||||||
|
var
|
||||||
|
lSideLen: Integer;
|
||||||
|
begin
|
||||||
|
Result := 0;
|
||||||
|
if AIsY then lSideLen := (ARect.Bottom-ARect.Top)
|
||||||
|
else lSideLen := (ARect.Right-ARect.Left);
|
||||||
|
case AUnit of
|
||||||
|
//vcuDocumentUnit: Result := ;
|
||||||
|
vcuPercentage: Result := Round(lSideLen * AValue);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function Distance_To_RadialGradient_Color(ADist: Double): TFPColor;
|
||||||
|
var
|
||||||
|
k: Integer;
|
||||||
|
begin
|
||||||
|
Result := colTransparent;
|
||||||
|
for k := 0 to Length(Brush.Gradient_colors)-1 do
|
||||||
|
begin
|
||||||
|
if k = 0 then
|
||||||
|
begin
|
||||||
|
Result := Brush.Gradient_colors[k].Color;
|
||||||
|
Continue;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if ADist < Brush.Gradient_colors[k].Position then
|
||||||
|
begin
|
||||||
|
Result := MixColors(
|
||||||
|
Brush.Gradient_colors[k-1].Color, Brush.Gradient_colors[k].Color,
|
||||||
|
ADist - Brush.Gradient_colors[k-1].Position,
|
||||||
|
Brush.Gradient_colors[k].Position - Brush.Gradient_colors[k-1].Position);
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
lWidth := (ARect.Right-ARect.Left);
|
||||||
|
lHeight := (ARect.Bottom-ARect.Top);
|
||||||
|
lBiggestSizeIsY := lHeight > lWidth;
|
||||||
|
if lBiggestSizeIsY then lBiggestHalfSide := Round(lHeight / 2)
|
||||||
|
else lBiggestHalfSide := Round(lWidth / 2);
|
||||||
|
|
||||||
|
// Calculate Gradient_X_px
|
||||||
|
lGradient_cx_px := Gradient_value_to_px(Brush.Gradient_cx, Brush.Gradient_cx_Unit, True);
|
||||||
|
lGradient_cy_px := Gradient_value_to_px(Brush.Gradient_cy, Brush.Gradient_cy_Unit, False);
|
||||||
|
lGradient_r_px := Gradient_value_to_px(Brush.Gradient_r, Brush.Gradient_r_Unit, lBiggestSizeIsY);
|
||||||
|
lGradient_fx_px := Gradient_value_to_px(Brush.Gradient_fx, Brush.Gradient_fx_Unit, True);
|
||||||
|
lGradient_fy_px := Gradient_value_to_px(Brush.Gradient_fy, Brush.Gradient_fy_Unit, False);
|
||||||
|
|
||||||
|
// pixel-by-pixel version
|
||||||
|
for i := 0 to lWidth-1 do
|
||||||
|
begin
|
||||||
|
for J := 0 to lHeight-1 do
|
||||||
|
begin
|
||||||
|
lDist := sqrt(sqr(i-lGradient_cx_px)+sqr(j-lGradient_cy_px));
|
||||||
|
lDist := lDist / lBiggestHalfSide;
|
||||||
|
lDist := Min(Max(0, lDist), 1);
|
||||||
|
lColor := Distance_To_RadialGradient_Color(lDist);
|
||||||
|
lx := ARect.Left + i;
|
||||||
|
ly := ARect.Top + j;
|
||||||
|
if not IsPointInPolygon(lx, ly, APoints) then Exit;
|
||||||
|
ADest.Colors[lx, ly] := AlphaBlendColor(ADest.Colors[lx, ly], lColor);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TvEntityWithPenAndBrush.DrawBrushGradient(ADest: TFPCustomCanvas;
|
procedure TvEntityWithPenAndBrush.DrawBrushGradient(ADest: TFPCustomCanvas;
|
||||||
var ARenderInfo: TvRenderInfo; x1, y1, x2, y2: Integer;
|
var ARenderInfo: TvRenderInfo; x1, y1, x2, y2: Integer; ADestX: Integer;
|
||||||
ADestX, ADestY: Integer; AMulX, AMulY: Double);
|
ADestY: Integer; AMulX: Double; AMulY: Double);
|
||||||
var
|
var
|
||||||
tmpPath: TPath;
|
tmpPath: TPath;
|
||||||
polypoints: TPointsArray;
|
polypoints: TPointsArray;
|
||||||
@ -4056,7 +4143,8 @@ begin
|
|||||||
end; *)
|
end; *)
|
||||||
|
|
||||||
procedure TvEntityWithPenAndBrush.DrawBrush(ADest: TFPCustomCanvas;
|
procedure TvEntityWithPenAndBrush.DrawBrush(ADest: TFPCustomCanvas;
|
||||||
var ARenderInfo: TvRenderInfo; ADestX, ADestY: Integer; AMulX, AMulY: Double);
|
var ARenderInfo: TvRenderInfo; ADestX: Integer; ADestY: Integer;
|
||||||
|
AMulX: Double; AMulY: Double);
|
||||||
var
|
var
|
||||||
tmpPath: TPath;
|
tmpPath: TPath;
|
||||||
polypoints: TPointsArray;
|
polypoints: TPointsArray;
|
||||||
@ -4085,12 +4173,13 @@ function TvEntityWithPenAndBrush.GenerateDebugTree(
|
|||||||
var
|
var
|
||||||
lStr: string;
|
lStr: string;
|
||||||
begin
|
begin
|
||||||
lStr := Format('[%s] Name=%s X=%f Y=%f Pen.Color=%s Pen.Style=%s Brush.Color=%s Brush.Style=%s %s',
|
lStr := Format('[%s] Name=%s X=%f Y=%f Pen=[Color=%s Style=%s] Brush=[Color=%s Style=%s Kind=%s] %s',
|
||||||
[Self.ClassName, Self.Name, X, Y,
|
[Self.ClassName, Self.Name, X, Y,
|
||||||
GenerateDebugStrForFPColor(Pen.Color),
|
GenerateDebugStrForFPColor(Pen.Color),
|
||||||
GetEnumName(TypeInfo(TFPPenStyle), integer(Pen.Style)),
|
GetEnumName(TypeInfo(TFPPenStyle), integer(Pen.Style)),
|
||||||
GenerateDebugStrForFPColor(Brush.Color),
|
GenerateDebugStrForFPColor(Brush.Color),
|
||||||
GetEnumName(TypeInfo(TFPBrushStyle), integer(Brush.Style)),
|
GetEnumName(TypeInfo(TFPBrushStyle), integer(Brush.Style)),
|
||||||
|
GetEnumName(TypeInfo(TvBrushKind), integer(Brush.Kind)),
|
||||||
FExtraDebugStr]);
|
FExtraDebugStr]);
|
||||||
Result := ADestRoutine(lStr, APageItem);
|
Result := ADestRoutine(lStr, APageItem);
|
||||||
end;
|
end;
|
||||||
@ -4215,7 +4304,7 @@ begin
|
|||||||
if (Style <> nil) then
|
if (Style <> nil) then
|
||||||
begin
|
begin
|
||||||
ApplyPenToCanvas(ADest, ARenderInfo, Style.Pen);
|
ApplyPenToCanvas(ADest, ARenderInfo, Style.Pen);
|
||||||
ApplyBrushToCanvas(ADest, Style.Brush);
|
ApplyBrushToCanvas(ADest, @Style.Brush);
|
||||||
ApplyFontToCanvas(ADest, ARenderInfo, Style.Font, AMulX);
|
ApplyFontToCanvas(ADest, ARenderInfo, Style.Font, AMulX);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
@ -43,6 +43,7 @@ function FPColorToRGBHexString(AColor: TFPColor): string;
|
|||||||
function RGBToFPColor(AR, AG, AB: byte): TFPColor; inline;
|
function RGBToFPColor(AR, AG, AB: byte): TFPColor; inline;
|
||||||
function MixColors(AColor1, AColor2: TFPColor; APos, AMax: Double): TFPColor;
|
function MixColors(AColor1, AColor2: TFPColor; APos, AMax: Double): TFPColor;
|
||||||
function GradientColor(AColors: TvGradientColors; AValue: Double): TFPColor;
|
function GradientColor(AColors: TvGradientColors; AValue: Double): TFPColor;
|
||||||
|
function AlphaBlendColor(AColorBase, AColor: TFPColor): TFPColor;
|
||||||
// Coordinate Conversion routines
|
// Coordinate Conversion routines
|
||||||
function CanvasCoordsToFPVectorial(AY: Integer; AHeight: Integer): Integer; inline;
|
function CanvasCoordsToFPVectorial(AY: Integer; AHeight: Integer): Integer; inline;
|
||||||
function CanvasTextPosToFPVectorial(AY: Integer; ACanvasHeight, ATextHeight: Integer): Integer;
|
function CanvasTextPosToFPVectorial(AY: Integer; ACanvasHeight, ATextHeight: Integer): Integer;
|
||||||
@ -165,6 +166,18 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function AlphaBlendColor(AColorBase, AColor: TFPColor): TFPColor;
|
||||||
|
var
|
||||||
|
f1, f2: Double;
|
||||||
|
begin
|
||||||
|
f1 := 1 - f2;
|
||||||
|
f2 := AColor.Alpha / alphaOpaque;
|
||||||
|
Result.Alpha := Round(AColorBase.Alpha * f1 + AColor.Alpha * f2);
|
||||||
|
Result.Red := Round(AColorBase.Red * f1 + AColor.Red * f2);
|
||||||
|
Result.Green := Round(AColorBase.Green * f1 + AColor.Green * f2);
|
||||||
|
Result.Blue := Round(AColorBase.Blue * f1 + AColor.Blue * f2);
|
||||||
|
end;
|
||||||
|
|
||||||
{@@ Converts the coordinate system from a TCanvas to FPVectorial
|
{@@ Converts the coordinate system from a TCanvas to FPVectorial
|
||||||
The basic difference is that the Y axis is positioned differently and
|
The basic difference is that the Y axis is positioned differently and
|
||||||
points upwards in FPVectorial and downwards in TCanvas.
|
points upwards in FPVectorial and downwards in TCanvas.
|
||||||
|
@ -682,7 +682,7 @@ begin
|
|||||||
begin
|
begin
|
||||||
ADest.AssignPen(lCurStyle.Pen);
|
ADest.AssignPen(lCurStyle.Pen);
|
||||||
if ADest is TvEntityWithPenAndBrush then
|
if ADest is TvEntityWithPenAndBrush then
|
||||||
TvEntityWithPenAndBrush(ADest).AssignBrush(lCurStyle.Brush);
|
TvEntityWithPenAndBrush(ADest).AssignBrush(@lCurStyle.Brush);
|
||||||
|
|
||||||
Exit;
|
Exit;
|
||||||
end;
|
end;
|
||||||
|
Loading…
Reference in New Issue
Block a user