From d468124038dc7331c70f10a9ea6a982c533bf727 Mon Sep 17 00:00:00 2001 From: James Richters Date: Fri, 16 Jun 2017 14:06:15 -0400 Subject: [PATCH 1/7] Select 32Bit or 64Bit Freetype.dll --- src/corelib/render/software/agg_font_freetype_lib.pas | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/corelib/render/software/agg_font_freetype_lib.pas b/src/corelib/render/software/agg_font_freetype_lib.pas index cd6d05bd0..7bb20d020 100644 --- a/src/corelib/render/software/agg_font_freetype_lib.pas +++ b/src/corelib/render/software/agg_font_freetype_lib.pas @@ -41,7 +41,11 @@ const {$IFDEF WINDOWS } - ft_lib = 'freetype.dll'; +{$IFDEF CPU64 } + ft_lib = 'freetype64.dll'; +{$Else } + ft_lib = 'freetype32.dll'; +{$ENDIF } {$ENDIF } // Linux, FreeBSD etc. From 3872d3392490b2e557a8e00581b54c5fd4dcede0 Mon Sep 17 00:00:00 2001 From: James Richters Date: Fri, 16 Jun 2017 14:13:33 -0400 Subject: [PATCH 2/7] Copy agg_2D.dll to agg_2D_RGB565.dll to be modified for use with ptcgraph --- src/corelib/render/software/agg_2D_RGB565.pas | 3481 +++++++++++++++++ 1 file changed, 3481 insertions(+) create mode 100644 src/corelib/render/software/agg_2D_RGB565.pas diff --git a/src/corelib/render/software/agg_2D_RGB565.pas b/src/corelib/render/software/agg_2D_RGB565.pas new file mode 100644 index 000000000..1e09657d0 --- /dev/null +++ b/src/corelib/render/software/agg_2D_RGB565.pas @@ -0,0 +1,3481 @@ +//---------------------------------------------------------------------------- +// Agg2D - Version 1.0 +// Based on Anti-Grain Geometry +// Copyright (C) 2005 Maxim Shemanarev (http://www.antigrain.com) +// +// Agg2D - Version 1.0 Release Milano 3 (AggPas 2.4 RM3) +// Pascal Port By: Milan Marusinec alias Milano +// milan@marusinec.sk +// http://www.aggpas.org +// Copyright (c) 2007 - 2008 +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// + +unit agg_2D ; + +{$I agg_mode.inc } + +{.$Define CStackDebug} + +interface + + +{ With this define you can switch use of FreeType or Win32 TrueType font + engine. + + NOTE: + The FreeType font engine is recommended, even under Windows - simply + because it has more functionality and generates better looking text. If + enabled under Windows, your application will require the freetype.dll + though. The freetype.dll is included in the fpGUI repository for your + convenience. } + +{.$DEFINE AGG2D_USE_FREETYPE } + +{$IFDEF AGG2D_USE_FREETYPE} + {$UNDEF AGG2D_USE_WINFONTS} +{$ENDIF} + +uses + agg_basics , + agg_array , + agg_trans_affine , + agg_trans_viewport , + agg_path_storage , + agg_conv_stroke , + agg_conv_transform , + agg_conv_curve , + agg_conv_dash , + agg_rendering_buffer , + agg_renderer_base , + agg_renderer_scanline , + agg_span_gradient , + agg_span_image_filter_rgba , + agg_span_image_resample_rgba , + agg_span_converter , + agg_span_interpolator_linear , + agg_span_allocator , + agg_rasterizer_scanline_aa , + agg_gamma_functions , + agg_scanline_u , + agg_arc , + agg_bezier_arc , + agg_rounded_rect , + agg_font_engine , + agg_font_cache_manager , + agg_pixfmt , + agg_pixfmt_rgba , + agg_color , + agg_math_stroke , + agg_image_filters , + agg_vertex_source , + agg_render_scanlines , + agg_blur, + +{$IFDEF AGG2D_USE_FREETYPE } + agg_font_freetype , +{$ENDIF } +{$IFDEF AGG2D_USE_WINFONTS} + agg_font_win32_tt , + Windows , +{$ENDIF } + + Math ; + +{ GLOBAL VARIABLES & CONSTANTS } +const +// LineJoin + JoinMiter = miter_join; + JoinRound = round_join; + JoinBevel = bevel_join; + +// LineCap + CapButt = butt_cap; + CapSquare = square_cap; + CapRound = round_cap; + +// TextAlignment + AlignLeft = 0; + AlignRight = 1; + AlignCenter = 2; + AlignTop = AlignRight; + AlignBottom = AlignLeft; + +// BlendMode + BlendAlpha = end_of_comp_op_e; + BlendClear = comp_op_clear; + BlendSrc = comp_op_src; + BlendDst = comp_op_dst; + BlendSrcOver = comp_op_src_over; + BlendDstOver = comp_op_dst_over; + BlendSrcIn = comp_op_src_in; + BlendDstIn = comp_op_dst_in; + BlendSrcOut = comp_op_src_out; + BlendDstOut = comp_op_dst_out; + BlendSrcAtop = comp_op_src_atop; + BlendDstAtop = comp_op_dst_atop; + BlendXor = comp_op_xor; + BlendAdd = comp_op_plus; + BlendSub = comp_op_minus; + BlendMultiply = comp_op_multiply; + BlendScreen = comp_op_screen; + BlendOverlay = comp_op_overlay; + BlendDarken = comp_op_darken; + BlendLighten = comp_op_lighten; + BlendColorDodge = comp_op_color_dodge; + BlendColorBurn = comp_op_color_burn; + BlendHardLight = comp_op_hard_light; + BlendSoftLight = comp_op_soft_light; + BlendDifference = comp_op_difference; + BlendExclusion = comp_op_exclusion; + BlendContrast = comp_op_contrast; + +{ TYPES DEFINITION } +type + Color_ptr = ^Color; + Color = rgba8; + + Rect_ = agg_basics.rect; + RectD = agg_basics.rect_d; + + Affine = trans_affine; + Affine_ptr = trans_affine_ptr; + + FontRasterizer = gray8_adaptor_type; + FontRasterizer_ptr = gray8_adaptor_type_ptr; + + FontScanline = gray8_scanline_type; + FontScanline_ptr = gray8_scanline_type_ptr; + +{$IFDEF AGG2D_USE_FREETYPE } + FontEngine = font_engine_freetype_int32; +{$ENDIF } +{$IFDEF AGG2D_USE_WINFONTS} + FontEngine = font_engine_win32_tt_int32; +{$ENDIF } + + Gradient = (Solid ,Linear ,Radial ); + Direction = (CW, CCW ); + + LineJoin_ = int; + LineCap_ = int; + BlendMode_ = comp_op_e; + + TextAlignment = int; + + DrawPathFlag = ( + FillOnly , + StrokeOnly , + FillAndStroke , + FillWithLineColor ); + + ViewportOption = ( + Anisotropic , + XMinYMin , + XMidYMin , + XMaxYMin , + XMinYMid , + XMidYMid , + XMaxYMid , + XMinYMax , + XMidYMax , + XMaxYMax ); + + ImageFilter_ = ( + NoFilter , + Bilinear , + Hanning , + Hermite , + Quadric , + Bicubic , + Catrom , + Spline16 , + Spline36 , + Blackman144 ); + + ImageResample_ = ( + NoResample , + ResampleAlways , + ResampleOnZoomOut ); + + FontCacheType = ( + RasterFontCache , + VectorFontCache ); + + LineStyle = ( + stySolid, + styDash, + styDot, + styDashDot, + styDashDotDot ); + + Transformations_ptr = ^Transformations_; + Transformations_ = record + affineMatrix : array[0..5 ] of double; + + end; + + Image_ptr = ^Image; + Image = object + renBuf : rendering_buffer; + + constructor Construct; overload; + constructor Construct(buf : int8u_ptr; width_ ,height_ : unsigned; stride : int ); overload; + destructor Destruct; + + procedure attach(buf : int8u_ptr; width_ ,height_ : unsigned; stride : int ); + + function width : int; + function height : int; + + procedure premultiply; + procedure demultiply; + + end; + + Agg2DRasterizerGamma = object(vertex_source ) + m_alpha : gamma_multiply; + m_gamma : gamma_power; + + constructor Construct(alpha ,gamma : double ); + + function func_operator_gamma(x : double ) : double; virtual; + + end; + + Agg2D_ptr = ^Agg2D; + Agg2D = object + private + m_rbuf : rendering_buffer; + + m_pixFormat ,m_pixFormatComp ,m_pixFormatPre ,m_pixFormatCompPre : pixel_formats; + m_renBase ,m_renBaseComp ,m_renBasePre ,m_renBaseCompPre : renderer_base; + + m_renSolid ,m_renSolidComp : renderer_scanline_aa_solid; + + m_allocator : span_allocator; + m_clipBox : RectD; + + m_blendMode ,m_imageBlendMode : BlendMode_; + + m_imageBlendColor : Color; + + m_scanline : scanline_u8; + m_rasterizer : rasterizer_scanline_aa; + + m_masterAlpha ,m_antiAliasGamma : double; + + m_fillColor ,m_lineColor : Color; + + m_fillGradient ,m_lineGradient : pod_auto_array; + + m_lineCap : LineCap_; + m_lineJoin : LineJoin_; + + m_fillGradientFlag ,m_lineGradientFlag : Gradient; + + m_fillGradientMatrix ,m_lineGradientMatrix : trans_affine; + + m_fillGradientD1 , + m_lineGradientD1 , + m_fillGradientD2 , + m_lineGradientD2 , + m_textAngle : double; + m_textAlignX , + m_textAlignY : TextAlignment; + m_textHints : boolean; + m_fontHeight , + m_fontAscent , + m_fontDescent : double; + m_fontCacheType : FontCacheType; + + m_imageFilter : ImageFilter_; + m_imageResample : ImageResample_; + m_imageFilterLut : image_filter_lut; + + m_fillGradientInterpolator , + m_lineGradientInterpolator : span_interpolator_linear; + + m_linearGradientFunction : gradient_x; + m_radialGradientFunction : gradient_circle; + + m_lineWidth : double; + m_evenOddFlag : boolean; + + m_path : path_storage; + m_transform : trans_affine; + + m_convCurve : conv_curve; + m_convStroke : conv_stroke; + m_convDash: conv_dash; + + m_pathTransform ,m_strokeTransform : conv_transform; + + {$IFNDEF AGG2D_NO_FONT} + m_fontEngine : FontEngine; + m_fontCacheManager : font_cache_manager; + {$ENDIF} + {$IFDEF AGG2D_USE_WINFONTS } + m_fontDC : HDC; + {$ENDIF } + + // Other Pascal-specific members + m_gammaNone : gamma_none; + m_gammaAgg2D : Agg2DRasterizerGamma; + + m_ifBilinear : image_filter_bilinear; + m_ifHanning : image_filter_hanning; + m_ifHermite : image_filter_hermite; + m_ifQuadric : image_filter_quadric; + m_ifBicubic : image_filter_bicubic; + m_ifCatrom : image_filter_catrom; + m_ifSpline16 : image_filter_spline16; + m_ifSpline36 : image_filter_spline36; + m_ifBlackman144 : image_filter_blackman144; + + public + constructor Construct; + destructor Destruct; + + // Setup + procedure attach(buf : int8u_ptr; width_ ,height_ : unsigned; stride : int ); overload; + procedure attach(img : Image_ptr ); overload; + + procedure clipBox(x1 ,y1 ,x2 ,y2 : double ); overload; + function clipBox : RectD; overload; + + procedure clearAll(c : Color ); overload; + procedure clearAll(r ,g ,b : unsigned; a : unsigned = 255 ); overload; + procedure FillAll(c: Color); overload; + procedure FillAll(r, g, b: byte; a: byte = 255); overload; + + procedure clearClipBox(c : Color ); overload; + procedure clearClipBox(r ,g ,b : unsigned; a : unsigned = 255 ); overload; + + // Conversions + procedure worldToScreen(x ,y : double_ptr ); overload; + procedure screenToWorld(x ,y : double_ptr ); overload; + function worldToScreen(scalar : double ) : double; overload; + function screenToWorld(scalar : double ) : double; overload; + + procedure alignPoint(x ,y : double_ptr ); + + function inBox(worldX ,worldY : double ) : boolean; + + // General Attributes + procedure blendMode(m : BlendMode_ ); overload; + function blendMode : BlendMode_; overload; + + procedure imageBlendMode(m : BlendMode_ ); overload; + function imageBlendMode : BlendMode_; overload; + + procedure imageBlendColor(c : Color ); overload; + procedure imageBlendColor(r ,g ,b : unsigned; a : unsigned = 255 ); overload; + function imageBlendColor : Color; overload; + + procedure masterAlpha(a : double ); overload; + function masterAlpha : double; overload; + + procedure antiAliasGamma(g : double ); overload; + function antiAliasGamma : double; overload; + + procedure fillColor(c : Color ); overload; + procedure fillColor(r ,g ,b : unsigned; a : unsigned = 255 ); overload; + procedure noFill; + + procedure lineColor(c : Color ); overload; + procedure lineColor(r ,g ,b : unsigned; a : unsigned = 255 ); overload; + procedure noLine; + + function fillColor : Color; overload; + function lineColor : Color; overload; + + procedure fillLinearGradient(x1 ,y1 ,x2 ,y2 : double; c1 ,c2 : Color; profile : double = 1.0 ); + procedure lineLinearGradient(x1 ,y1 ,x2 ,y2 : double; c1 ,c2 : Color; profile : double = 1.0 ); + + procedure fillRadialGradient(x ,y ,r : double; c1 ,c2 : Color; profile : double = 1.0 ); overload; + procedure lineRadialGradient(x ,y ,r : double; c1 ,c2 : Color; profile : double = 1.0 ); overload; + + procedure fillRadialGradient(x ,y ,r : double; c1 ,c2 ,c3 : Color ); overload; + procedure lineRadialGradient(x ,y ,r : double; c1 ,c2 ,c3 : Color ); overload; + + procedure fillRadialGradient(x ,y ,r : double ); overload; + procedure lineRadialGradient(x ,y ,r : double ); overload; + + procedure lineWidth (w : double ); + function lineWidth_(w : double ) : double; + + procedure lineCap(cap : LineCap_ ); overload; + function lineCap : LineCap_; overload; + + procedure lineJoin(join : LineJoin_ ); overload; + function lineJoin : LineJoin_; overload; + + procedure fillEvenOdd(evenOddFlag : boolean ); overload; + function fillEvenOdd : boolean; overload; + + procedure SetLineStyle(awidth: double; astyle: LineStyle); + + // Transformations + function transformations : Transformations_; overload; + procedure transformations(tr : Transformations_ptr ); overload; + procedure resetTransformations; + + procedure affine(tr : Affine_ptr ); overload; + procedure affine(tr : Transformations_ptr ); overload; + + procedure rotate (angle : double ); + procedure scale (sx ,sy : double ); + procedure skew (sx ,sy : double ); + procedure translate(x ,y : double ); + + procedure parallelogram(x1 ,y1 ,x2 ,y2 : double; para : double_ptr ); + + procedure viewport( + worldX1 ,worldY1 ,worldX2 ,worldY2 , + screenX1 ,screenY1 ,screenX2 ,screenY2 : double; + opt : ViewportOption = XMidYMid ); + + // Basic Shapes + procedure line (const x1 ,y1 ,x2 ,y2 : double; AFixAlignment: boolean = false ); + procedure triangle (x1 ,y1 ,x2 ,y2 ,x3 ,y3 : double ); + procedure rectangle(const x1 ,y1 ,x2 ,y2 : double; AFixAlignment: boolean = false); + + procedure roundedRect(x1 ,y1 ,x2 ,y2 ,r : double ); overload; + procedure roundedRect(x1 ,y1 ,x2 ,y2 ,rx ,ry : double ); overload; + procedure roundedRect( + x1 ,y1 ,x2 ,y2 , + rxBottom ,ryBottom , + rxTop ,ryTop : double ); overload; + + procedure ellipse(cx ,cy ,rx ,ry : double ); + + procedure arc (cx ,cy ,rx ,ry ,start ,sweep : double ); + procedure star(cx ,cy ,r1 ,r2 ,startAngle : double; numRays : int ); + + procedure curve(x1 ,y1 ,x2 ,y2 ,x3 ,y3 : double ); overload; + procedure curve(x1 ,y1 ,x2 ,y2 ,x3 ,y3 ,x4 ,y4 : double ); overload; + + procedure polygon (xy : double_ptr; numPoints : int ); + procedure polyline(xy : double_ptr; numPoints : int ); + + // Text + procedure flipText(flip : boolean ); + + procedure font( + fileName : char_ptr; height : double; + bold : boolean = false; + italic : boolean = false; + ch : FontCacheType = VectorFontCache; + angle : double = 0.0 ); + + function fontHeight : double; + + procedure textAlignment(alignX ,alignY : TextAlignment ); + + function textHints : boolean; overload; + procedure textHints(hints : boolean ); overload; + function textWidth(str : AnsiString ) : double; + + procedure text( + x ,y : double; str : AnsiString; + roundOff : boolean = false; + ddx : double = 0.0; + ddy : double = 0.0 ); + + // Path commands + procedure resetPath; + + procedure moveTo (x ,y : double ); + procedure moveRel(dx ,dy : double ); + + procedure lineTo (x ,y : double ); + procedure lineRel(dx ,dy : double ); + + procedure horLineTo (x : double ); + procedure horLineRel(dx : double ); + + procedure verLineTo (y : double ); + procedure verLineRel(dy : double ); + + procedure arcTo( + rx ,ry ,angle : double; + largeArcFlag ,sweepFlag : boolean; + x ,y : double ); + + procedure arcRel( + rx ,ry ,angle : double; + largeArcFlag ,sweepFlag : boolean; + dx ,dy : double ); + + procedure quadricCurveTo (xCtrl ,yCtrl ,xTo ,yTo : double ); overload; + procedure quadricCurveRel(dxCtrl ,dyCtrl ,dxTo ,dyTo : double ); overload; + procedure quadricCurveTo (xTo ,yTo : double ); overload; + procedure quadricCurveRel(dxTo ,dyTo : double ); overload; + + procedure cubicCurveTo (xCtrl1 ,yCtrl1 ,xCtrl2 ,yCtrl2 ,xTo ,yTo : double ); overload; + procedure cubicCurveRel(dxCtrl1 ,dyCtrl1 ,dxCtrl2 ,dyCtrl2 ,dxTo ,dyTo : double ); overload; + procedure cubicCurveTo (xCtrl2 ,yCtrl2 ,xTo ,yTo : double ); overload; + procedure cubicCurveRel(xCtrl2 ,yCtrl2 ,xTo ,yTo : double ); overload; + + procedure addEllipse(cx ,cy ,rx ,ry : double; dir : Direction ); + procedure closePolygon; + + procedure drawPath(flag : DrawPathFlag = FillAndStroke ); + + procedure drawPathNoTransform(flag : DrawPathFlag = FillAndStroke ); + + // Image Transformations + procedure imageFilter(f : ImageFilter_ ); overload; + function imageFilter : ImageFilter_; overload; + + procedure imageResample(f : ImageResample_ ); overload; + function imageResample : ImageResample_; overload; + + procedure transformImage( + img : Image_ptr; + imgX1 ,imgY1 ,imgX2 ,imgY2 : int; + dstX1 ,dstY1 ,dstX2 ,dstY2 : double ); overload; + + procedure transformImage( + img : Image_ptr; + dstX1 ,dstY1 ,dstX2 ,dstY2 : double ); overload; + + procedure transformImage( + img : Image_ptr; + imgX1 ,imgY1 ,imgX2 ,imgY2 : int; + parallelogram_ : double_ptr ); overload; + + procedure transformImage(img : Image_ptr; parallelogram_ : double_ptr ); overload; + + procedure transformImagePath( + img : Image_ptr; + imgX1 ,imgY1 ,imgX2 ,imgY2 : int; + dstX1 ,dstY1 ,dstX2 ,dstY2 : double ); overload; + + procedure transformImagePath( + img : Image_ptr; + dstX1 ,dstY1 ,dstX2 ,dstY2 : double ); overload; + + procedure transformImagePath( + img : Image_ptr; + imgX1 ,imgY1 ,imgX2 ,imgY2 : int; + parallelogram_ : double_ptr ); overload; + + procedure transformImagePath(img : Image_ptr; parallelogram_ : double_ptr ); overload; + procedure Blur(rx ,ry : unsigned); + + // Image Blending (no transformations available) + procedure blendImage( + img : Image_ptr; + imgX1 ,imgY1 ,imgX2 ,imgY2 : int; + dstX ,dstY : double; alpha : unsigned = 255 ); overload; + + procedure blendImage(img : Image_ptr; dstX ,dstY : double; alpha : unsigned = 255 ); overload; + + // Copy image directly, together with alpha-channel + procedure copyImage( + img : Image_ptr; + imgX1 ,imgY1 ,imgX2 ,imgY2 : int; + dstX ,dstY : double ); overload; + + procedure copyImage(img : Image_ptr; dstX ,dstY : double ); overload; + + private + procedure render(fillColor_ : boolean ); overload; + procedure render(ras : FontRasterizer_ptr; sl : FontScanline_ptr ); overload; + + procedure addLine(x1 ,y1 ,x2 ,y2 : double ); + procedure updateRasterizerGamma; + procedure renderImage( + img : Image_ptr; + x1 ,y1 ,x2 ,y2 : int; + parl : double_ptr ); + + end; + + SpanConvImageBlend_ptr = ^SpanConvImageBlend; + SpanConvImageBlend = object(span_convertor ) + private + m_mode : BlendMode_; + m_color : Color; + m_pixel : pixel_formats_ptr; // m_pixFormatCompPre + + public + constructor Construct(m : BlendMode_; c : Color; p : pixel_formats_ptr ); + + procedure convert(span : aggclr_ptr; x ,y : int; len : unsigned ); virtual; + + end; + +{ GLOBAL PROCEDURES } +// Auxiliary + function pi : double; + function deg2Rad(v : double ) : double; + function rad2Deg(v : double ) : double; + + function operator_is_equal (c1 ,c2 : Color_ptr ) : boolean; + function operator_is_not_equal(c1 ,c2 : Color_ptr ) : boolean; + + procedure Agg2DRenderer_render( + gr : Agg2D_ptr; + renBase : renderer_base_ptr; + renSolid : renderer_scanline_aa_solid_ptr; + fillColor_ : boolean ); overload; + + procedure Agg2DRenderer_render( + gr : Agg2D_ptr; + renBase : renderer_base_ptr; + renSolid : renderer_scanline_aa_solid_ptr; + ras : gray8_adaptor_type_ptr; + sl : gray8_scanline_type_ptr ); overload; + + procedure Agg2DRenderer_renderImage( + gr : Agg2D_ptr; + img : Image_ptr; + renBase : renderer_base_ptr; + interpolator : span_interpolator_linear_ptr ); + + function Agg2DUsesFreeType : boolean; + function Agg2DUsesWin32TrueType : boolean; + +IMPLEMENTATION + +{ LOCAL VARIABLES & CONSTANTS } +var + g_approxScale : double = 2.0; + +{ copied from the "fpg_stringutils" unit. } +function UTF8CharToUnicode(p: PChar; out CharLen: longint): Cardinal; +begin + if p=nil then begin + Result:=0; + CharLen:=0; + exit; + end; + if ord(p^) < $C0 then begin + // regular single byte character (#0 is a normal char, this is pascal ;) + end + else if ((ord(p^) and $E0) = $C0) then begin + // could be double byte character + if (ord(p[1]) and $C0) = $80 then begin + Result:=((ord(p^) and $1F) shl 6) + or (ord(p[1]) and $3F); + CharLen:=2; + exit; + end; + end + else if ((ord(p^) and $F0) = $E0) then begin + // could be triple byte character + if ((ord(p[1]) and $C0) = $80) + and ((ord(p[2]) and $C0) = $80) then begin + Result:=((ord(p^) and $1F) shl 12) + or ((ord(p[1]) and $3F) shl 6) + or (ord(p[2]) and $3F); + CharLen:=3; + exit; + end; + end + else if ((ord(p^) and $F8) = $F0) then begin + // could be 4 byte character + if ((ord(p[1]) and $C0) = $80) + and ((ord(p[2]) and $C0) = $80) + and ((ord(p[3]) and $C0) = $80) then begin + Result:=((ord(p^) and $0F) shl 18) + or ((ord(p[1]) and $3F) shl 12) + or ((ord(p[2]) and $3F) shl 6) + or (ord(p[3]) and $3F); + CharLen:=4; + exit; + end; + end + else begin + // invalid character + end; + Result:=ord(p^); + CharLen:=1; +end; + +{ UNIT IMPLEMENTATION } +{ CONSTRUCT } +constructor Image.Construct; +begin +end; + +{ CONSTRUCT } +constructor Image.Construct(buf : int8u_ptr; width_ ,height_ : unsigned; stride : int ); +begin + renBuf.Construct(buf ,width_ ,height_ ,stride ); + +end; + +{ DESTRUCT } +destructor Image.Destruct; +begin + renBuf.Destruct; + +end; + +{ ATTACH } +procedure Image.attach(buf : int8u_ptr; width_ ,height_ : unsigned; stride : int ); +begin + renBuf.attach(buf ,width_ ,height_ ,stride ); + +end; + +{ WIDTH } +function Image.width : int; +begin + result:=renBuf._width; + +end; + +{ HEIGHT } +function Image.height : int; +begin + result:=renBuf._height; + +end; + +{ PREMULTIPLY } +procedure Image.premultiply; +var + pixf : pixel_formats; + +begin +{ pixfmt_rgba32(pixf ,@renBuf ); + + pixf.premultiply; } + +end; + +{ DEMULTIPLY } +procedure Image.demultiply; +var + pixf : pixel_formats; + +begin +{ pixfmt_rgba32(pixf ,@renBuf ); + + pixf.demultiply; } + +end; + +{ CONSTRUCT } +constructor Agg2DRasterizerGamma.Construct(alpha ,gamma : double ); +begin + m_alpha.Construct(alpha ); + m_gamma.Construct(gamma ); + +end; + +{ FUNC_OPERATOR_GAMMA } +function Agg2DRasterizerGamma.func_operator_gamma(x : double ) : double; +begin + result:=m_alpha.func_operator_gamma(m_gamma.func_operator_gamma(x ) ); + +end; + +{ CONSTRUCT } +constructor Agg2D.Construct; +begin + m_rbuf.Construct; + + pixfmt_rgba32 (m_pixFormat ,@m_rbuf ); + pixfmt_custom_blend_rgba(m_pixFormatComp ,@m_rbuf ,@comp_op_adaptor_rgba ,rgba_order ); + pixfmt_rgba32 (m_pixFormatPre ,@m_rbuf ); + pixfmt_custom_blend_rgba(m_pixFormatCompPre ,@m_rbuf ,@comp_op_adaptor_rgba ,rgba_order ); + + m_renBase.Construct (@m_pixFormat ); + m_renBaseComp.Construct (@m_pixFormatComp ); + m_renBasePre.Construct (@m_pixFormatPre ); + m_renBaseCompPre.Construct(@m_pixFormatCompPre ); + + m_renSolid.Construct (@m_renBase ); + m_renSolidComp.Construct(@m_renBaseComp ); + + m_allocator.Construct; + m_clipBox.Construct(0 ,0 ,0 ,0 ); + + m_blendMode :=BlendAlpha; + m_imageBlendMode:=BlendDst; + + m_imageBlendColor.Construct(0 ,0 ,0 ); + + m_scanline.Construct; + m_rasterizer.Construct; + + m_masterAlpha :=1.0; + m_antiAliasGamma:=1.0; + + m_fillColor.Construct(255 ,255 ,255 ); + m_lineColor.Construct(0 ,0 ,0 ); + + m_fillGradient.Construct(256 ,sizeof(aggclr ) ); + m_lineGradient.Construct(256 ,sizeof(aggclr ) ); + + m_lineCap :=CapRound; + m_lineJoin:=JoinRound; + + m_fillGradientFlag:=Solid; + m_lineGradientFlag:=Solid; + + m_fillGradientMatrix.Construct; + m_lineGradientMatrix.Construct; + + m_fillGradientD1:=0.0; + m_lineGradientD1:=0.0; + m_fillGradientD2:=100.0; + m_lineGradientD2:=100.0; + + m_textAngle :=0.0; + m_textAlignX :=AlignLeft; + m_textAlignY :=AlignBottom; + m_textHints :=true; + m_fontHeight :=0.0; + m_fontAscent :=0.0; + m_fontDescent:=0.0; + + m_fontCacheType:=RasterFontCache; + m_imageFilter :=Bilinear; + m_imageResample:=NoResample; + + m_gammaNone.Construct; + + m_ifBilinear.Construct; + m_ifHanning.Construct; + m_ifHermite.Construct; + m_ifQuadric.Construct; + m_ifBicubic.Construct; + m_ifCatrom.Construct; + m_ifSpline16.Construct; + m_ifSpline36.Construct; + m_ifBlackman144.Construct; + + m_imageFilterLut.Construct(@m_ifBilinear ,true ); + + m_linearGradientFunction.Construct; + m_radialGradientFunction.Construct; + + m_fillGradientInterpolator.Construct(@m_fillGradientMatrix ); + m_lineGradientInterpolator.Construct(@m_lineGradientMatrix ); + + m_lineWidth :=1; + m_evenOddFlag:=false; + + m_path.Construct; + m_transform.Construct; + + m_convCurve.Construct(@m_path); + m_convDash.Construct(@m_convCurve); + m_convStroke.Construct(@m_convDash); + + m_pathTransform.Construct (@m_convCurve ,@m_transform ); + m_strokeTransform.Construct(@m_convStroke ,@m_transform ); + + SetLineStyle(m_lineWidth, stySolid); + +{$IFDEF AGG2D_USE_FREETYPE } + m_fontEngine.Construct; +{$ENDIF } +{$IFDEF AGG2D_USE_WINFONTS} + m_fontDC:=GetDC(0 ); + m_fontEngine.Construct(m_fontDC ); +{$ENDIF } +{$IFNDEF AGG2D_NO_FONT} + m_fontCacheManager.Construct(@m_fontEngine ); +{$ENDIF} + + lineCap (m_lineCap ); + lineJoin(m_lineJoin ); + +end; + +{ DESTRUCT } +destructor Agg2D.Destruct; +begin + m_rbuf.Destruct; + m_allocator.Destruct; + + m_scanline.Destruct; + m_rasterizer.Destruct; + + m_fillGradient.Destruct; + m_lineGradient.Destruct; + + m_imageFilterLut.Destruct; + + m_convStroke.Destruct; + m_convDash.Destruct; + m_convCurve.Destruct; + + m_path.Destruct; + +{$IFNDEF AGG2D_NO_FONT} + m_fontEngine.Destruct; + m_fontCacheManager.Destruct; +{$ENDIF} +{$IFDEF AGG2D_USE_WINFONTS } + ReleaseDC(0 ,m_fontDC ); +{$ENDIF } +end; + +{ ATTACH } +procedure Agg2D.attach(buf : int8u_ptr; width_ ,height_ : unsigned; stride : int ); +begin + m_rbuf.attach(buf ,width_ ,height_ ,stride ); + + m_renBase.reset_clipping (true ); + m_renBaseComp.reset_clipping (true ); + m_renBasePre.reset_clipping (true ); + m_renBaseCompPre.reset_clipping(true ); + + resetTransformations; + + lineWidth(1.0 ); + lineColor(0 ,0 ,0 ); + fillColor(255 ,255 ,255 ); + + textAlignment(AlignLeft ,AlignBottom ); + + clipBox (0 ,0 ,width_ ,height_ ); + lineCap (CapRound ); + lineJoin(JoinRound ); + flipText(false ); + + imageFilter (Bilinear ); + imageResample(NoResample ); + + m_masterAlpha :=1.0; + m_antiAliasGamma:=1.0; + + m_rasterizer.gamma(@m_gammaNone ); + + m_blendMode:=BlendAlpha; + +end; + +{ ATTACH } +procedure Agg2D.attach(img : Image_ptr ); +begin + attach(img.renBuf._buf ,img.renBuf._width ,img.renBuf._height ,img.renBuf._stride ); + +end; + +{ CLIPBOX } +procedure Agg2D.clipBox(x1 ,y1 ,x2 ,y2 : double ); +var + rx1 ,ry1 ,rx2 ,ry2 : int; + +begin + m_clipBox.Construct(x1 ,y1 ,x2 ,y2 ); + + rx1:=Trunc(x1 ); + ry1:=Trunc(y1 ); + rx2:=Trunc(x2 ); + ry2:=Trunc(y2 ); + + m_renBase.clip_box_ (rx1 ,ry1 ,rx2 ,ry2 ); + m_renBaseComp.clip_box_ (rx1 ,ry1 ,rx2 ,ry2 ); + m_renBasePre.clip_box_ (rx1 ,ry1 ,rx2 ,ry2 ); + m_renBaseCompPre.clip_box_(rx1 ,ry1 ,rx2 ,ry2 ); + + m_rasterizer.clip_box(x1 ,y1 ,x2 ,y2 ); + +end; + +{ CLIPBOX } +function Agg2D.clipBox : RectD; +begin + result:=m_clipBox; + +end; + +{ CLEARALL } +procedure Agg2D.clearAll(c : Color ); +var + clr : aggclr; + +begin + clr.Construct (c ); + m_renBase.clear(@clr ); + +end; + +{ CLEARALL } +procedure Agg2D.clearAll(r ,g ,b : unsigned; a : unsigned = 255 ); +var + clr : Color; + +begin + clr.Construct(r ,g ,b ,a ); + clearAll (clr ); + +end; + +procedure Agg2D.FillAll(c: Color); +var + clr: aggclr; +begin + clr.Construct (c ); + m_renBase.fill(@clr ); +end; + +procedure Agg2D.FillAll(r, g, b: byte; a: byte); +var + clr: Color; +begin + clr.Construct(r, g, b, a); + FillAll(clr); +end; + +{ CLEARCLIPBOX } +procedure Agg2D.clearClipBox(c : Color ); +var + clr : aggclr; + +begin + clr.Construct(c ); + + m_renBase.copy_bar(0 ,0 ,m_renBase.width ,m_renBase.height ,@clr ); + +end; + +{ CLEARCLIPBOX } +procedure Agg2D.clearClipBox(r ,g ,b : unsigned; a : unsigned = 255 ); +var + clr : Color; + +begin + clr.Construct(r ,g ,b ,a ); + clearClipBox (clr ); + +end; + +{ WORLDTOSCREEN } +procedure Agg2D.worldToScreen(x ,y : double_ptr ); +begin + m_transform.transform(@m_transform ,x ,y ); + +end; + +{ SCREENTOWORLD } +procedure Agg2D.screenToWorld(x ,y : double_ptr ); +begin + m_transform.inverse_transform(@m_transform ,x ,y ); + +end; + +{ WORLDTOSCREEN } +function Agg2D.worldToScreen(scalar : double ) : double; +var + x1 ,y1 ,x2 ,y2 : double; + +begin + x1:=0; + y1:=0; + x2:=scalar; + y2:=scalar; + + worldToScreen(@x1 ,@y1 ); + worldToScreen(@x2 ,@y2 ); + + result:=Sqrt((x2 - x1 ) * (x2 - x1 ) + (y2 - y1 ) * (y2 - y1 ) ) * 0.7071068; + +end; + +{ SCREENTOWORLD } +function Agg2D.screenToWorld(scalar : double ) : double; +var + x1 ,y1 ,x2 ,y2 : double; + +begin + x1:=0; + y1:=0; + x2:=scalar; + y2:=scalar; + + screenToWorld(@x1 ,@y1 ); + screenToWorld(@x2 ,@y2 ); + + result:=Sqrt((x2 - x1 ) * (x2 - x1 ) + (y2 - y1 ) * (y2 - y1 ) ) * 0.7071068; + +end; + +{ ALIGNPOINT } +procedure Agg2D.alignPoint(x ,y : double_ptr ); +begin + worldToScreen(x ,y ); + + x^:=Floor(x^ ) + 0.5; + y^:=Floor(y^ ) + 0.5; + + screenToWorld(x ,y ); + +end; + +{ INBOX } +function Agg2D.inBox(worldX ,worldY : double ) : boolean; +begin + worldToScreen(@worldX ,@worldY ); + + result:=m_renBase.inbox(Trunc(worldX ) ,Trunc(worldY ) ); + +end; + +{ BLENDMODE } +procedure Agg2D.blendMode(m : BlendMode_ ); +begin + m_blendMode:=m; + + m_pixFormatComp.comp_op_ (unsigned(m ) ); + m_pixFormatCompPre.comp_op_(unsigned(m ) ); + +end; + +{ BLENDMODE } +function Agg2D.blendMode : BlendMode_; +begin + result:=m_blendMode; + +end; + +{ IMAGEBLENDMODE } +procedure Agg2D.imageBlendMode(m : BlendMode_ ); +begin + m_imageBlendMode:=m; + +end; + +{ IMAGEBLENDMODE } +function Agg2D.imageBlendMode : BlendMode_; +begin + result:=m_imageBlendMode; + +end; + +{ IMAGEBLENDCOLOR } +procedure Agg2D.imageBlendColor(c : Color ); +begin + m_imageBlendColor:=c; + +end; + +{ IMAGEBLENDCOLOR } +procedure Agg2D.imageBlendColor(r ,g ,b : unsigned; a : unsigned = 255 ); +var + clr : Color; + +begin + clr.Construct (r ,g ,b ,a ); + imageBlendColor(clr ); + +end; + +{ IMAGEBLENDCOLOR } +function Agg2D.imageBlendColor : Color; +begin + result:=m_imageBlendColor; + +end; + +{ MASTERALPHA } +procedure Agg2D.masterAlpha(a : double ); +begin + m_masterAlpha:=a; + + updateRasterizerGamma; + +end; + +{ MASTERALPHA } +function Agg2D.masterAlpha : double; +begin + result:=m_masterAlpha; + +end; + +{ ANTIALIASGAMMA } +procedure Agg2D.antiAliasGamma(g : double ); +begin + m_antiAliasGamma:=g; + + updateRasterizerGamma; + +end; + +{ ANTIALIASGAMMA } +function Agg2D.antiAliasGamma : double; +begin + result:=m_antiAliasGamma; + +end; + +{ FILLCOLOR } +procedure Agg2D.fillColor(c : Color ); +begin + m_fillColor :=c; + m_fillGradientFlag:=Solid; + +end; + +{ FILLCOLOR } +procedure Agg2D.fillColor(r ,g ,b : unsigned; a : unsigned = 255 ); +var + clr : Color; + +begin + clr.Construct(r ,g ,b ,a ); + fillColor (clr ); + +end; + +{ NOFILL } +procedure Agg2D.noFill; +var + clr : Color; + +begin + clr.Construct(0 ,0 ,0 ,0 ); + fillColor (clr ); + +end; + +{ LINECOLOR } +procedure Agg2D.lineColor(c : Color ); +begin + m_lineColor :=c; + m_lineGradientFlag:=Solid; + +end; + +{ LINECOLOR } +procedure Agg2D.lineColor(r ,g ,b : unsigned; a : unsigned = 255 ); +var + clr : Color; + +begin + clr.Construct(r ,g ,b ,a ); + lineColor (clr ); + +end; + +{ NOLINE } +procedure Agg2D.noLine; +var + clr : Color; + +begin + clr.Construct(0 ,0 ,0 ,0 ); + lineColor (clr ); + +end; + +{ FILLCOLOR } +function Agg2D.fillColor : Color; +begin + result:=m_fillColor; + +end; + +{ LINECOLOR } +function Agg2D.lineColor : Color; +begin + result:=m_lineColor; + +end; + +{ FILLLINEARGRADIENT } +procedure Agg2D.fillLinearGradient(x1 ,y1 ,x2 ,y2 : double; c1 ,c2 : Color; profile : double = 1.0 ); +var + i ,startGradient ,endGradient : int; + + k ,angle : double; + + c : Color; + + clr : aggclr; + tar : trans_affine_rotation; + tat : trans_affine_translation; + +begin + startGradient:=128 - Trunc(profile * 127.0 ); + endGradient :=128 + Trunc(profile * 127.0 ); + + if endGradient <= startGradient then + endGradient:=startGradient + 1; + + k:=1.0 / (endGradient - startGradient ); + i:=0; + + while i < startGradient do + begin + clr.Construct(c1 ); + + move(clr ,m_fillGradient.array_operator(i )^ ,sizeof(aggclr ) ); + inc (i ); + + end; + + while i < endGradient do + begin + c:=c1.gradient(c2 ,(i - startGradient ) * k ); + + clr.Construct(c ); + + move(clr ,m_fillGradient.array_operator(i )^ ,sizeof(aggclr ) ); + inc (i ); + + end; + + while i < 256 do + begin + clr.Construct(c2 ); + + move(clr ,m_fillGradient.array_operator(i )^ ,sizeof(aggclr ) ); + inc (i ); + + end; + + angle:=ArcTan2(y2 - y1 ,x2 - x1 ); + + m_fillGradientMatrix.reset; + + tar.Construct(angle ); + + m_fillGradientMatrix.multiply(@tar ); + + tat.Construct(x1 ,y1 ); + + m_fillGradientMatrix.multiply(@tat ); + m_fillGradientMatrix.multiply(@m_transform ); + m_fillGradientMatrix.invert; + + m_fillGradientD1 :=0.0; + m_fillGradientD2 :=Sqrt((x2 - x1 ) * (x2 - x1 ) + (y2 - y1 ) * (y2 - y1 ) ); + m_fillGradientFlag:=Linear; + + m_fillColor.Construct(0 ,0 ,0 ); // Set some real color + +end; + +{ LINELINEARGRADIENT } +procedure Agg2D.lineLinearGradient(x1 ,y1 ,x2 ,y2 : double; c1 ,c2 : Color; profile : double = 1.0 ); +var + i ,startGradient ,endGradient : int; + + k ,angle : double; + + c : Color; + + clr : aggclr; + tar : trans_affine_rotation; + tat : trans_affine_translation; + +begin + startGradient:=128 - Trunc(profile * 128.0 ); + endGradient :=128 + Trunc(profile * 128.0 ); + + if endGradient <= startGradient then + endGradient:=startGradient + 1; + + k:=1.0 / (endGradient - startGradient ); + i:=0; + + while i < startGradient do + begin + clr.Construct(c1 ); + + move(clr ,m_lineGradient.array_operator(i )^ ,sizeof(aggclr ) ); + inc (i ); + + end; + + while i < endGradient do + begin + c:=c1.gradient(c2 ,(i - startGradient) * k ); + + clr.Construct(c ); + + move(clr ,m_lineGradient.array_operator(i )^ ,sizeof(aggclr ) ); + inc (i ); + + end; + + while i < 256 do + begin + clr.Construct(c2 ); + + move(clr ,m_lineGradient.array_operator(i )^ ,sizeof(aggclr ) ); + inc (i ); + + end; + + angle:=ArcTan2(y2 - y1 ,x2 - x1 ); + + m_lineGradientMatrix.reset; + + tar.Construct(angle ); + + m_lineGradientMatrix.multiply(@tar ); + + tat.Construct(x1 ,y1 ); + + m_lineGradientMatrix.multiply(@tat ); + m_lineGradientMatrix.multiply(@m_transform ); {!} + m_lineGradientMatrix.invert; + + m_lineGradientD1 :=0.0; + m_lineGradientD2 :=Sqrt((x2 - x1 ) * (x2 - x1 ) + (y2 - y1 ) * (y2 - y1 ) ); + m_lineGradientFlag:=Linear; + + m_lineColor.Construct(0 ,0 ,0 ); // Set some real color + +end; + +{ FILLRADIALGRADIENT } +procedure Agg2D.fillRadialGradient(x ,y ,r : double; c1 ,c2 : Color; profile : double = 1.0 ); +var + i ,startGradient ,endGradient : int; + + k : double; + c : Color; + + clr : aggclr; + tat : trans_affine_translation; + +begin + startGradient:=128 - Trunc(profile * 127.0 ); + endGradient :=128 + Trunc(profile * 127.0 ); + + if endGradient <= startGradient then + endGradient:=startGradient + 1; + + k:=1.0 / (endGradient - startGradient ); + i:=0; + + while i < startGradient do + begin + clr.Construct(c1 ); + + move(clr ,m_fillGradient.array_operator(i )^ ,sizeof(aggclr ) ); + inc (i ); + + end; + + while i < endGradient do + begin + c:=c1.gradient(c2 ,(i - startGradient ) * k ); + + clr.Construct(c ); + + move(clr ,m_fillGradient.array_operator(i )^ ,sizeof(aggclr ) ); + inc (i ); + + end; + + while i < 256 do + begin + clr.Construct(c2 ); + + move(clr ,m_fillGradient.array_operator(i )^ ,sizeof(aggclr ) ); + inc (i ); + + end; + + m_fillGradientD2:=worldToScreen(r ); + + worldToScreen(@x ,@y ); + + m_fillGradientMatrix.reset; + + tat.Construct(x ,y ); + + m_fillGradientMatrix.multiply(@tat ); + m_fillGradientMatrix.invert; + + m_fillGradientD1 :=0; + m_fillGradientFlag:=Radial; + + m_fillColor.Construct(0 ,0 ,0 ); // Set some real color + +end; + +{ LINERADIALGRADIENT } +procedure Agg2D.lineRadialGradient(x ,y ,r : double; c1 ,c2 : Color; profile : double = 1.0 ); +var + i ,startGradient ,endGradient : int; + + k : double; + c : Color; + + clr : aggclr; + tat : trans_affine_translation; + +begin + startGradient:=128 - Trunc(profile * 128.0 ); + endGradient :=128 + Trunc(profile * 128.0 ); + + if endGradient <= startGradient then + endGradient:=startGradient + 1; + + k:=1.0 / (endGradient - startGradient ); + i:=0; + + while i < startGradient do + begin + clr.Construct(c1 ); + + move(clr ,m_lineGradient.array_operator(i )^ ,sizeof(aggclr ) ); + inc (i ); + + end; + + while i < endGradient do + begin + c:=c1.gradient(c2 ,(i - startGradient ) * k ); + + clr.Construct(c ); + + move(clr ,m_lineGradient.array_operator(i )^ ,sizeof(aggclr ) ); + inc (i ); + + end; + + while i < 256 do + begin + clr.Construct(c2 ); + + move(clr ,m_lineGradient.array_operator(i )^ ,sizeof(aggclr ) ); + inc (i ); + + end; + + m_lineGradientD2:=worldToScreen(r ); + + worldToScreen(@x ,@y ); + + m_lineGradientMatrix.reset; + + tat.Construct(x ,y ); + + m_lineGradientMatrix.multiply(@tat ); + m_lineGradientMatrix.invert; + + m_lineGradientD1 :=0; + m_lineGradientFlag:=Radial; + + m_lineColor.Construct(0 ,0 ,0 ); // Set some real color + +end; + +{ FILLRADIALGRADIENT } +procedure Agg2D.fillRadialGradient(x ,y ,r : double; c1 ,c2 ,c3 : Color ); +var + i : int; + c : Color; + + clr : aggclr; + tat : trans_affine_translation; + +begin + i:=0; + + while i < 128 do + begin + c:=c1.gradient(c2 ,i / 127.0 ); + + clr.Construct(c ); + + move(clr ,m_fillGradient.array_operator(i )^ ,sizeof(aggclr ) ); + inc (i ); + + end; + + while i < 256 do + begin + c:=c2.gradient(c3 ,(i - 128 ) / 127.0 ); + + clr.Construct(c ); + + move(clr ,m_fillGradient.array_operator(i )^ ,sizeof(aggclr ) ); + inc (i ); + + end; + + m_fillGradientD2:=worldToScreen(r ); + + worldToScreen(@x ,@y ); + + m_fillGradientMatrix.reset; + + tat.Construct(x ,y ); + + m_fillGradientMatrix.multiply(@tat ); + m_fillGradientMatrix.invert; + + m_fillGradientD1 :=0; + m_fillGradientFlag:=Radial; + + m_fillColor.Construct(0 ,0 ,0 ); // Set some real color + +end; + +{ LINERADIALGRADIENT } +procedure Agg2D.lineRadialGradient(x ,y ,r : double; c1 ,c2 ,c3 : Color ); +var + i : int; + c : Color; + + clr : aggclr; + tat : trans_affine_translation; + +begin + i:=0; + + while i < 128 do + begin + c:=c1.gradient(c2 ,i / 127.0 ); + + clr.Construct(c ); + + move(clr ,m_lineGradient.array_operator(i )^ ,sizeof(aggclr ) ); + inc (i ); + + end; + + while i < 256 do + begin + c:=c2.gradient(c3 ,(i - 128 ) / 127.0 ); + + clr.Construct(c ); + + move(clr ,m_lineGradient.array_operator(i )^ ,sizeof(aggclr ) ); + inc (i ); + + end; + + m_lineGradientD2:=worldToScreen(r ); + + worldToScreen(@x ,@y ); + + m_lineGradientMatrix.reset; + + tat.Construct(x ,y ); + + m_lineGradientMatrix.multiply(@tat ); + m_lineGradientMatrix.invert; + + m_lineGradientD1 :=0; + m_lineGradientFlag:=Radial; + + m_lineColor.Construct(0 ,0 ,0 ); // Set some real color + +end; + +{ FILLRADIALGRADIENT } +procedure Agg2D.fillRadialGradient(x ,y ,r : double ); +var + tat : trans_affine_translation; + +begin + m_fillGradientD2:=worldToScreen(r ); + + worldToScreen(@x ,@y ); + + m_fillGradientMatrix.reset; + + tat.Construct(x ,y ); + + m_fillGradientMatrix.multiply(@tat ); + m_fillGradientMatrix.invert; + + m_fillGradientD1:=0; + +end; + +{ LINERADIALGRADIENT } +procedure Agg2D.lineRadialGradient(x ,y ,r : double ); +var + tat : trans_affine_translation; + +begin + m_lineGradientD2:=worldToScreen(r ); + + worldToScreen(@x ,@y ); + + m_lineGradientMatrix.reset; + + tat.Construct(x ,y ); + + m_lineGradientMatrix.multiply(@tat ); + m_lineGradientMatrix.invert; + + m_lineGradientD1:=0; + +end; + +{ LINEWIDTH } +procedure Agg2D.lineWidth(w : double ); +begin + m_lineWidth:=w; + + m_convStroke.width_(w ); + +end; + +{ LINEWIDTH_ } +function Agg2D.lineWidth_(w : double ) : double; +begin + result:=m_lineWidth; + +end; + +{ LINECAP } +procedure Agg2D.lineCap(cap : LineCap_ ); +begin + m_lineCap:=cap; + + m_convStroke.line_cap_(cap ); + +end; + +{ LINECAP } +function Agg2D.lineCap : LineCap_; +begin + result:=m_lineCap; + +end; + +{ LINEJOIN } +procedure Agg2D.lineJoin(join : LineJoin_ ); +begin + m_lineJoin:=join; + + m_convStroke.line_join_(join ); + +end; + +{ LINEJOIN } +function Agg2D.lineJoin : LineJoin_; +begin + result:=m_lineJoin; + +end; + +{ FILLEVENODD } +procedure Agg2D.fillEvenOdd(evenOddFlag : boolean ); +begin + m_evenOddFlag:=evenOddFlag; + + if evenOddFlag then + m_rasterizer.filling_rule(fill_even_odd ) + else + m_rasterizer.filling_rule(fill_non_zero ); + +end; + +{ FILLEVENODD } +function Agg2D.fillEvenOdd : boolean; +begin + result:=m_evenOddFlag; + +end; + +procedure Agg2D.SetLineStyle(awidth: double; astyle: LineStyle); +begin + LineWidth(awidth); + { dashes and dots are relative to the line width } + m_convDash.remove_all_dashes; + case astyle of + stySolid: + begin + // do nothing here + end; + styDash: + begin + m_convDash.add_dash(3 * awidth, 4 * awidth); + end; + styDot: + begin + m_convDash.add_dash(0.5 * awidth, 3 * awidth); + end; + styDashDot: + begin + m_convDash.add_dash(4 * awidth, 3 * awidth); + m_convDash.add_dash(0.5 * awidth, 4 * awidth); + end; + styDashDotDot: + begin + m_convDash.add_dash(4 * awidth, 2 * awidth); + m_convDash.add_dash(0.5 * awidth, 2 * awidth); + m_convDash.add_dash(0.5 * awidth, 4 * awidth); + end; + end; + // add or remove dash generator from rendering pipeline + if astyle = stySolid then + m_convStroke.set_source(@m_convCurve) + else + m_convStroke.set_source(@m_convDash); +end; + +{ TRANSFORMATIONS } +function Agg2D.transformations : Transformations_; +begin + m_transform.store_to(@result.affineMatrix[0 ] ); + +end; + +{ TRANSFORMATIONS } +procedure Agg2D.transformations(tr : Transformations_ptr ); +begin + m_transform.load_from(@tr.affineMatrix[0 ] ); + + m_convCurve.approximation_scale_ (worldToScreen(1.0 ) * g_approxScale ); + m_convStroke.approximation_scale_(worldToScreen(1.0 ) * g_approxScale ); + +end; + +{ RESETTRANSFORMATIONS } +procedure Agg2D.resetTransformations; +begin + m_transform.reset; + +end; + +{ AFFINE } +procedure Agg2D.affine(tr : Affine_ptr ); +begin + m_transform.multiply(tr ); + + m_convCurve.approximation_scale_ (worldToScreen(1.0 ) * g_approxScale ); + m_convStroke.approximation_scale_(worldToScreen(1.0 ) * g_approxScale ); + +end; + +{ AFFINE } +procedure Agg2D.affine(tr : Transformations_ptr ); +var + ta : trans_affine; + +begin + ta.Construct( + tr.affineMatrix[0 ] ,tr.affineMatrix[1 ] ,tr.affineMatrix[2 ] , + tr.affineMatrix[3 ] ,tr.affineMatrix[4 ] ,tr.affineMatrix[5 ] ); + + affine(Affine_ptr(@ta ) ); + +end; + +{ ROTATE } +procedure Agg2D.rotate(angle : double ); +var + tar : trans_affine_rotation; + +begin + tar.Construct(angle ); + + m_transform.multiply(@tar ); + +end; + +{ SCALE } +procedure Agg2D.scale(sx ,sy : double ); +var + tas : trans_affine_scaling; + +begin + tas.Construct(sx ,sy ); + + m_transform.multiply(@tas ); + + m_convCurve.approximation_scale_ (worldToScreen(1.0 ) * g_approxScale ); + m_convStroke.approximation_scale_(worldToScreen(1.0 ) * g_approxScale ); + +end; + +{ SKEW } +procedure Agg2D.skew(sx ,sy : double ); +var + tas : trans_affine_skewing; + +begin + tas.Construct(sx ,sy ); + + m_transform.multiply(@tas ); + +end; + +{ TRANSLATE } +procedure Agg2D.translate(x ,y : double ); +var + tat : trans_affine_translation; + +begin + tat.Construct(x ,y ); + + m_transform.multiply(@tat ); + +end; + +{ PARALLELOGRAM } +procedure Agg2D.parallelogram(x1 ,y1 ,x2 ,y2 : double; para : double_ptr ); +var + ta : trans_affine; + +begin + ta.Construct(x1 ,y1 ,x2 ,y2 ,parallelo_ptr(para ) ); + + m_transform.multiply(@ta ); + + m_convCurve.approximation_scale_ (worldToScreen(1.0 ) * g_approxScale ); + m_convStroke.approximation_scale_(worldToScreen(1.0 ) * g_approxScale ); + +end; + +{ VIEWPORT } +procedure Agg2D.viewport( + worldX1 ,worldY1 ,worldX2 ,worldY2 , + screenX1 ,screenY1 ,screenX2 ,screenY2 : double; + opt : ViewportOption = XMidYMid ); +var + vp : trans_viewport; + mx : trans_affine; + +begin + vp.Construct; + + case opt of + Anisotropic : + vp.preserve_aspect_ratio(0.0 ,0.0 ,aspect_ratio_stretch ); + + XMinYMin : + vp.preserve_aspect_ratio(0.0 ,0.0 ,aspect_ratio_meet ); + + XMidYMin : + vp.preserve_aspect_ratio(0.5 ,0.0 ,aspect_ratio_meet ); + + XMaxYMin : + vp.preserve_aspect_ratio(1.0 ,0.0 ,aspect_ratio_meet ); + + XMinYMid : + vp.preserve_aspect_ratio(0.0 ,0.5 ,aspect_ratio_meet ); + + XMidYMid : + vp.preserve_aspect_ratio(0.5 ,0.5 ,aspect_ratio_meet ); + + XMaxYMid : + vp.preserve_aspect_ratio(1.0 ,0.5 ,aspect_ratio_meet ); + + XMinYMax : + vp.preserve_aspect_ratio(0.0 ,1.0 ,aspect_ratio_meet ); + + XMidYMax : + vp.preserve_aspect_ratio(0.5 ,1.0 ,aspect_ratio_meet ); + + XMaxYMax : + vp.preserve_aspect_ratio(1.0 ,1.0 ,aspect_ratio_meet ); + + end; + + vp.world_viewport (worldX1 ,worldY1 ,worldX2 ,worldY2 ); + vp.device_viewport(screenX1 ,screenY1 ,screenX2 ,screenY2 ); + + mx.Construct; + + vp.to_affine (@mx ); + m_transform.multiply(@mx ); + + m_convCurve.approximation_scale_ (worldToScreen(1.0 ) * g_approxScale ); + m_convStroke.approximation_scale_(worldToScreen(1.0 ) * g_approxScale ); + +end; + +{ LINE } +procedure Agg2D.line(const x1, y1, x2, y2: double; AFixAlignment: boolean = false); +var + lx1, ly1, lx2, ly2: double; +begin + m_path.remove_all; + + lx1 := x1; + ly1 := y1; + lx2 := x2; + ly2 := y2; + + if AFixAlignment then + begin + AlignPoint(@lx1, @ly1); + AlignPoint(@lx2, @ly2); + end; + + addLine(lx1, ly1, lx2, ly2); + drawPath(StrokeOnly); +end; + +{ TRIANGLE } +procedure Agg2D.triangle(x1 ,y1 ,x2 ,y2 ,x3 ,y3 : double ); +begin + m_path.remove_all; + m_path.move_to(x1 ,y1 ); + m_path.line_to(x2 ,y2 ); + m_path.line_to(x3 ,y3 ); + m_path.close_polygon; + + drawPath(FillAndStroke ); + +end; + +{ RECTANGLE } +procedure Agg2D.rectangle(const x1 ,y1 ,x2 ,y2 : double; AFixAlignment: boolean); +var + lx1, ly1, lx2, ly2: double; +begin + m_path.remove_all; + + lx1 := x1; + ly1 := y1; + lx2 := x2; + ly2 := y2; + + if AFixAlignment then + begin + AlignPoint(@lx1, @ly1); + AlignPoint(@lx2, @ly2); + end; + + m_path.move_to(lx1 ,ly1 ); + m_path.line_to(lx2 ,ly1 ); + m_path.line_to(lx2 ,ly2 ); + m_path.line_to(lx1 ,ly2 ); + m_path.close_polygon; + + drawPath(FillAndStroke ); + +end; + +{ ROUNDEDRECT } +procedure Agg2D.roundedRect(x1 ,y1 ,x2 ,y2 ,r : double ); +var + rc : rounded_rect; + +begin + m_path.remove_all; + rc.Construct(x1 ,y1 ,x2 ,y2 ,r ); + + rc.normalize_radius; + rc.approximation_scale_(worldToScreen(1.0 ) * g_approxScale ); + + m_path.add_path(@rc ,0 ,false ); + + drawPath(FillAndStroke ); + +end; + +{ ROUNDEDRECT } +procedure Agg2D.roundedRect(x1 ,y1 ,x2 ,y2 ,rx ,ry : double ); +var + rc : rounded_rect; + +begin + m_path.remove_all; + rc.Construct; + + rc.rect (x1 ,y1 ,x2 ,y2 ); + rc.radius(rx ,ry ); + rc.normalize_radius; + + m_path.add_path(@rc ,0 ,false ); + + drawPath(FillAndStroke ); + +end; + +{ ROUNDEDRECT } +procedure Agg2D.roundedRect( + x1 ,y1 ,x2 ,y2 , + rxBottom ,ryBottom , + rxTop ,ryTop : double ); +var + rc : rounded_rect; + +begin + m_path.remove_all; + rc.Construct; + + rc.rect (x1 ,y1 ,x2 ,y2 ); + rc.radius(rxBottom ,ryBottom ,rxTop ,ryTop ); + rc.normalize_radius; + + rc.approximation_scale_(worldToScreen(1.0 ) * g_approxScale ); + + m_path.add_path(@rc ,0 ,false ); + + drawPath(FillAndStroke ); + +end; + +{ ELLIPSE } +procedure Agg2D.ellipse(cx ,cy ,rx ,ry : double ); +var + el : bezier_arc; + +begin + m_path.remove_all; + + el.Construct(cx ,cy ,rx ,ry ,0 ,2 * pi ); + + m_path.add_path(@el ,0 ,false ); + m_path.close_polygon; + + drawPath(FillAndStroke ); + +end; + +{ ARC } +procedure Agg2D.arc(cx ,cy ,rx ,ry ,start ,sweep : double ); +var + ar : {bezier_}agg_arc.arc; + +begin + m_path.remove_all; + + ar.Construct(cx ,cy ,rx ,ry ,start ,sweep ,false ); + + m_path.add_path(@ar ,0 ,false ); + + drawPath(StrokeOnly ); + +end; + +{ STAR } +procedure Agg2D.star(cx ,cy ,r1 ,r2 ,startAngle : double; numRays : int ); +var + da ,a ,x ,y : double; + + i : int; + +begin + m_path.remove_all; + + da:=pi / numRays; + a :=startAngle; + + i:=0; + + while i < numRays do + begin + x:=Cos(a ) * r2 + cx; + y:=Sin(a ) * r2 + cy; + + if i <> 0 then + m_path.line_to(x ,y ) + else + m_path.move_to(x ,y ); + + a:=a + da; + + m_path.line_to(Cos(a ) * r1 + cx ,Sin(a ) * r1 + cy ); + + a:=a + da; + + inc(i ); + + end; + + closePolygon; + drawPath(FillAndStroke ); + +end; + +{ CURVE } +procedure Agg2D.curve(x1 ,y1 ,x2 ,y2 ,x3 ,y3 : double ); +begin + m_path.remove_all; + m_path.move_to(x1 ,y1 ); + m_path.curve3 (x2 ,y2 ,x3 ,y3 ); + + drawPath(StrokeOnly ); + +end; + +{ CURVE } +procedure Agg2D.curve(x1 ,y1 ,x2 ,y2 ,x3 ,y3 ,x4 ,y4 : double ); +begin + m_path.remove_all; + m_path.move_to(x1 ,y1 ); + m_path.curve4 (x2 ,y2 ,x3 ,y3 ,x4 ,y4 ); + + drawPath(StrokeOnly ); + +end; + +{ POLYGON } +procedure Agg2D.polygon(xy : double_ptr; numPoints : int ); +begin + m_path.remove_all; + m_path.add_poly(double_2_ptr(xy ) ,numPoints ); + + closePolygon; + drawPath(FillAndStroke ); + +end; + +{ POLYLINE } +procedure Agg2D.polyline(xy : double_ptr; numPoints : int ); +begin + m_path.remove_all; + m_path.add_poly(double_2_ptr(xy ) ,numPoints ); + + drawPath(StrokeOnly ); + +end; + +{ FLIPTEXT } +procedure Agg2D.flipText(flip : boolean ); +begin + {$IFNDEF AGG2D_NO_FONT} + m_fontEngine.flip_y_(flip ); + {$ENDIF} +end; + +{ FONT } +procedure Agg2D.font( + fileName : char_ptr; height : double; + bold : boolean = false; + italic : boolean = false; + ch : FontCacheType = VectorFontCache; + angle : double = 0.0 ); +var + b : int; + +begin + m_textAngle :=angle; + m_fontHeight :=height; + m_fontCacheType:=ch; + +{$IFDEF AGG2D_USE_FREETYPE } + if ch = VectorFontCache then + m_fontEngine.load_font(PChar(fileName ) ,0 ,glyph_ren_outline ) + else + m_fontEngine.load_font(PChar(fileName ) ,0 ,glyph_ren_agg_gray8 ); + + m_fontEngine.hinting_(m_textHints ); + + if ch = VectorFontCache then + m_fontEngine.height_(height * 96 {screen dpi} / 72 {font dpi}) + else + m_fontEngine.height_(worldToScreen(height ) ); +{$ENDIF} +{$IFDEF AGG2D_USE_WINFONTS} + m_fontEngine.hinting_(m_textHints ); + + if bold then + b:=700 + else + b:=400; + + if ch = VectorFontCache then + m_fontEngine.create_font_(PChar(fileName ) ,glyph_ren_outline ,height ,0.0 ,b ,italic ) + else + m_fontEngine.create_font_(PChar(fileName ) ,glyph_ren_agg_gray8 ,worldToScreen(height) ,0.0 ,b ,italic ); +{$ENDIF } + +end; + +{ FONTHEIGHT } +function Agg2D.fontHeight : double; +begin + result:=m_fontHeight; + +end; + +{ TEXTALIGNMENT } +procedure Agg2D.textAlignment(alignX ,alignY : TextAlignment ); +begin + m_textAlignX:=alignX; + m_textAlignY:=alignY; + +end; + +{ TEXTHINTS } +function Agg2D.textHints : boolean; +begin + result:=m_textHints; + +end; + +{ TEXTHINTS } +procedure Agg2D.textHints(hints : boolean ); +begin + m_textHints:=hints; + {$IFNDEF AGG2D_NO_FONT} + m_fontEngine.hinting_(m_textHints ); + {$ENDIF} +end; + +{ TEXTWIDTH } +function Agg2D.textWidth(str : AnsiString ) : double; +{$IFDEF AGG2D_NO_FONT} +begin + Result := 0; +end; +{$ELSE} +var + x ,y : double; + first : boolean; + glyph : glyph_cache_ptr; + str_ : PChar; + +begin + if str = '' then exit(0); + x:=0; + y:=0; + + first:=true; + str_ := PChar(str); + + while str_^ <> #0 do + begin + glyph:=m_fontCacheManager.glyph(int32u(str_^ ) ); + + if glyph <> NIL then + begin + if not first then + m_fontCacheManager.add_kerning(@x ,@y ); + + x:=x + glyph.advance_x; + y:=y + glyph.advance_y; + + first:=false; + + end; + + inc(ptrcomp(str_ ) ); + + end; + + if m_fontCacheType = VectorFontCache then + result:=x + else + result:=screenToWorld(x ); + +end; +{$ENDIF} + +{ TEXT } +procedure Agg2D.text( + x ,y : double; str : AnsiString; + roundOff : boolean = false; + ddx : double = 0.0; + ddy : double = 0.0 ); +{$IFDEF AGG2D_NO_FONT} +begin + +end; +{$ELSE} +var + dx ,dy ,asc ,start_x ,start_y : double; + + glyph : glyph_cache_ptr; + + mtx : trans_affine; + str_ : PChar; + + tat : trans_affine_translation; + tar : trans_affine_rotation; + + tr : conv_transform; + charlen: int; + char_id: int32u; + First: Boolean; + +begin + if Str='' then exit; + + dx:=0.0; + dy:=0.0; + + case m_textAlignX of + AlignCenter : + dx:=-textWidth(str ) * 0.5; + + AlignRight : + dx:=-textWidth(str ); + + end; + + asc :=fontHeight; + glyph:=m_fontCacheManager.glyph(int32u('H' ) ); + + if glyph <> NIL then + asc:=glyph.bounds.y2 - glyph.bounds.y1; + + if m_fontCacheType = RasterFontCache then + asc:=screenToWorld(asc ); + + case m_textAlignY of + AlignCenter : + dy:=-asc * 0.5; + + AlignTop : + dy:=-asc; + + end; + + if m_fontEngine._flip_y then + dy:=-dy; + + mtx.Construct; + + start_x:=x + dx; + start_y:=y + dy; + + if roundOff then + begin + start_x:=Trunc(start_x ); + start_y:=Trunc(start_y ); + end; + + start_x:=start_x + ddx; + start_y:=start_y + ddy; + + tat.Construct(-x ,-y ); + mtx.multiply (@tat ); + + tar.Construct(m_textAngle ); + mtx.multiply (@tar ); + + tat.Construct(x ,y ); + mtx.multiply (@tat ); + + tr.Construct(m_fontCacheManager.path_adaptor ,@mtx ); + + if m_fontCacheType = RasterFontCache then + WorldToScreen(@start_x ,@start_y ); + + str_:=@str[1 ]; + First:=true; + + while str_^ <> #0 do + begin + char_id := UTF8CharToUnicode(str_, charlen); + inc(str_, charlen); + glyph := m_fontCacheManager.glyph(char_id); + + if glyph <> NIL then + begin + if First then + begin + m_fontCacheManager.add_kerning(@x ,@y ); + First:=false; + end; + + m_fontCacheManager.init_embedded_adaptors(glyph ,start_x ,start_y ); + + if glyph.data_type = glyph_data_outline then + begin + m_path.remove_all; + m_path.add_path(@tr ,0 ,false ); + drawPath; + end; + + if glyph.data_type = glyph_data_gray8 then + begin + Render( + m_fontCacheManager.gray8_adaptor , + m_fontCacheManager.gray8_scanline ); + end; + + start_x := start_x + glyph.advance_x; + start_y := start_y + glyph.advance_y; + end; + end; { if glyph <> nil } +end; +{$ENDIF} + +{ RESETPATH } +procedure Agg2D.resetPath; +begin + m_path.remove_all; + m_path.move_to(0 ,0 ); + +end; + +{ MOVETO } +procedure Agg2D.moveTo(x ,y : double ); +begin + m_path.move_to(x ,y ); + +end; + +{ MOVEREL } +procedure Agg2D.moveRel(dx ,dy : double ); +begin + m_path.move_rel(dx ,dy ); + +end; + +{ LINETO } +procedure Agg2D.lineTo(x ,y : double ); +begin + m_path.line_to(x ,y ); + +end; + +{ LINEREL } +procedure Agg2D.lineRel(dx ,dy : double ); +begin + m_path.line_rel(dx ,dy ); + +end; + +{ HORLINETO } +procedure Agg2D.horLineTo(x : double ); +begin + m_path.hline_to(x ); + +end; + +{ HORLINEREL } +procedure Agg2D.horLineRel(dx : double ); +begin + m_path.hline_rel(dx ); + +end; + +{ VERLINETO } +procedure Agg2D.verLineTo(y : double ); +begin + m_path.vline_to(y ); + +end; + +{ VERLINEREL } +procedure Agg2D.verLineRel(dy : double ); +begin + m_path.vline_rel(dy ); + +end; + +{ ARCTO } +procedure Agg2D.arcTo( + rx ,ry ,angle : double; + largeArcFlag ,sweepFlag : boolean; + x ,y : double ); +begin + m_path.arc_to(rx ,ry ,angle ,largeArcFlag ,sweepFlag ,x ,y ); + +end; + +{ ARCREL } +procedure Agg2D.arcRel( + rx ,ry ,angle : double; + largeArcFlag ,sweepFlag : boolean; + dx ,dy : double ); +begin + m_path.arc_rel(rx ,ry ,angle ,largeArcFlag ,sweepFlag ,dx ,dy ); + +end; + +{ QUADRICCURVETO } +procedure Agg2D.quadricCurveTo (xCtrl ,yCtrl ,xTo ,yTo : double ); +begin + m_path.curve3(xCtrl ,yCtrl ,xTo ,yTo ); + +end; + +{ QUADRICCURVEREL } +procedure Agg2D.quadricCurveRel(dxCtrl ,dyCtrl ,dxTo ,dyTo : double ); +begin + m_path.curve3_rel(dxCtrl ,dyCtrl ,dxTo ,dyTo ); + +end; + +{ QUADRICCURVETO } +procedure Agg2D.quadricCurveTo (xTo ,yTo : double ); +begin + m_path.curve3(xTo ,yTo ); + +end; + +{ QUADRICCURVEREL } +procedure Agg2D.quadricCurveRel(dxTo ,dyTo : double ); +begin + m_path.curve3_rel(dxTo ,dyTo ); + +end; + +{ CUBICCURVETO } +procedure Agg2D.cubicCurveTo (xCtrl1 ,yCtrl1 ,xCtrl2 ,yCtrl2 ,xTo ,yTo : double ); +begin + m_path.curve4(xCtrl1 ,yCtrl1 ,xCtrl2 ,yCtrl2 ,xTo ,yTo ); + +end; + +{ CUBICCURVEREL } +procedure Agg2D.cubicCurveRel(dxCtrl1 ,dyCtrl1 ,dxCtrl2 ,dyCtrl2 ,dxTo ,dyTo : double ); +begin + m_path.curve4_rel(dxCtrl1 ,dyCtrl1 ,dxCtrl2 ,dyCtrl2 ,dxTo ,dyTo ); + +end; + +{ CUBICCURVETO } +procedure Agg2D.cubicCurveTo (xCtrl2 ,yCtrl2 ,xTo ,yTo : double ); +begin + m_path.curve4(xCtrl2 ,yCtrl2 ,xTo ,yTo ); + +end; + +{ CUBICCURVEREL } +procedure Agg2D.cubicCurveRel(xCtrl2 ,yCtrl2 ,xTo ,yTo : double ); +begin + m_path.curve4_rel(xCtrl2 ,yCtrl2 ,xTo ,yTo ); + +end; + +{ ADDELLIPSE } +procedure Agg2D.addEllipse(cx ,cy ,rx ,ry : double; dir : Direction ); +var + ar : bezier_arc; + +begin + if dir = CCW then + ar.Construct(cx ,cy ,rx ,ry ,0 ,2 * pi ) + else + ar.Construct(cx ,cy ,rx ,ry ,0 ,-2 * pi ); + + m_path.add_path(@ar ,0 ,false ); + m_path.close_polygon; + +end; + +{ CLOSEPOLYGON } +procedure Agg2D.closePolygon; +begin + m_path.close_polygon; + +end; + +{ DRAWPATH } +procedure Agg2D.drawPath(flag : DrawPathFlag = FillAndStroke ); +begin + m_rasterizer.reset; + + case flag of + FillOnly : + if m_fillColor.a <> 0 then + begin + m_rasterizer.add_path(@m_pathTransform ); + + render(true ); + + end; + + StrokeOnly : + if (m_lineColor.a <> 0 ) and + (m_lineWidth > 0.0 ) then + begin + m_rasterizer.add_path(@m_strokeTransform ); + + render(false ); + + end; + + FillAndStroke : + begin + if m_fillColor.a <> 0 then + begin + m_rasterizer.add_path(@m_pathTransform ); + + render(true ); + + end; + + if (m_lineColor.a <> 0 ) and + (m_lineWidth > 0.0 ) then + begin + m_rasterizer.add_path(@m_strokeTransform ); + + render(false ); + + end; + + end; + + FillWithLineColor : + if m_lineColor.a <> 0 then + begin + m_rasterizer.add_path(@m_pathTransform ); + + render(false ); + + end; + + end; + +end; + +{ DRAWPATHNOTRANSFORM } +procedure Agg2D.drawPathNoTransform(flag : DrawPathFlag = FillAndStroke ); +begin +end; + +{ IMAGEFILTER } +procedure Agg2D.imageFilter(f : ImageFilter_ ); +begin + m_imageFilter:=f; + + case f of + Bilinear : + m_imageFilterLut.calculate(@m_ifBilinear ,true ); + + Hanning : + m_imageFilterLut.calculate(@m_ifHanning ,true ); + + Hermite : + m_imageFilterLut.calculate(@m_ifHermite ,true ); + + Quadric : + m_imageFilterLut.calculate(@m_ifQuadric ,true ); + + Bicubic : + m_imageFilterLut.calculate(@m_ifBicubic ,true ); + + Catrom : + m_imageFilterLut.calculate(@m_ifCatrom ,true ); + + Spline16 : + m_imageFilterLut.calculate(@m_ifSpline16 ,true ); + + Spline36 : + m_imageFilterLut.calculate(@m_ifSpline36 ,true ); + + Blackman144 : + m_imageFilterLut.calculate(@m_ifBlackman144 ,true ); + + end; + +end; + +{ IMAGEFILTER } +function Agg2D.imageFilter : ImageFilter_; +begin + result:=m_imageFilter; + +end; + +{ IMAGERESAMPLE } +procedure Agg2D.imageResample(f : ImageResample_ ); +begin + m_imageResample:=f; + +end; + +{ IMAGERESAMPLE } +function Agg2D.imageResample : ImageResample_; +begin + result:=m_imageResample; + +end; + +{ TRANSFORMIMAGE } +procedure Agg2D.transformImage( + img : Image_ptr; + imgX1 ,imgY1 ,imgX2 ,imgY2 : int; + dstX1 ,dstY1 ,dstX2 ,dstY2 : double ); +var + parall : array[0..5 ] of double; + +begin + resetPath; + moveTo(dstX1 ,dstY1 ); + lineTo(dstX2 ,dstY1 ); + lineTo(dstX2 ,dstY2 ); + lineTo(dstX1 ,dstY2 ); + closePolygon; + + parall[0 ]:=dstX1; + parall[1 ]:=dstY1; + parall[2 ]:=dstX2; + parall[3 ]:=dstY1; + parall[4 ]:=dstX2; + parall[5 ]:=dstY2; + + renderImage(img ,imgX1 ,imgY1 ,imgX2 ,imgY2 ,@parall[0 ] ); + +end; + +{ TRANSFORMIMAGE } +procedure Agg2D.transformImage( + img : Image_ptr; + dstX1 ,dstY1 ,dstX2 ,dstY2 : double ); +var + parall : array[0..5 ] of double; + +begin + resetPath; + moveTo(dstX1 ,dstY1 ); + lineTo(dstX2 ,dstY1 ); + lineTo(dstX2 ,dstY2 ); + lineTo(dstX1 ,dstY2 ); + closePolygon; + + parall[0 ]:=dstX1; + parall[1 ]:=dstY1; + parall[2 ]:=dstX2; + parall[3 ]:=dstY1; + parall[4 ]:=dstX2; + parall[5 ]:=dstY2; + + renderImage(img ,0 ,0 ,img.renBuf._width ,img.renBuf._height ,@parall[0 ] ); + +end; + +{ TRANSFORMIMAGE } +procedure Agg2D.transformImage( + img : Image_ptr; + imgX1 ,imgY1 ,imgX2 ,imgY2 : int; + parallelogram_ : double_ptr ); +begin + resetPath; + + moveTo( + double_ptr(ptrcomp(parallelogram_ ) + 0 * sizeof(double ) )^ , + double_ptr(ptrcomp(parallelogram_ ) + 1 * sizeof(double ) )^ ); + + lineTo( + double_ptr(ptrcomp(parallelogram_ ) + 2 * sizeof(double ) )^ , + double_ptr(ptrcomp(parallelogram_ ) + 3 * sizeof(double ) )^ ); + + lineTo( + double_ptr(ptrcomp(parallelogram_ ) + 4 * sizeof(double ) )^ , + double_ptr(ptrcomp(parallelogram_ ) + 5 * sizeof(double ) )^ ); + + lineTo( + double_ptr(ptrcomp(parallelogram_ ) + 0 * sizeof(double ) )^ + + double_ptr(ptrcomp(parallelogram_ ) + 4 * sizeof(double ) )^ - + double_ptr(ptrcomp(parallelogram_ ) + 2 * sizeof(double ) )^ , + double_ptr(ptrcomp(parallelogram_ ) + 1 * sizeof(double ) )^ + + double_ptr(ptrcomp(parallelogram_ ) + 5 * sizeof(double ) )^ - + double_ptr(ptrcomp(parallelogram_ ) + 3 * sizeof(double ) )^ ); + + closePolygon; + + renderImage(img ,imgX1 ,imgY1 ,imgX2 ,imgY2 ,parallelogram_ ); + +end; + +{ TRANSFORMIMAGE } +procedure Agg2D.transformImage(img : Image_ptr; parallelogram_ : double_ptr ); +begin + resetPath; + + moveTo( + double_ptr(ptrcomp(parallelogram_ ) + 0 * sizeof(double ) )^ , + double_ptr(ptrcomp(parallelogram_ ) + 1 * sizeof(double ) )^ ); + + lineTo( + double_ptr(ptrcomp(parallelogram_ ) + 2 * sizeof(double ) )^ , + double_ptr(ptrcomp(parallelogram_ ) + 3 * sizeof(double ) )^ ); + + lineTo( + double_ptr(ptrcomp(parallelogram_ ) + 4 * sizeof(double ) )^ , + double_ptr(ptrcomp(parallelogram_ ) + 5 * sizeof(double ) )^ ); + + lineTo( + double_ptr(ptrcomp(parallelogram_ ) + 0 * sizeof(double ) )^ + + double_ptr(ptrcomp(parallelogram_ ) + 4 * sizeof(double ) )^ - + double_ptr(ptrcomp(parallelogram_ ) + 2 * sizeof(double ) )^ , + double_ptr(ptrcomp(parallelogram_ ) + 1 * sizeof(double ) )^ + + double_ptr(ptrcomp(parallelogram_ ) + 5 * sizeof(double ) )^ - + double_ptr(ptrcomp(parallelogram_ ) + 3 * sizeof(double ) )^ ); + + closePolygon; + + renderImage(img ,0 ,0 ,img.renBuf._width ,img.renBuf._height ,parallelogram_ ); + +end; + +{ TRANSFORMIMAGEPATH } +procedure Agg2D.transformImagePath( + img : Image_ptr; + imgX1 ,imgY1 ,imgX2 ,imgY2 : int; + dstX1 ,dstY1 ,dstX2 ,dstY2 : double ); +var + parall : array[0..5 ] of double; + +begin + parall[0 ]:=dstX1; + parall[1 ]:=dstY1; + parall[2 ]:=dstX2; + parall[3 ]:=dstY1; + parall[4 ]:=dstX2; + parall[5 ]:=dstY2; + + renderImage(img ,imgX1 ,imgY1 ,imgX2 ,imgY2 ,@parall[0 ] ); + +end; + +{ TRANSFORMIMAGEPATH } +procedure Agg2D.transformImagePath( + img : Image_ptr; + dstX1 ,dstY1 ,dstX2 ,dstY2 : double ); +var + parall : array[0..5 ] of double; + +begin + parall[0 ]:=dstX1; + parall[1 ]:=dstY1; + parall[2 ]:=dstX2; + parall[3 ]:=dstY1; + parall[4 ]:=dstX2; + parall[5 ]:=dstY2; + + renderImage(img ,0 ,0 ,img.renBuf._width ,img.renBuf._height ,@parall[0 ] ); + +end; + +{ TRANSFORMIMAGEPATH } +procedure Agg2D.transformImagePath( + img : Image_ptr; + imgX1 ,imgY1 ,imgX2 ,imgY2 : int; + parallelogram_ : double_ptr ); +begin + renderImage(img ,imgX1 ,imgY1 ,imgX2 ,imgY2 ,parallelogram_ ); + +end; + +{ TRANSFORMIMAGEPATH } +procedure Agg2D.transformImagePath(img : Image_ptr; parallelogram_ : double_ptr ); +begin + renderImage(img ,0 ,0 ,img.renBuf._width ,img.renBuf._height ,parallelogram_ ); + +end; + +procedure Agg2D.Blur(rx, ry: unsigned); +begin + stack_blur_rgba32(@m_pixFormat, rx, ry); +end; + +{ BLENDIMAGE } +procedure Agg2D.blendImage( + img : Image_ptr; + imgX1 ,imgY1 ,imgX2 ,imgY2 : int; + dstX ,dstY : double; alpha : unsigned = 255 ); +var + pixF : pixel_formats; + + r : agg_basics.rect; + +begin + worldToScreen(@dstX ,@dstY ); + pixfmt_rgba32(pixF ,@img.renBuf ); + r.Construct (imgX1 ,imgY1 ,imgX2 ,imgY2 ); + + if m_blendMode = BlendAlpha then + m_renBasePre.blend_from(@pixF ,@r ,Trunc(dstX ) - imgX1 ,Trunc(dstY ) - imgY1 ,alpha ) + else + m_renBaseCompPre.blend_from(@pixF ,@r ,Trunc(dstX ) - imgX1 ,Trunc(dstY ) - imgY1 ,alpha ); + +end; + +{ BLENDIMAGE } +procedure Agg2D.blendImage(img : Image_ptr; dstX ,dstY : double; alpha : unsigned = 255 ); +var + pixF : pixel_formats; + +begin + worldToScreen(@dstX ,@dstY ); + pixfmt_rgba32(pixF ,@img.renBuf ); + + m_renBasePre.blend_from(@pixF ,NIL ,Trunc(dstX ) ,Trunc(dstY ) ,alpha ); + + if m_blendMode = BlendAlpha then + m_renBasePre.blend_from(@pixF ,NIL ,Trunc(dstX ) ,Trunc(dstY ) ,alpha ) + else + m_renBaseCompPre.blend_from(@pixF ,NIL ,Trunc(dstX ) ,Trunc(dstY ) ,alpha ); + +end; + +{ COPYIMAGE } +procedure Agg2D.copyImage( + img : Image_ptr; + imgX1 ,imgY1 ,imgX2 ,imgY2 : int; + dstX ,dstY : double ); +var + r : agg_basics.rect; + +begin + worldToScreen(@dstX ,@dstY ); + r.Construct (imgX1 ,imgY1 ,imgX2 ,imgY2 ); + + m_renBase.copy_from(@img.renBuf ,@r ,Trunc(dstX ) - imgX1 ,Trunc(dstY ) - imgY1 ); + +end; + +{ COPYIMAGE } +procedure Agg2D.copyImage(img : Image_ptr; dstX ,dstY : double ); +begin + worldToScreen(@dstX ,@dstY ); + + m_renBase.copy_from(@img.renBuf ,NIL ,Trunc(dstX ) ,Trunc(dstY ) ); + +end; + +{ RENDER } +procedure Agg2D.render(fillColor_ : boolean ); +begin + if m_blendMode = BlendAlpha then + Agg2DRenderer_render(@self ,@m_renBase ,@m_renSolid ,fillColor_ ) + else + Agg2DRenderer_render(@self ,@m_renBaseComp ,@m_renSolidComp ,fillColor_ ); + +end; + +{ RENDER } +procedure Agg2D.render(ras : FontRasterizer_ptr; sl : FontScanline_ptr ); +begin + if m_blendMode = BlendAlpha then + Agg2DRenderer_render(@self ,@m_renBase ,@m_renSolid ,ras ,sl ) + else + Agg2DRenderer_render(@self ,@m_renBaseComp ,@m_renSolidComp ,ras ,sl ); + +end; + +{ ADDLINE } +procedure Agg2D.addLine(x1 ,y1 ,x2 ,y2 : double ); +begin + m_path.move_to(x1 ,y1 ); + m_path.line_to(x2 ,y2 ); + +end; + +{ UPDATERASTERIZERGAMMA } +procedure Agg2D.updateRasterizerGamma; +begin + m_gammaAgg2D.Construct(m_masterAlpha ,m_antiAliasGamma ); + m_rasterizer.gamma (@m_gammaAgg2D ); + +end; + +{ RENDERIMAGE } +procedure Agg2D.renderImage( + img : Image_ptr; + x1 ,y1 ,x2 ,y2 : int; + parl : double_ptr ); +var + mtx : trans_affine; + + interpolator : span_interpolator_linear; + +begin + mtx.Construct(x1 ,y1 ,x2 ,y2 ,parallelo_ptr(parl ) ); + mtx.multiply (@m_transform ); + mtx.invert; + + m_rasterizer.reset; + m_rasterizer.add_path(@m_pathTransform ); + + interpolator.Construct(@mtx ); + + if m_blendMode = BlendAlpha then + Agg2DRenderer_renderImage(@self ,img ,@m_renBasePre ,@interpolator ) + else + Agg2DRenderer_renderImage(@self ,img ,@m_renBaseCompPre ,@interpolator ); + +end; + +{ CONSTRUCT } +constructor SpanConvImageBlend.Construct(m : BlendMode_; c : Color; p : pixel_formats_ptr ); +begin + m_mode :=m; + m_color:=c; + m_pixel:=p; + +end; + +{ CONVERT } +procedure SpanConvImageBlend.convert(span : aggclr_ptr; x ,y : int; len : unsigned ); +var + l2 ,a : unsigned; + + s2 : Color_ptr; + +begin + if m_mode <> BlendDst then + begin + l2:=len; + s2:=Color_ptr(span ); + + repeat + comp_op_adaptor_clip_to_dst_rgba_pre( + m_pixel , + unsigned(m_mode ) , + int8u_ptr(s2 ) , + m_color.r , + m_color.g , + m_color.b , + base_mask , + cover_full ); + + inc(ptrcomp(s2 ) ,sizeof(Color ) ); + dec(l2 ); + + until l2 = 0; + + end; + + if m_color.a < base_mask then + begin + l2:=len; + s2:=Color_ptr(span ); + a :=m_color.a; + + repeat + s2.r:=(s2.r * a ) shr base_shift; + s2.g:=(s2.g * a ) shr base_shift; + s2.b:=(s2.b * a ) shr base_shift; + s2.a:=(s2.a * a ) shr base_shift; + + inc(ptrcomp(s2 ) ,sizeof(Color ) ); + dec(l2 ); + + until l2 = 0; + + end; + +end; + +{ PI } +function pi : double; +begin + result:=agg_basics.pi; + +end; + +{ DEG2RAD } +function deg2Rad(v : double ) : double; +begin + result:=v * agg_basics.pi / 180.0; + +end; + +{ RAD2DEG } +function rad2Deg(v : double ) : double; +begin + result:=v * 180.0 / agg_basics.pi; + +end; + +{ OPERATOR_IS_EQUAL } +function operator_is_equal(c1 ,c2 : Color_ptr ) : boolean; +begin + result:= + (c1.r = c2.r ) and + (c1.g = c2.g ) and + (c1.b = c2.b ) and + (c1.a = c2.a ); + +end; + +{ OPERATOR_IS_NOT_EQUAL } +function operator_is_not_equal(c1 ,c2 : Color_ptr ) : boolean; +begin + result:=not operator_is_equal(c1 ,c2 ); + +end; + +{ AGG2DRENDERER_RENDER } +procedure Agg2DRenderer_render( + gr : Agg2D_ptr; + renBase : renderer_base_ptr; + renSolid : renderer_scanline_aa_solid_ptr; + fillColor_ : boolean ); +var + span : span_gradient; + ren : renderer_scanline_aa; + clr : aggclr; + +begin + if (fillColor_ and + (gr.m_fillGradientFlag = Linear ) ) or + (not fillColor_ and + (gr.m_lineGradientFlag = Linear ) ) then + if fillColor_ then + begin + span.Construct( + @gr.m_allocator , + @gr.m_fillGradientInterpolator , + @gr.m_linearGradientFunction , + @gr.m_fillGradient , + gr.m_fillGradientD1 , + gr.m_fillGradientD2 ); + + ren.Construct (renBase ,@span ); + render_scanlines(@gr.m_rasterizer ,@gr.m_scanline ,@ren ); + + end + else + begin + span.Construct( + @gr.m_allocator , + @gr.m_lineGradientInterpolator , + @gr.m_linearGradientFunction , + @gr.m_lineGradient , + gr.m_lineGradientD1 , + gr.m_lineGradientD2 ); + + ren.Construct (renBase ,@span ); + render_scanlines(@gr.m_rasterizer ,@gr.m_scanline ,@ren ); + + end + else + if (fillColor_ and + (gr.m_fillGradientFlag = Radial ) ) or + (not fillColor_ and + (gr.m_lineGradientFlag = Radial ) ) then + if fillColor_ then + begin + span.Construct( + @gr.m_allocator , + @gr.m_fillGradientInterpolator , + @gr.m_radialGradientFunction , + @gr.m_fillGradient , + gr.m_fillGradientD1 , + gr.m_fillGradientD2 ); + + ren.Construct (renBase ,@span ); + render_scanlines(@gr.m_rasterizer ,@gr.m_scanline ,@ren ); + + end + else + begin + span.Construct( + @gr.m_allocator , + @gr.m_lineGradientInterpolator , + @gr.m_radialGradientFunction , + @gr.m_lineGradient , + gr.m_lineGradientD1 , + gr.m_lineGradientD2 ); + + ren.Construct (renBase ,@span ); + render_scanlines(@gr.m_rasterizer ,@gr.m_scanline ,@ren ); + + end + else + begin + if fillColor_ then + clr.Construct(gr.m_fillColor ) + else + clr.Construct(gr.m_lineColor ); + + renSolid.color_ (@clr ); + render_scanlines(@gr.m_rasterizer ,@gr.m_scanline ,renSolid ); + + end; + +end; + +{ AGG2DRENDERER_RENDER } +procedure Agg2DRenderer_render( + gr : Agg2D_ptr; + renBase : renderer_base_ptr; + renSolid : renderer_scanline_aa_solid_ptr; + ras : gray8_adaptor_type_ptr; + sl : gray8_scanline_type_ptr ); +var + span : span_gradient; + ren : renderer_scanline_aa; + clr : aggclr; + +begin + if gr.m_fillGradientFlag = Linear then + begin + span.Construct( + @gr.m_allocator , + @gr.m_fillGradientInterpolator , + @gr.m_linearGradientFunction , + @gr.m_fillGradient , + gr.m_fillGradientD1 , + gr.m_fillGradientD2 ); + + ren.Construct (renBase ,@span ); + render_scanlines(ras ,sl ,@ren ); + + end + else + if gr.m_fillGradientFlag = Radial then + begin + span.Construct( + @gr.m_allocator , + @gr.m_fillGradientInterpolator , + @gr.m_radialGradientFunction , + @gr.m_fillGradient , + gr.m_fillGradientD1 , + gr.m_fillGradientD2 ); + + ren.Construct (renBase ,@span ); + render_scanlines(ras ,sl ,@ren ); + + end + else + begin + clr.Construct (gr.m_fillColor ); + renSolid.color_ (@clr ); + render_scanlines(ras ,sl ,renSolid ); + + end; + +end; + +{ AGG2DRENDERER_RENDERIMAGE } +procedure Agg2DRenderer_renderImage( + gr : Agg2D_ptr; + img : Image_ptr; + renBase : renderer_base_ptr; + interpolator : span_interpolator_linear_ptr ); +var + blend : SpanConvImageBlend; + + si : span_image_filter_rgba; + sg : span_image_filter_rgba_nn; + sb : span_image_filter_rgba_bilinear; + s2 : span_image_filter_rgba_2x2; + sa : span_image_resample_rgba_affine; + sc : span_converter; + ri : renderer_scanline_aa; + + clr : aggclr; + + resample : boolean; + + sx ,sy : double; + +begin + blend.Construct(gr.m_imageBlendMode ,gr.m_imageBlendColor ,@gr.m_pixFormatCompPre ); + + if gr.m_imageFilter = NoFilter then + begin + clr.ConstrInt(0 ,0 ,0 ,0 ); + sg.Construct (@gr.m_allocator ,@img.renBuf ,@clr ,interpolator ,rgba_order ); + sc.Construct (@sg ,@blend ); + ri.Construct (renBase ,@sc ); + + render_scanlines(@gr.m_rasterizer ,@gr.m_scanline ,@ri ); + + end + else + begin + resample:=gr.m_imageResample = ResampleAlways; + + if gr.m_imageResample = ResampleOnZoomOut then + begin + interpolator._transformer.scaling_abs(@sx ,@sy ); + + if (sx > 1.125 ) or + (sy > 1.125 ) then + resample:=true; + + end; + + if resample then + begin + clr.ConstrInt(0 ,0 ,0 ,0 ); + sa.Construct( + @gr.m_allocator , + @img.renBuf , + @clr , + interpolator , + @gr.m_imageFilterLut , + rgba_order ); + + sc.Construct(@sa ,@blend ); + ri.Construct(renBase ,@sc ); + + render_scanlines(@gr.m_rasterizer ,@gr.m_scanline ,@ri ); + + end + else + if gr.m_imageFilter = Bilinear then + begin + clr.ConstrInt(0 ,0 ,0 ,0 ); + sb.Construct( + @gr.m_allocator , + @img.renBuf , + @clr , + interpolator , + rgba_order ); + + sc.Construct(@sb ,@blend ); + ri.Construct(renBase ,@sc ); + + render_scanlines(@gr.m_rasterizer ,@gr.m_scanline ,@ri ); + + end + else + if gr.m_imageFilterLut.diameter = 2 then + begin + clr.ConstrInt(0 ,0 ,0 ,0 ); + s2.Construct( + @gr.m_allocator , + @img.renBuf , + @clr , + interpolator, + @gr.m_imageFilterLut , + rgba_order ); + + sc.Construct(@s2 ,@blend ); + ri.Construct(renBase ,@sc ); + + render_scanlines(@gr.m_rasterizer ,@gr.m_scanline ,@ri ); + + end + else + begin + clr.ConstrInt(0 ,0 ,0 ,0 ); + si.Construct( + @gr.m_allocator , + @img.renBuf , + @clr , + interpolator , + @gr.m_imageFilterLut , + rgba_order ); + + sc.Construct(@si ,@blend ); + ri.Construct(renBase ,@sc ); + + render_scanlines(@gr.m_rasterizer ,@gr.m_scanline ,@ri ); + + end; + + end; + +end; + +{ AGG2DUSESFREETYPE } +function Agg2DUsesFreeType : boolean; +begin +{$IFDEF AGG2D_USE_FREETYPE } + result:=true; +{$ELSE } + result:=false; +{$ENDIF } + +end; + +function Agg2DUsesWin32TrueType: boolean; +begin +{$IFDEF AGG2D_USE_WINFONTS } + result:=true; +{$ELSE } + result:=false; +{$ENDIF } +end; + +end. + From 998d80277ee02e7796d8519bd2db39d6e815885f Mon Sep 17 00:00:00 2001 From: James Richters Date: Fri, 16 Jun 2017 14:18:11 -0400 Subject: [PATCH 3/7] Initial modifications - red and blue channels are reversed (need to fix) --- src/corelib/render/software/agg_2D_RGB565.pas | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/corelib/render/software/agg_2D_RGB565.pas b/src/corelib/render/software/agg_2D_RGB565.pas index 1e09657d0..f3ff011f3 100644 --- a/src/corelib/render/software/agg_2D_RGB565.pas +++ b/src/corelib/render/software/agg_2D_RGB565.pas @@ -15,7 +15,7 @@ // warranty, and with no claim as to its suitability for any purpose. // -unit agg_2D ; +unit agg_2D_RGB565 ; {$I agg_mode.inc } @@ -68,6 +68,7 @@ interface agg_font_engine , agg_font_cache_manager , agg_pixfmt , + agg_pixfmt_rgb_packed , agg_pixfmt_rgba , agg_color , agg_math_stroke , @@ -338,7 +339,7 @@ Transformations_ = record m_ifBlackman144 : image_filter_blackman144; public - constructor Construct; + constructor Construct(pixfmt:define_pixfmt); destructor Destruct; // Setup @@ -781,13 +782,13 @@ function Agg2DRasterizerGamma.func_operator_gamma(x : double ) : double; end; { CONSTRUCT } -constructor Agg2D.Construct; +constructor Agg2D.Construct(pixfmt:define_pixfmt); begin m_rbuf.Construct; - pixfmt_rgba32 (m_pixFormat ,@m_rbuf ); + pixfmt (m_pixFormat ,@m_rbuf ); pixfmt_custom_blend_rgba(m_pixFormatComp ,@m_rbuf ,@comp_op_adaptor_rgba ,rgba_order ); - pixfmt_rgba32 (m_pixFormatPre ,@m_rbuf ); + pixfmt (m_pixFormatPre ,@m_rbuf ); pixfmt_custom_blend_rgba(m_pixFormatCompPre ,@m_rbuf ,@comp_op_adaptor_rgba ,rgba_order ); m_renBase.Construct (@m_pixFormat ); From 7c1ed4251d72d91fe1105fd763769c7bac9bd3f7 Mon Sep 17 00:00:00 2001 From: James Richters Date: Fri, 16 Jun 2017 15:09:04 -0400 Subject: [PATCH 4/7] Use compiler Directive {AGG2D_USE_RGB565} with agg_2D.pas unit instead of maintianing 2 units --- src/corelib/render/software/agg_2D.pas | 25 +- src/corelib/render/software/agg_2D_RGB565.pas | 3482 ----------------- 2 files changed, 24 insertions(+), 3483 deletions(-) delete mode 100644 src/corelib/render/software/agg_2D_RGB565.pas diff --git a/src/corelib/render/software/agg_2D.pas b/src/corelib/render/software/agg_2D.pas index 1e09657d0..d88628762 100644 --- a/src/corelib/render/software/agg_2D.pas +++ b/src/corelib/render/software/agg_2D.pas @@ -40,6 +40,13 @@ interface {$UNDEF AGG2D_USE_WINFONTS} {$ENDIF} +{ With this define you can switch to an experimental version that is more + compatible with freepascal console graphics units such as Graph and ptcgraph + + ToDo: red and blue are reversed and need to be fixed } + +{.$Define AGG2D_USE_RGB565} + uses agg_basics , agg_array , @@ -68,6 +75,9 @@ interface agg_font_engine , agg_font_cache_manager , agg_pixfmt , +{$IFDEF AGG2D_USE_RGB565 } + agg_pixfmt_rgb_packed , +{$ENDIF } agg_pixfmt_rgba , agg_color , agg_math_stroke , @@ -338,7 +348,11 @@ Transformations_ = record m_ifBlackman144 : image_filter_blackman144; public +{$IFDEF AGG2D_USE_RGB565 } + constructor Construct(pixfmt:define_pixfmt); +{$ELSE } constructor Construct; +{$ENDIF } destructor Destruct; // Setup @@ -781,13 +795,22 @@ function Agg2DRasterizerGamma.func_operator_gamma(x : double ) : double; end; { CONSTRUCT } +{$IFDEF AGG2D_USE_RGB565 } +constructor Agg2D.Construct(pixfmt:define_pixfmt); +{$ELSE } constructor Agg2D.Construct; +{$ENDIF } begin m_rbuf.Construct; +{$IFDEF AGG2D_USE_RGB565 } + pixfmt (m_pixFormat ,@m_rbuf ); + pixfmt (m_pixFormatPre ,@m_rbuf ); +{$ELSE } pixfmt_rgba32 (m_pixFormat ,@m_rbuf ); - pixfmt_custom_blend_rgba(m_pixFormatComp ,@m_rbuf ,@comp_op_adaptor_rgba ,rgba_order ); pixfmt_rgba32 (m_pixFormatPre ,@m_rbuf ); +{$ENDIF } + pixfmt_custom_blend_rgba(m_pixFormatComp ,@m_rbuf ,@comp_op_adaptor_rgba ,rgba_order ); pixfmt_custom_blend_rgba(m_pixFormatCompPre ,@m_rbuf ,@comp_op_adaptor_rgba ,rgba_order ); m_renBase.Construct (@m_pixFormat ); diff --git a/src/corelib/render/software/agg_2D_RGB565.pas b/src/corelib/render/software/agg_2D_RGB565.pas deleted file mode 100644 index f3ff011f3..000000000 --- a/src/corelib/render/software/agg_2D_RGB565.pas +++ /dev/null @@ -1,3482 +0,0 @@ -//---------------------------------------------------------------------------- -// Agg2D - Version 1.0 -// Based on Anti-Grain Geometry -// Copyright (C) 2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Agg2D - Version 1.0 Release Milano 3 (AggPas 2.4 RM3) -// Pascal Port By: Milan Marusinec alias Milano -// milan@marusinec.sk -// http://www.aggpas.org -// Copyright (c) 2007 - 2008 -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all copies. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// - -unit agg_2D_RGB565 ; - -{$I agg_mode.inc } - -{.$Define CStackDebug} - -interface - - -{ With this define you can switch use of FreeType or Win32 TrueType font - engine. - - NOTE: - The FreeType font engine is recommended, even under Windows - simply - because it has more functionality and generates better looking text. If - enabled under Windows, your application will require the freetype.dll - though. The freetype.dll is included in the fpGUI repository for your - convenience. } - -{.$DEFINE AGG2D_USE_FREETYPE } - -{$IFDEF AGG2D_USE_FREETYPE} - {$UNDEF AGG2D_USE_WINFONTS} -{$ENDIF} - -uses - agg_basics , - agg_array , - agg_trans_affine , - agg_trans_viewport , - agg_path_storage , - agg_conv_stroke , - agg_conv_transform , - agg_conv_curve , - agg_conv_dash , - agg_rendering_buffer , - agg_renderer_base , - agg_renderer_scanline , - agg_span_gradient , - agg_span_image_filter_rgba , - agg_span_image_resample_rgba , - agg_span_converter , - agg_span_interpolator_linear , - agg_span_allocator , - agg_rasterizer_scanline_aa , - agg_gamma_functions , - agg_scanline_u , - agg_arc , - agg_bezier_arc , - agg_rounded_rect , - agg_font_engine , - agg_font_cache_manager , - agg_pixfmt , - agg_pixfmt_rgb_packed , - agg_pixfmt_rgba , - agg_color , - agg_math_stroke , - agg_image_filters , - agg_vertex_source , - agg_render_scanlines , - agg_blur, - -{$IFDEF AGG2D_USE_FREETYPE } - agg_font_freetype , -{$ENDIF } -{$IFDEF AGG2D_USE_WINFONTS} - agg_font_win32_tt , - Windows , -{$ENDIF } - - Math ; - -{ GLOBAL VARIABLES & CONSTANTS } -const -// LineJoin - JoinMiter = miter_join; - JoinRound = round_join; - JoinBevel = bevel_join; - -// LineCap - CapButt = butt_cap; - CapSquare = square_cap; - CapRound = round_cap; - -// TextAlignment - AlignLeft = 0; - AlignRight = 1; - AlignCenter = 2; - AlignTop = AlignRight; - AlignBottom = AlignLeft; - -// BlendMode - BlendAlpha = end_of_comp_op_e; - BlendClear = comp_op_clear; - BlendSrc = comp_op_src; - BlendDst = comp_op_dst; - BlendSrcOver = comp_op_src_over; - BlendDstOver = comp_op_dst_over; - BlendSrcIn = comp_op_src_in; - BlendDstIn = comp_op_dst_in; - BlendSrcOut = comp_op_src_out; - BlendDstOut = comp_op_dst_out; - BlendSrcAtop = comp_op_src_atop; - BlendDstAtop = comp_op_dst_atop; - BlendXor = comp_op_xor; - BlendAdd = comp_op_plus; - BlendSub = comp_op_minus; - BlendMultiply = comp_op_multiply; - BlendScreen = comp_op_screen; - BlendOverlay = comp_op_overlay; - BlendDarken = comp_op_darken; - BlendLighten = comp_op_lighten; - BlendColorDodge = comp_op_color_dodge; - BlendColorBurn = comp_op_color_burn; - BlendHardLight = comp_op_hard_light; - BlendSoftLight = comp_op_soft_light; - BlendDifference = comp_op_difference; - BlendExclusion = comp_op_exclusion; - BlendContrast = comp_op_contrast; - -{ TYPES DEFINITION } -type - Color_ptr = ^Color; - Color = rgba8; - - Rect_ = agg_basics.rect; - RectD = agg_basics.rect_d; - - Affine = trans_affine; - Affine_ptr = trans_affine_ptr; - - FontRasterizer = gray8_adaptor_type; - FontRasterizer_ptr = gray8_adaptor_type_ptr; - - FontScanline = gray8_scanline_type; - FontScanline_ptr = gray8_scanline_type_ptr; - -{$IFDEF AGG2D_USE_FREETYPE } - FontEngine = font_engine_freetype_int32; -{$ENDIF } -{$IFDEF AGG2D_USE_WINFONTS} - FontEngine = font_engine_win32_tt_int32; -{$ENDIF } - - Gradient = (Solid ,Linear ,Radial ); - Direction = (CW, CCW ); - - LineJoin_ = int; - LineCap_ = int; - BlendMode_ = comp_op_e; - - TextAlignment = int; - - DrawPathFlag = ( - FillOnly , - StrokeOnly , - FillAndStroke , - FillWithLineColor ); - - ViewportOption = ( - Anisotropic , - XMinYMin , - XMidYMin , - XMaxYMin , - XMinYMid , - XMidYMid , - XMaxYMid , - XMinYMax , - XMidYMax , - XMaxYMax ); - - ImageFilter_ = ( - NoFilter , - Bilinear , - Hanning , - Hermite , - Quadric , - Bicubic , - Catrom , - Spline16 , - Spline36 , - Blackman144 ); - - ImageResample_ = ( - NoResample , - ResampleAlways , - ResampleOnZoomOut ); - - FontCacheType = ( - RasterFontCache , - VectorFontCache ); - - LineStyle = ( - stySolid, - styDash, - styDot, - styDashDot, - styDashDotDot ); - - Transformations_ptr = ^Transformations_; - Transformations_ = record - affineMatrix : array[0..5 ] of double; - - end; - - Image_ptr = ^Image; - Image = object - renBuf : rendering_buffer; - - constructor Construct; overload; - constructor Construct(buf : int8u_ptr; width_ ,height_ : unsigned; stride : int ); overload; - destructor Destruct; - - procedure attach(buf : int8u_ptr; width_ ,height_ : unsigned; stride : int ); - - function width : int; - function height : int; - - procedure premultiply; - procedure demultiply; - - end; - - Agg2DRasterizerGamma = object(vertex_source ) - m_alpha : gamma_multiply; - m_gamma : gamma_power; - - constructor Construct(alpha ,gamma : double ); - - function func_operator_gamma(x : double ) : double; virtual; - - end; - - Agg2D_ptr = ^Agg2D; - Agg2D = object - private - m_rbuf : rendering_buffer; - - m_pixFormat ,m_pixFormatComp ,m_pixFormatPre ,m_pixFormatCompPre : pixel_formats; - m_renBase ,m_renBaseComp ,m_renBasePre ,m_renBaseCompPre : renderer_base; - - m_renSolid ,m_renSolidComp : renderer_scanline_aa_solid; - - m_allocator : span_allocator; - m_clipBox : RectD; - - m_blendMode ,m_imageBlendMode : BlendMode_; - - m_imageBlendColor : Color; - - m_scanline : scanline_u8; - m_rasterizer : rasterizer_scanline_aa; - - m_masterAlpha ,m_antiAliasGamma : double; - - m_fillColor ,m_lineColor : Color; - - m_fillGradient ,m_lineGradient : pod_auto_array; - - m_lineCap : LineCap_; - m_lineJoin : LineJoin_; - - m_fillGradientFlag ,m_lineGradientFlag : Gradient; - - m_fillGradientMatrix ,m_lineGradientMatrix : trans_affine; - - m_fillGradientD1 , - m_lineGradientD1 , - m_fillGradientD2 , - m_lineGradientD2 , - m_textAngle : double; - m_textAlignX , - m_textAlignY : TextAlignment; - m_textHints : boolean; - m_fontHeight , - m_fontAscent , - m_fontDescent : double; - m_fontCacheType : FontCacheType; - - m_imageFilter : ImageFilter_; - m_imageResample : ImageResample_; - m_imageFilterLut : image_filter_lut; - - m_fillGradientInterpolator , - m_lineGradientInterpolator : span_interpolator_linear; - - m_linearGradientFunction : gradient_x; - m_radialGradientFunction : gradient_circle; - - m_lineWidth : double; - m_evenOddFlag : boolean; - - m_path : path_storage; - m_transform : trans_affine; - - m_convCurve : conv_curve; - m_convStroke : conv_stroke; - m_convDash: conv_dash; - - m_pathTransform ,m_strokeTransform : conv_transform; - - {$IFNDEF AGG2D_NO_FONT} - m_fontEngine : FontEngine; - m_fontCacheManager : font_cache_manager; - {$ENDIF} - {$IFDEF AGG2D_USE_WINFONTS } - m_fontDC : HDC; - {$ENDIF } - - // Other Pascal-specific members - m_gammaNone : gamma_none; - m_gammaAgg2D : Agg2DRasterizerGamma; - - m_ifBilinear : image_filter_bilinear; - m_ifHanning : image_filter_hanning; - m_ifHermite : image_filter_hermite; - m_ifQuadric : image_filter_quadric; - m_ifBicubic : image_filter_bicubic; - m_ifCatrom : image_filter_catrom; - m_ifSpline16 : image_filter_spline16; - m_ifSpline36 : image_filter_spline36; - m_ifBlackman144 : image_filter_blackman144; - - public - constructor Construct(pixfmt:define_pixfmt); - destructor Destruct; - - // Setup - procedure attach(buf : int8u_ptr; width_ ,height_ : unsigned; stride : int ); overload; - procedure attach(img : Image_ptr ); overload; - - procedure clipBox(x1 ,y1 ,x2 ,y2 : double ); overload; - function clipBox : RectD; overload; - - procedure clearAll(c : Color ); overload; - procedure clearAll(r ,g ,b : unsigned; a : unsigned = 255 ); overload; - procedure FillAll(c: Color); overload; - procedure FillAll(r, g, b: byte; a: byte = 255); overload; - - procedure clearClipBox(c : Color ); overload; - procedure clearClipBox(r ,g ,b : unsigned; a : unsigned = 255 ); overload; - - // Conversions - procedure worldToScreen(x ,y : double_ptr ); overload; - procedure screenToWorld(x ,y : double_ptr ); overload; - function worldToScreen(scalar : double ) : double; overload; - function screenToWorld(scalar : double ) : double; overload; - - procedure alignPoint(x ,y : double_ptr ); - - function inBox(worldX ,worldY : double ) : boolean; - - // General Attributes - procedure blendMode(m : BlendMode_ ); overload; - function blendMode : BlendMode_; overload; - - procedure imageBlendMode(m : BlendMode_ ); overload; - function imageBlendMode : BlendMode_; overload; - - procedure imageBlendColor(c : Color ); overload; - procedure imageBlendColor(r ,g ,b : unsigned; a : unsigned = 255 ); overload; - function imageBlendColor : Color; overload; - - procedure masterAlpha(a : double ); overload; - function masterAlpha : double; overload; - - procedure antiAliasGamma(g : double ); overload; - function antiAliasGamma : double; overload; - - procedure fillColor(c : Color ); overload; - procedure fillColor(r ,g ,b : unsigned; a : unsigned = 255 ); overload; - procedure noFill; - - procedure lineColor(c : Color ); overload; - procedure lineColor(r ,g ,b : unsigned; a : unsigned = 255 ); overload; - procedure noLine; - - function fillColor : Color; overload; - function lineColor : Color; overload; - - procedure fillLinearGradient(x1 ,y1 ,x2 ,y2 : double; c1 ,c2 : Color; profile : double = 1.0 ); - procedure lineLinearGradient(x1 ,y1 ,x2 ,y2 : double; c1 ,c2 : Color; profile : double = 1.0 ); - - procedure fillRadialGradient(x ,y ,r : double; c1 ,c2 : Color; profile : double = 1.0 ); overload; - procedure lineRadialGradient(x ,y ,r : double; c1 ,c2 : Color; profile : double = 1.0 ); overload; - - procedure fillRadialGradient(x ,y ,r : double; c1 ,c2 ,c3 : Color ); overload; - procedure lineRadialGradient(x ,y ,r : double; c1 ,c2 ,c3 : Color ); overload; - - procedure fillRadialGradient(x ,y ,r : double ); overload; - procedure lineRadialGradient(x ,y ,r : double ); overload; - - procedure lineWidth (w : double ); - function lineWidth_(w : double ) : double; - - procedure lineCap(cap : LineCap_ ); overload; - function lineCap : LineCap_; overload; - - procedure lineJoin(join : LineJoin_ ); overload; - function lineJoin : LineJoin_; overload; - - procedure fillEvenOdd(evenOddFlag : boolean ); overload; - function fillEvenOdd : boolean; overload; - - procedure SetLineStyle(awidth: double; astyle: LineStyle); - - // Transformations - function transformations : Transformations_; overload; - procedure transformations(tr : Transformations_ptr ); overload; - procedure resetTransformations; - - procedure affine(tr : Affine_ptr ); overload; - procedure affine(tr : Transformations_ptr ); overload; - - procedure rotate (angle : double ); - procedure scale (sx ,sy : double ); - procedure skew (sx ,sy : double ); - procedure translate(x ,y : double ); - - procedure parallelogram(x1 ,y1 ,x2 ,y2 : double; para : double_ptr ); - - procedure viewport( - worldX1 ,worldY1 ,worldX2 ,worldY2 , - screenX1 ,screenY1 ,screenX2 ,screenY2 : double; - opt : ViewportOption = XMidYMid ); - - // Basic Shapes - procedure line (const x1 ,y1 ,x2 ,y2 : double; AFixAlignment: boolean = false ); - procedure triangle (x1 ,y1 ,x2 ,y2 ,x3 ,y3 : double ); - procedure rectangle(const x1 ,y1 ,x2 ,y2 : double; AFixAlignment: boolean = false); - - procedure roundedRect(x1 ,y1 ,x2 ,y2 ,r : double ); overload; - procedure roundedRect(x1 ,y1 ,x2 ,y2 ,rx ,ry : double ); overload; - procedure roundedRect( - x1 ,y1 ,x2 ,y2 , - rxBottom ,ryBottom , - rxTop ,ryTop : double ); overload; - - procedure ellipse(cx ,cy ,rx ,ry : double ); - - procedure arc (cx ,cy ,rx ,ry ,start ,sweep : double ); - procedure star(cx ,cy ,r1 ,r2 ,startAngle : double; numRays : int ); - - procedure curve(x1 ,y1 ,x2 ,y2 ,x3 ,y3 : double ); overload; - procedure curve(x1 ,y1 ,x2 ,y2 ,x3 ,y3 ,x4 ,y4 : double ); overload; - - procedure polygon (xy : double_ptr; numPoints : int ); - procedure polyline(xy : double_ptr; numPoints : int ); - - // Text - procedure flipText(flip : boolean ); - - procedure font( - fileName : char_ptr; height : double; - bold : boolean = false; - italic : boolean = false; - ch : FontCacheType = VectorFontCache; - angle : double = 0.0 ); - - function fontHeight : double; - - procedure textAlignment(alignX ,alignY : TextAlignment ); - - function textHints : boolean; overload; - procedure textHints(hints : boolean ); overload; - function textWidth(str : AnsiString ) : double; - - procedure text( - x ,y : double; str : AnsiString; - roundOff : boolean = false; - ddx : double = 0.0; - ddy : double = 0.0 ); - - // Path commands - procedure resetPath; - - procedure moveTo (x ,y : double ); - procedure moveRel(dx ,dy : double ); - - procedure lineTo (x ,y : double ); - procedure lineRel(dx ,dy : double ); - - procedure horLineTo (x : double ); - procedure horLineRel(dx : double ); - - procedure verLineTo (y : double ); - procedure verLineRel(dy : double ); - - procedure arcTo( - rx ,ry ,angle : double; - largeArcFlag ,sweepFlag : boolean; - x ,y : double ); - - procedure arcRel( - rx ,ry ,angle : double; - largeArcFlag ,sweepFlag : boolean; - dx ,dy : double ); - - procedure quadricCurveTo (xCtrl ,yCtrl ,xTo ,yTo : double ); overload; - procedure quadricCurveRel(dxCtrl ,dyCtrl ,dxTo ,dyTo : double ); overload; - procedure quadricCurveTo (xTo ,yTo : double ); overload; - procedure quadricCurveRel(dxTo ,dyTo : double ); overload; - - procedure cubicCurveTo (xCtrl1 ,yCtrl1 ,xCtrl2 ,yCtrl2 ,xTo ,yTo : double ); overload; - procedure cubicCurveRel(dxCtrl1 ,dyCtrl1 ,dxCtrl2 ,dyCtrl2 ,dxTo ,dyTo : double ); overload; - procedure cubicCurveTo (xCtrl2 ,yCtrl2 ,xTo ,yTo : double ); overload; - procedure cubicCurveRel(xCtrl2 ,yCtrl2 ,xTo ,yTo : double ); overload; - - procedure addEllipse(cx ,cy ,rx ,ry : double; dir : Direction ); - procedure closePolygon; - - procedure drawPath(flag : DrawPathFlag = FillAndStroke ); - - procedure drawPathNoTransform(flag : DrawPathFlag = FillAndStroke ); - - // Image Transformations - procedure imageFilter(f : ImageFilter_ ); overload; - function imageFilter : ImageFilter_; overload; - - procedure imageResample(f : ImageResample_ ); overload; - function imageResample : ImageResample_; overload; - - procedure transformImage( - img : Image_ptr; - imgX1 ,imgY1 ,imgX2 ,imgY2 : int; - dstX1 ,dstY1 ,dstX2 ,dstY2 : double ); overload; - - procedure transformImage( - img : Image_ptr; - dstX1 ,dstY1 ,dstX2 ,dstY2 : double ); overload; - - procedure transformImage( - img : Image_ptr; - imgX1 ,imgY1 ,imgX2 ,imgY2 : int; - parallelogram_ : double_ptr ); overload; - - procedure transformImage(img : Image_ptr; parallelogram_ : double_ptr ); overload; - - procedure transformImagePath( - img : Image_ptr; - imgX1 ,imgY1 ,imgX2 ,imgY2 : int; - dstX1 ,dstY1 ,dstX2 ,dstY2 : double ); overload; - - procedure transformImagePath( - img : Image_ptr; - dstX1 ,dstY1 ,dstX2 ,dstY2 : double ); overload; - - procedure transformImagePath( - img : Image_ptr; - imgX1 ,imgY1 ,imgX2 ,imgY2 : int; - parallelogram_ : double_ptr ); overload; - - procedure transformImagePath(img : Image_ptr; parallelogram_ : double_ptr ); overload; - procedure Blur(rx ,ry : unsigned); - - // Image Blending (no transformations available) - procedure blendImage( - img : Image_ptr; - imgX1 ,imgY1 ,imgX2 ,imgY2 : int; - dstX ,dstY : double; alpha : unsigned = 255 ); overload; - - procedure blendImage(img : Image_ptr; dstX ,dstY : double; alpha : unsigned = 255 ); overload; - - // Copy image directly, together with alpha-channel - procedure copyImage( - img : Image_ptr; - imgX1 ,imgY1 ,imgX2 ,imgY2 : int; - dstX ,dstY : double ); overload; - - procedure copyImage(img : Image_ptr; dstX ,dstY : double ); overload; - - private - procedure render(fillColor_ : boolean ); overload; - procedure render(ras : FontRasterizer_ptr; sl : FontScanline_ptr ); overload; - - procedure addLine(x1 ,y1 ,x2 ,y2 : double ); - procedure updateRasterizerGamma; - procedure renderImage( - img : Image_ptr; - x1 ,y1 ,x2 ,y2 : int; - parl : double_ptr ); - - end; - - SpanConvImageBlend_ptr = ^SpanConvImageBlend; - SpanConvImageBlend = object(span_convertor ) - private - m_mode : BlendMode_; - m_color : Color; - m_pixel : pixel_formats_ptr; // m_pixFormatCompPre - - public - constructor Construct(m : BlendMode_; c : Color; p : pixel_formats_ptr ); - - procedure convert(span : aggclr_ptr; x ,y : int; len : unsigned ); virtual; - - end; - -{ GLOBAL PROCEDURES } -// Auxiliary - function pi : double; - function deg2Rad(v : double ) : double; - function rad2Deg(v : double ) : double; - - function operator_is_equal (c1 ,c2 : Color_ptr ) : boolean; - function operator_is_not_equal(c1 ,c2 : Color_ptr ) : boolean; - - procedure Agg2DRenderer_render( - gr : Agg2D_ptr; - renBase : renderer_base_ptr; - renSolid : renderer_scanline_aa_solid_ptr; - fillColor_ : boolean ); overload; - - procedure Agg2DRenderer_render( - gr : Agg2D_ptr; - renBase : renderer_base_ptr; - renSolid : renderer_scanline_aa_solid_ptr; - ras : gray8_adaptor_type_ptr; - sl : gray8_scanline_type_ptr ); overload; - - procedure Agg2DRenderer_renderImage( - gr : Agg2D_ptr; - img : Image_ptr; - renBase : renderer_base_ptr; - interpolator : span_interpolator_linear_ptr ); - - function Agg2DUsesFreeType : boolean; - function Agg2DUsesWin32TrueType : boolean; - -IMPLEMENTATION - -{ LOCAL VARIABLES & CONSTANTS } -var - g_approxScale : double = 2.0; - -{ copied from the "fpg_stringutils" unit. } -function UTF8CharToUnicode(p: PChar; out CharLen: longint): Cardinal; -begin - if p=nil then begin - Result:=0; - CharLen:=0; - exit; - end; - if ord(p^) < $C0 then begin - // regular single byte character (#0 is a normal char, this is pascal ;) - end - else if ((ord(p^) and $E0) = $C0) then begin - // could be double byte character - if (ord(p[1]) and $C0) = $80 then begin - Result:=((ord(p^) and $1F) shl 6) - or (ord(p[1]) and $3F); - CharLen:=2; - exit; - end; - end - else if ((ord(p^) and $F0) = $E0) then begin - // could be triple byte character - if ((ord(p[1]) and $C0) = $80) - and ((ord(p[2]) and $C0) = $80) then begin - Result:=((ord(p^) and $1F) shl 12) - or ((ord(p[1]) and $3F) shl 6) - or (ord(p[2]) and $3F); - CharLen:=3; - exit; - end; - end - else if ((ord(p^) and $F8) = $F0) then begin - // could be 4 byte character - if ((ord(p[1]) and $C0) = $80) - and ((ord(p[2]) and $C0) = $80) - and ((ord(p[3]) and $C0) = $80) then begin - Result:=((ord(p^) and $0F) shl 18) - or ((ord(p[1]) and $3F) shl 12) - or ((ord(p[2]) and $3F) shl 6) - or (ord(p[3]) and $3F); - CharLen:=4; - exit; - end; - end - else begin - // invalid character - end; - Result:=ord(p^); - CharLen:=1; -end; - -{ UNIT IMPLEMENTATION } -{ CONSTRUCT } -constructor Image.Construct; -begin -end; - -{ CONSTRUCT } -constructor Image.Construct(buf : int8u_ptr; width_ ,height_ : unsigned; stride : int ); -begin - renBuf.Construct(buf ,width_ ,height_ ,stride ); - -end; - -{ DESTRUCT } -destructor Image.Destruct; -begin - renBuf.Destruct; - -end; - -{ ATTACH } -procedure Image.attach(buf : int8u_ptr; width_ ,height_ : unsigned; stride : int ); -begin - renBuf.attach(buf ,width_ ,height_ ,stride ); - -end; - -{ WIDTH } -function Image.width : int; -begin - result:=renBuf._width; - -end; - -{ HEIGHT } -function Image.height : int; -begin - result:=renBuf._height; - -end; - -{ PREMULTIPLY } -procedure Image.premultiply; -var - pixf : pixel_formats; - -begin -{ pixfmt_rgba32(pixf ,@renBuf ); - - pixf.premultiply; } - -end; - -{ DEMULTIPLY } -procedure Image.demultiply; -var - pixf : pixel_formats; - -begin -{ pixfmt_rgba32(pixf ,@renBuf ); - - pixf.demultiply; } - -end; - -{ CONSTRUCT } -constructor Agg2DRasterizerGamma.Construct(alpha ,gamma : double ); -begin - m_alpha.Construct(alpha ); - m_gamma.Construct(gamma ); - -end; - -{ FUNC_OPERATOR_GAMMA } -function Agg2DRasterizerGamma.func_operator_gamma(x : double ) : double; -begin - result:=m_alpha.func_operator_gamma(m_gamma.func_operator_gamma(x ) ); - -end; - -{ CONSTRUCT } -constructor Agg2D.Construct(pixfmt:define_pixfmt); -begin - m_rbuf.Construct; - - pixfmt (m_pixFormat ,@m_rbuf ); - pixfmt_custom_blend_rgba(m_pixFormatComp ,@m_rbuf ,@comp_op_adaptor_rgba ,rgba_order ); - pixfmt (m_pixFormatPre ,@m_rbuf ); - pixfmt_custom_blend_rgba(m_pixFormatCompPre ,@m_rbuf ,@comp_op_adaptor_rgba ,rgba_order ); - - m_renBase.Construct (@m_pixFormat ); - m_renBaseComp.Construct (@m_pixFormatComp ); - m_renBasePre.Construct (@m_pixFormatPre ); - m_renBaseCompPre.Construct(@m_pixFormatCompPre ); - - m_renSolid.Construct (@m_renBase ); - m_renSolidComp.Construct(@m_renBaseComp ); - - m_allocator.Construct; - m_clipBox.Construct(0 ,0 ,0 ,0 ); - - m_blendMode :=BlendAlpha; - m_imageBlendMode:=BlendDst; - - m_imageBlendColor.Construct(0 ,0 ,0 ); - - m_scanline.Construct; - m_rasterizer.Construct; - - m_masterAlpha :=1.0; - m_antiAliasGamma:=1.0; - - m_fillColor.Construct(255 ,255 ,255 ); - m_lineColor.Construct(0 ,0 ,0 ); - - m_fillGradient.Construct(256 ,sizeof(aggclr ) ); - m_lineGradient.Construct(256 ,sizeof(aggclr ) ); - - m_lineCap :=CapRound; - m_lineJoin:=JoinRound; - - m_fillGradientFlag:=Solid; - m_lineGradientFlag:=Solid; - - m_fillGradientMatrix.Construct; - m_lineGradientMatrix.Construct; - - m_fillGradientD1:=0.0; - m_lineGradientD1:=0.0; - m_fillGradientD2:=100.0; - m_lineGradientD2:=100.0; - - m_textAngle :=0.0; - m_textAlignX :=AlignLeft; - m_textAlignY :=AlignBottom; - m_textHints :=true; - m_fontHeight :=0.0; - m_fontAscent :=0.0; - m_fontDescent:=0.0; - - m_fontCacheType:=RasterFontCache; - m_imageFilter :=Bilinear; - m_imageResample:=NoResample; - - m_gammaNone.Construct; - - m_ifBilinear.Construct; - m_ifHanning.Construct; - m_ifHermite.Construct; - m_ifQuadric.Construct; - m_ifBicubic.Construct; - m_ifCatrom.Construct; - m_ifSpline16.Construct; - m_ifSpline36.Construct; - m_ifBlackman144.Construct; - - m_imageFilterLut.Construct(@m_ifBilinear ,true ); - - m_linearGradientFunction.Construct; - m_radialGradientFunction.Construct; - - m_fillGradientInterpolator.Construct(@m_fillGradientMatrix ); - m_lineGradientInterpolator.Construct(@m_lineGradientMatrix ); - - m_lineWidth :=1; - m_evenOddFlag:=false; - - m_path.Construct; - m_transform.Construct; - - m_convCurve.Construct(@m_path); - m_convDash.Construct(@m_convCurve); - m_convStroke.Construct(@m_convDash); - - m_pathTransform.Construct (@m_convCurve ,@m_transform ); - m_strokeTransform.Construct(@m_convStroke ,@m_transform ); - - SetLineStyle(m_lineWidth, stySolid); - -{$IFDEF AGG2D_USE_FREETYPE } - m_fontEngine.Construct; -{$ENDIF } -{$IFDEF AGG2D_USE_WINFONTS} - m_fontDC:=GetDC(0 ); - m_fontEngine.Construct(m_fontDC ); -{$ENDIF } -{$IFNDEF AGG2D_NO_FONT} - m_fontCacheManager.Construct(@m_fontEngine ); -{$ENDIF} - - lineCap (m_lineCap ); - lineJoin(m_lineJoin ); - -end; - -{ DESTRUCT } -destructor Agg2D.Destruct; -begin - m_rbuf.Destruct; - m_allocator.Destruct; - - m_scanline.Destruct; - m_rasterizer.Destruct; - - m_fillGradient.Destruct; - m_lineGradient.Destruct; - - m_imageFilterLut.Destruct; - - m_convStroke.Destruct; - m_convDash.Destruct; - m_convCurve.Destruct; - - m_path.Destruct; - -{$IFNDEF AGG2D_NO_FONT} - m_fontEngine.Destruct; - m_fontCacheManager.Destruct; -{$ENDIF} -{$IFDEF AGG2D_USE_WINFONTS } - ReleaseDC(0 ,m_fontDC ); -{$ENDIF } -end; - -{ ATTACH } -procedure Agg2D.attach(buf : int8u_ptr; width_ ,height_ : unsigned; stride : int ); -begin - m_rbuf.attach(buf ,width_ ,height_ ,stride ); - - m_renBase.reset_clipping (true ); - m_renBaseComp.reset_clipping (true ); - m_renBasePre.reset_clipping (true ); - m_renBaseCompPre.reset_clipping(true ); - - resetTransformations; - - lineWidth(1.0 ); - lineColor(0 ,0 ,0 ); - fillColor(255 ,255 ,255 ); - - textAlignment(AlignLeft ,AlignBottom ); - - clipBox (0 ,0 ,width_ ,height_ ); - lineCap (CapRound ); - lineJoin(JoinRound ); - flipText(false ); - - imageFilter (Bilinear ); - imageResample(NoResample ); - - m_masterAlpha :=1.0; - m_antiAliasGamma:=1.0; - - m_rasterizer.gamma(@m_gammaNone ); - - m_blendMode:=BlendAlpha; - -end; - -{ ATTACH } -procedure Agg2D.attach(img : Image_ptr ); -begin - attach(img.renBuf._buf ,img.renBuf._width ,img.renBuf._height ,img.renBuf._stride ); - -end; - -{ CLIPBOX } -procedure Agg2D.clipBox(x1 ,y1 ,x2 ,y2 : double ); -var - rx1 ,ry1 ,rx2 ,ry2 : int; - -begin - m_clipBox.Construct(x1 ,y1 ,x2 ,y2 ); - - rx1:=Trunc(x1 ); - ry1:=Trunc(y1 ); - rx2:=Trunc(x2 ); - ry2:=Trunc(y2 ); - - m_renBase.clip_box_ (rx1 ,ry1 ,rx2 ,ry2 ); - m_renBaseComp.clip_box_ (rx1 ,ry1 ,rx2 ,ry2 ); - m_renBasePre.clip_box_ (rx1 ,ry1 ,rx2 ,ry2 ); - m_renBaseCompPre.clip_box_(rx1 ,ry1 ,rx2 ,ry2 ); - - m_rasterizer.clip_box(x1 ,y1 ,x2 ,y2 ); - -end; - -{ CLIPBOX } -function Agg2D.clipBox : RectD; -begin - result:=m_clipBox; - -end; - -{ CLEARALL } -procedure Agg2D.clearAll(c : Color ); -var - clr : aggclr; - -begin - clr.Construct (c ); - m_renBase.clear(@clr ); - -end; - -{ CLEARALL } -procedure Agg2D.clearAll(r ,g ,b : unsigned; a : unsigned = 255 ); -var - clr : Color; - -begin - clr.Construct(r ,g ,b ,a ); - clearAll (clr ); - -end; - -procedure Agg2D.FillAll(c: Color); -var - clr: aggclr; -begin - clr.Construct (c ); - m_renBase.fill(@clr ); -end; - -procedure Agg2D.FillAll(r, g, b: byte; a: byte); -var - clr: Color; -begin - clr.Construct(r, g, b, a); - FillAll(clr); -end; - -{ CLEARCLIPBOX } -procedure Agg2D.clearClipBox(c : Color ); -var - clr : aggclr; - -begin - clr.Construct(c ); - - m_renBase.copy_bar(0 ,0 ,m_renBase.width ,m_renBase.height ,@clr ); - -end; - -{ CLEARCLIPBOX } -procedure Agg2D.clearClipBox(r ,g ,b : unsigned; a : unsigned = 255 ); -var - clr : Color; - -begin - clr.Construct(r ,g ,b ,a ); - clearClipBox (clr ); - -end; - -{ WORLDTOSCREEN } -procedure Agg2D.worldToScreen(x ,y : double_ptr ); -begin - m_transform.transform(@m_transform ,x ,y ); - -end; - -{ SCREENTOWORLD } -procedure Agg2D.screenToWorld(x ,y : double_ptr ); -begin - m_transform.inverse_transform(@m_transform ,x ,y ); - -end; - -{ WORLDTOSCREEN } -function Agg2D.worldToScreen(scalar : double ) : double; -var - x1 ,y1 ,x2 ,y2 : double; - -begin - x1:=0; - y1:=0; - x2:=scalar; - y2:=scalar; - - worldToScreen(@x1 ,@y1 ); - worldToScreen(@x2 ,@y2 ); - - result:=Sqrt((x2 - x1 ) * (x2 - x1 ) + (y2 - y1 ) * (y2 - y1 ) ) * 0.7071068; - -end; - -{ SCREENTOWORLD } -function Agg2D.screenToWorld(scalar : double ) : double; -var - x1 ,y1 ,x2 ,y2 : double; - -begin - x1:=0; - y1:=0; - x2:=scalar; - y2:=scalar; - - screenToWorld(@x1 ,@y1 ); - screenToWorld(@x2 ,@y2 ); - - result:=Sqrt((x2 - x1 ) * (x2 - x1 ) + (y2 - y1 ) * (y2 - y1 ) ) * 0.7071068; - -end; - -{ ALIGNPOINT } -procedure Agg2D.alignPoint(x ,y : double_ptr ); -begin - worldToScreen(x ,y ); - - x^:=Floor(x^ ) + 0.5; - y^:=Floor(y^ ) + 0.5; - - screenToWorld(x ,y ); - -end; - -{ INBOX } -function Agg2D.inBox(worldX ,worldY : double ) : boolean; -begin - worldToScreen(@worldX ,@worldY ); - - result:=m_renBase.inbox(Trunc(worldX ) ,Trunc(worldY ) ); - -end; - -{ BLENDMODE } -procedure Agg2D.blendMode(m : BlendMode_ ); -begin - m_blendMode:=m; - - m_pixFormatComp.comp_op_ (unsigned(m ) ); - m_pixFormatCompPre.comp_op_(unsigned(m ) ); - -end; - -{ BLENDMODE } -function Agg2D.blendMode : BlendMode_; -begin - result:=m_blendMode; - -end; - -{ IMAGEBLENDMODE } -procedure Agg2D.imageBlendMode(m : BlendMode_ ); -begin - m_imageBlendMode:=m; - -end; - -{ IMAGEBLENDMODE } -function Agg2D.imageBlendMode : BlendMode_; -begin - result:=m_imageBlendMode; - -end; - -{ IMAGEBLENDCOLOR } -procedure Agg2D.imageBlendColor(c : Color ); -begin - m_imageBlendColor:=c; - -end; - -{ IMAGEBLENDCOLOR } -procedure Agg2D.imageBlendColor(r ,g ,b : unsigned; a : unsigned = 255 ); -var - clr : Color; - -begin - clr.Construct (r ,g ,b ,a ); - imageBlendColor(clr ); - -end; - -{ IMAGEBLENDCOLOR } -function Agg2D.imageBlendColor : Color; -begin - result:=m_imageBlendColor; - -end; - -{ MASTERALPHA } -procedure Agg2D.masterAlpha(a : double ); -begin - m_masterAlpha:=a; - - updateRasterizerGamma; - -end; - -{ MASTERALPHA } -function Agg2D.masterAlpha : double; -begin - result:=m_masterAlpha; - -end; - -{ ANTIALIASGAMMA } -procedure Agg2D.antiAliasGamma(g : double ); -begin - m_antiAliasGamma:=g; - - updateRasterizerGamma; - -end; - -{ ANTIALIASGAMMA } -function Agg2D.antiAliasGamma : double; -begin - result:=m_antiAliasGamma; - -end; - -{ FILLCOLOR } -procedure Agg2D.fillColor(c : Color ); -begin - m_fillColor :=c; - m_fillGradientFlag:=Solid; - -end; - -{ FILLCOLOR } -procedure Agg2D.fillColor(r ,g ,b : unsigned; a : unsigned = 255 ); -var - clr : Color; - -begin - clr.Construct(r ,g ,b ,a ); - fillColor (clr ); - -end; - -{ NOFILL } -procedure Agg2D.noFill; -var - clr : Color; - -begin - clr.Construct(0 ,0 ,0 ,0 ); - fillColor (clr ); - -end; - -{ LINECOLOR } -procedure Agg2D.lineColor(c : Color ); -begin - m_lineColor :=c; - m_lineGradientFlag:=Solid; - -end; - -{ LINECOLOR } -procedure Agg2D.lineColor(r ,g ,b : unsigned; a : unsigned = 255 ); -var - clr : Color; - -begin - clr.Construct(r ,g ,b ,a ); - lineColor (clr ); - -end; - -{ NOLINE } -procedure Agg2D.noLine; -var - clr : Color; - -begin - clr.Construct(0 ,0 ,0 ,0 ); - lineColor (clr ); - -end; - -{ FILLCOLOR } -function Agg2D.fillColor : Color; -begin - result:=m_fillColor; - -end; - -{ LINECOLOR } -function Agg2D.lineColor : Color; -begin - result:=m_lineColor; - -end; - -{ FILLLINEARGRADIENT } -procedure Agg2D.fillLinearGradient(x1 ,y1 ,x2 ,y2 : double; c1 ,c2 : Color; profile : double = 1.0 ); -var - i ,startGradient ,endGradient : int; - - k ,angle : double; - - c : Color; - - clr : aggclr; - tar : trans_affine_rotation; - tat : trans_affine_translation; - -begin - startGradient:=128 - Trunc(profile * 127.0 ); - endGradient :=128 + Trunc(profile * 127.0 ); - - if endGradient <= startGradient then - endGradient:=startGradient + 1; - - k:=1.0 / (endGradient - startGradient ); - i:=0; - - while i < startGradient do - begin - clr.Construct(c1 ); - - move(clr ,m_fillGradient.array_operator(i )^ ,sizeof(aggclr ) ); - inc (i ); - - end; - - while i < endGradient do - begin - c:=c1.gradient(c2 ,(i - startGradient ) * k ); - - clr.Construct(c ); - - move(clr ,m_fillGradient.array_operator(i )^ ,sizeof(aggclr ) ); - inc (i ); - - end; - - while i < 256 do - begin - clr.Construct(c2 ); - - move(clr ,m_fillGradient.array_operator(i )^ ,sizeof(aggclr ) ); - inc (i ); - - end; - - angle:=ArcTan2(y2 - y1 ,x2 - x1 ); - - m_fillGradientMatrix.reset; - - tar.Construct(angle ); - - m_fillGradientMatrix.multiply(@tar ); - - tat.Construct(x1 ,y1 ); - - m_fillGradientMatrix.multiply(@tat ); - m_fillGradientMatrix.multiply(@m_transform ); - m_fillGradientMatrix.invert; - - m_fillGradientD1 :=0.0; - m_fillGradientD2 :=Sqrt((x2 - x1 ) * (x2 - x1 ) + (y2 - y1 ) * (y2 - y1 ) ); - m_fillGradientFlag:=Linear; - - m_fillColor.Construct(0 ,0 ,0 ); // Set some real color - -end; - -{ LINELINEARGRADIENT } -procedure Agg2D.lineLinearGradient(x1 ,y1 ,x2 ,y2 : double; c1 ,c2 : Color; profile : double = 1.0 ); -var - i ,startGradient ,endGradient : int; - - k ,angle : double; - - c : Color; - - clr : aggclr; - tar : trans_affine_rotation; - tat : trans_affine_translation; - -begin - startGradient:=128 - Trunc(profile * 128.0 ); - endGradient :=128 + Trunc(profile * 128.0 ); - - if endGradient <= startGradient then - endGradient:=startGradient + 1; - - k:=1.0 / (endGradient - startGradient ); - i:=0; - - while i < startGradient do - begin - clr.Construct(c1 ); - - move(clr ,m_lineGradient.array_operator(i )^ ,sizeof(aggclr ) ); - inc (i ); - - end; - - while i < endGradient do - begin - c:=c1.gradient(c2 ,(i - startGradient) * k ); - - clr.Construct(c ); - - move(clr ,m_lineGradient.array_operator(i )^ ,sizeof(aggclr ) ); - inc (i ); - - end; - - while i < 256 do - begin - clr.Construct(c2 ); - - move(clr ,m_lineGradient.array_operator(i )^ ,sizeof(aggclr ) ); - inc (i ); - - end; - - angle:=ArcTan2(y2 - y1 ,x2 - x1 ); - - m_lineGradientMatrix.reset; - - tar.Construct(angle ); - - m_lineGradientMatrix.multiply(@tar ); - - tat.Construct(x1 ,y1 ); - - m_lineGradientMatrix.multiply(@tat ); - m_lineGradientMatrix.multiply(@m_transform ); {!} - m_lineGradientMatrix.invert; - - m_lineGradientD1 :=0.0; - m_lineGradientD2 :=Sqrt((x2 - x1 ) * (x2 - x1 ) + (y2 - y1 ) * (y2 - y1 ) ); - m_lineGradientFlag:=Linear; - - m_lineColor.Construct(0 ,0 ,0 ); // Set some real color - -end; - -{ FILLRADIALGRADIENT } -procedure Agg2D.fillRadialGradient(x ,y ,r : double; c1 ,c2 : Color; profile : double = 1.0 ); -var - i ,startGradient ,endGradient : int; - - k : double; - c : Color; - - clr : aggclr; - tat : trans_affine_translation; - -begin - startGradient:=128 - Trunc(profile * 127.0 ); - endGradient :=128 + Trunc(profile * 127.0 ); - - if endGradient <= startGradient then - endGradient:=startGradient + 1; - - k:=1.0 / (endGradient - startGradient ); - i:=0; - - while i < startGradient do - begin - clr.Construct(c1 ); - - move(clr ,m_fillGradient.array_operator(i )^ ,sizeof(aggclr ) ); - inc (i ); - - end; - - while i < endGradient do - begin - c:=c1.gradient(c2 ,(i - startGradient ) * k ); - - clr.Construct(c ); - - move(clr ,m_fillGradient.array_operator(i )^ ,sizeof(aggclr ) ); - inc (i ); - - end; - - while i < 256 do - begin - clr.Construct(c2 ); - - move(clr ,m_fillGradient.array_operator(i )^ ,sizeof(aggclr ) ); - inc (i ); - - end; - - m_fillGradientD2:=worldToScreen(r ); - - worldToScreen(@x ,@y ); - - m_fillGradientMatrix.reset; - - tat.Construct(x ,y ); - - m_fillGradientMatrix.multiply(@tat ); - m_fillGradientMatrix.invert; - - m_fillGradientD1 :=0; - m_fillGradientFlag:=Radial; - - m_fillColor.Construct(0 ,0 ,0 ); // Set some real color - -end; - -{ LINERADIALGRADIENT } -procedure Agg2D.lineRadialGradient(x ,y ,r : double; c1 ,c2 : Color; profile : double = 1.0 ); -var - i ,startGradient ,endGradient : int; - - k : double; - c : Color; - - clr : aggclr; - tat : trans_affine_translation; - -begin - startGradient:=128 - Trunc(profile * 128.0 ); - endGradient :=128 + Trunc(profile * 128.0 ); - - if endGradient <= startGradient then - endGradient:=startGradient + 1; - - k:=1.0 / (endGradient - startGradient ); - i:=0; - - while i < startGradient do - begin - clr.Construct(c1 ); - - move(clr ,m_lineGradient.array_operator(i )^ ,sizeof(aggclr ) ); - inc (i ); - - end; - - while i < endGradient do - begin - c:=c1.gradient(c2 ,(i - startGradient ) * k ); - - clr.Construct(c ); - - move(clr ,m_lineGradient.array_operator(i )^ ,sizeof(aggclr ) ); - inc (i ); - - end; - - while i < 256 do - begin - clr.Construct(c2 ); - - move(clr ,m_lineGradient.array_operator(i )^ ,sizeof(aggclr ) ); - inc (i ); - - end; - - m_lineGradientD2:=worldToScreen(r ); - - worldToScreen(@x ,@y ); - - m_lineGradientMatrix.reset; - - tat.Construct(x ,y ); - - m_lineGradientMatrix.multiply(@tat ); - m_lineGradientMatrix.invert; - - m_lineGradientD1 :=0; - m_lineGradientFlag:=Radial; - - m_lineColor.Construct(0 ,0 ,0 ); // Set some real color - -end; - -{ FILLRADIALGRADIENT } -procedure Agg2D.fillRadialGradient(x ,y ,r : double; c1 ,c2 ,c3 : Color ); -var - i : int; - c : Color; - - clr : aggclr; - tat : trans_affine_translation; - -begin - i:=0; - - while i < 128 do - begin - c:=c1.gradient(c2 ,i / 127.0 ); - - clr.Construct(c ); - - move(clr ,m_fillGradient.array_operator(i )^ ,sizeof(aggclr ) ); - inc (i ); - - end; - - while i < 256 do - begin - c:=c2.gradient(c3 ,(i - 128 ) / 127.0 ); - - clr.Construct(c ); - - move(clr ,m_fillGradient.array_operator(i )^ ,sizeof(aggclr ) ); - inc (i ); - - end; - - m_fillGradientD2:=worldToScreen(r ); - - worldToScreen(@x ,@y ); - - m_fillGradientMatrix.reset; - - tat.Construct(x ,y ); - - m_fillGradientMatrix.multiply(@tat ); - m_fillGradientMatrix.invert; - - m_fillGradientD1 :=0; - m_fillGradientFlag:=Radial; - - m_fillColor.Construct(0 ,0 ,0 ); // Set some real color - -end; - -{ LINERADIALGRADIENT } -procedure Agg2D.lineRadialGradient(x ,y ,r : double; c1 ,c2 ,c3 : Color ); -var - i : int; - c : Color; - - clr : aggclr; - tat : trans_affine_translation; - -begin - i:=0; - - while i < 128 do - begin - c:=c1.gradient(c2 ,i / 127.0 ); - - clr.Construct(c ); - - move(clr ,m_lineGradient.array_operator(i )^ ,sizeof(aggclr ) ); - inc (i ); - - end; - - while i < 256 do - begin - c:=c2.gradient(c3 ,(i - 128 ) / 127.0 ); - - clr.Construct(c ); - - move(clr ,m_lineGradient.array_operator(i )^ ,sizeof(aggclr ) ); - inc (i ); - - end; - - m_lineGradientD2:=worldToScreen(r ); - - worldToScreen(@x ,@y ); - - m_lineGradientMatrix.reset; - - tat.Construct(x ,y ); - - m_lineGradientMatrix.multiply(@tat ); - m_lineGradientMatrix.invert; - - m_lineGradientD1 :=0; - m_lineGradientFlag:=Radial; - - m_lineColor.Construct(0 ,0 ,0 ); // Set some real color - -end; - -{ FILLRADIALGRADIENT } -procedure Agg2D.fillRadialGradient(x ,y ,r : double ); -var - tat : trans_affine_translation; - -begin - m_fillGradientD2:=worldToScreen(r ); - - worldToScreen(@x ,@y ); - - m_fillGradientMatrix.reset; - - tat.Construct(x ,y ); - - m_fillGradientMatrix.multiply(@tat ); - m_fillGradientMatrix.invert; - - m_fillGradientD1:=0; - -end; - -{ LINERADIALGRADIENT } -procedure Agg2D.lineRadialGradient(x ,y ,r : double ); -var - tat : trans_affine_translation; - -begin - m_lineGradientD2:=worldToScreen(r ); - - worldToScreen(@x ,@y ); - - m_lineGradientMatrix.reset; - - tat.Construct(x ,y ); - - m_lineGradientMatrix.multiply(@tat ); - m_lineGradientMatrix.invert; - - m_lineGradientD1:=0; - -end; - -{ LINEWIDTH } -procedure Agg2D.lineWidth(w : double ); -begin - m_lineWidth:=w; - - m_convStroke.width_(w ); - -end; - -{ LINEWIDTH_ } -function Agg2D.lineWidth_(w : double ) : double; -begin - result:=m_lineWidth; - -end; - -{ LINECAP } -procedure Agg2D.lineCap(cap : LineCap_ ); -begin - m_lineCap:=cap; - - m_convStroke.line_cap_(cap ); - -end; - -{ LINECAP } -function Agg2D.lineCap : LineCap_; -begin - result:=m_lineCap; - -end; - -{ LINEJOIN } -procedure Agg2D.lineJoin(join : LineJoin_ ); -begin - m_lineJoin:=join; - - m_convStroke.line_join_(join ); - -end; - -{ LINEJOIN } -function Agg2D.lineJoin : LineJoin_; -begin - result:=m_lineJoin; - -end; - -{ FILLEVENODD } -procedure Agg2D.fillEvenOdd(evenOddFlag : boolean ); -begin - m_evenOddFlag:=evenOddFlag; - - if evenOddFlag then - m_rasterizer.filling_rule(fill_even_odd ) - else - m_rasterizer.filling_rule(fill_non_zero ); - -end; - -{ FILLEVENODD } -function Agg2D.fillEvenOdd : boolean; -begin - result:=m_evenOddFlag; - -end; - -procedure Agg2D.SetLineStyle(awidth: double; astyle: LineStyle); -begin - LineWidth(awidth); - { dashes and dots are relative to the line width } - m_convDash.remove_all_dashes; - case astyle of - stySolid: - begin - // do nothing here - end; - styDash: - begin - m_convDash.add_dash(3 * awidth, 4 * awidth); - end; - styDot: - begin - m_convDash.add_dash(0.5 * awidth, 3 * awidth); - end; - styDashDot: - begin - m_convDash.add_dash(4 * awidth, 3 * awidth); - m_convDash.add_dash(0.5 * awidth, 4 * awidth); - end; - styDashDotDot: - begin - m_convDash.add_dash(4 * awidth, 2 * awidth); - m_convDash.add_dash(0.5 * awidth, 2 * awidth); - m_convDash.add_dash(0.5 * awidth, 4 * awidth); - end; - end; - // add or remove dash generator from rendering pipeline - if astyle = stySolid then - m_convStroke.set_source(@m_convCurve) - else - m_convStroke.set_source(@m_convDash); -end; - -{ TRANSFORMATIONS } -function Agg2D.transformations : Transformations_; -begin - m_transform.store_to(@result.affineMatrix[0 ] ); - -end; - -{ TRANSFORMATIONS } -procedure Agg2D.transformations(tr : Transformations_ptr ); -begin - m_transform.load_from(@tr.affineMatrix[0 ] ); - - m_convCurve.approximation_scale_ (worldToScreen(1.0 ) * g_approxScale ); - m_convStroke.approximation_scale_(worldToScreen(1.0 ) * g_approxScale ); - -end; - -{ RESETTRANSFORMATIONS } -procedure Agg2D.resetTransformations; -begin - m_transform.reset; - -end; - -{ AFFINE } -procedure Agg2D.affine(tr : Affine_ptr ); -begin - m_transform.multiply(tr ); - - m_convCurve.approximation_scale_ (worldToScreen(1.0 ) * g_approxScale ); - m_convStroke.approximation_scale_(worldToScreen(1.0 ) * g_approxScale ); - -end; - -{ AFFINE } -procedure Agg2D.affine(tr : Transformations_ptr ); -var - ta : trans_affine; - -begin - ta.Construct( - tr.affineMatrix[0 ] ,tr.affineMatrix[1 ] ,tr.affineMatrix[2 ] , - tr.affineMatrix[3 ] ,tr.affineMatrix[4 ] ,tr.affineMatrix[5 ] ); - - affine(Affine_ptr(@ta ) ); - -end; - -{ ROTATE } -procedure Agg2D.rotate(angle : double ); -var - tar : trans_affine_rotation; - -begin - tar.Construct(angle ); - - m_transform.multiply(@tar ); - -end; - -{ SCALE } -procedure Agg2D.scale(sx ,sy : double ); -var - tas : trans_affine_scaling; - -begin - tas.Construct(sx ,sy ); - - m_transform.multiply(@tas ); - - m_convCurve.approximation_scale_ (worldToScreen(1.0 ) * g_approxScale ); - m_convStroke.approximation_scale_(worldToScreen(1.0 ) * g_approxScale ); - -end; - -{ SKEW } -procedure Agg2D.skew(sx ,sy : double ); -var - tas : trans_affine_skewing; - -begin - tas.Construct(sx ,sy ); - - m_transform.multiply(@tas ); - -end; - -{ TRANSLATE } -procedure Agg2D.translate(x ,y : double ); -var - tat : trans_affine_translation; - -begin - tat.Construct(x ,y ); - - m_transform.multiply(@tat ); - -end; - -{ PARALLELOGRAM } -procedure Agg2D.parallelogram(x1 ,y1 ,x2 ,y2 : double; para : double_ptr ); -var - ta : trans_affine; - -begin - ta.Construct(x1 ,y1 ,x2 ,y2 ,parallelo_ptr(para ) ); - - m_transform.multiply(@ta ); - - m_convCurve.approximation_scale_ (worldToScreen(1.0 ) * g_approxScale ); - m_convStroke.approximation_scale_(worldToScreen(1.0 ) * g_approxScale ); - -end; - -{ VIEWPORT } -procedure Agg2D.viewport( - worldX1 ,worldY1 ,worldX2 ,worldY2 , - screenX1 ,screenY1 ,screenX2 ,screenY2 : double; - opt : ViewportOption = XMidYMid ); -var - vp : trans_viewport; - mx : trans_affine; - -begin - vp.Construct; - - case opt of - Anisotropic : - vp.preserve_aspect_ratio(0.0 ,0.0 ,aspect_ratio_stretch ); - - XMinYMin : - vp.preserve_aspect_ratio(0.0 ,0.0 ,aspect_ratio_meet ); - - XMidYMin : - vp.preserve_aspect_ratio(0.5 ,0.0 ,aspect_ratio_meet ); - - XMaxYMin : - vp.preserve_aspect_ratio(1.0 ,0.0 ,aspect_ratio_meet ); - - XMinYMid : - vp.preserve_aspect_ratio(0.0 ,0.5 ,aspect_ratio_meet ); - - XMidYMid : - vp.preserve_aspect_ratio(0.5 ,0.5 ,aspect_ratio_meet ); - - XMaxYMid : - vp.preserve_aspect_ratio(1.0 ,0.5 ,aspect_ratio_meet ); - - XMinYMax : - vp.preserve_aspect_ratio(0.0 ,1.0 ,aspect_ratio_meet ); - - XMidYMax : - vp.preserve_aspect_ratio(0.5 ,1.0 ,aspect_ratio_meet ); - - XMaxYMax : - vp.preserve_aspect_ratio(1.0 ,1.0 ,aspect_ratio_meet ); - - end; - - vp.world_viewport (worldX1 ,worldY1 ,worldX2 ,worldY2 ); - vp.device_viewport(screenX1 ,screenY1 ,screenX2 ,screenY2 ); - - mx.Construct; - - vp.to_affine (@mx ); - m_transform.multiply(@mx ); - - m_convCurve.approximation_scale_ (worldToScreen(1.0 ) * g_approxScale ); - m_convStroke.approximation_scale_(worldToScreen(1.0 ) * g_approxScale ); - -end; - -{ LINE } -procedure Agg2D.line(const x1, y1, x2, y2: double; AFixAlignment: boolean = false); -var - lx1, ly1, lx2, ly2: double; -begin - m_path.remove_all; - - lx1 := x1; - ly1 := y1; - lx2 := x2; - ly2 := y2; - - if AFixAlignment then - begin - AlignPoint(@lx1, @ly1); - AlignPoint(@lx2, @ly2); - end; - - addLine(lx1, ly1, lx2, ly2); - drawPath(StrokeOnly); -end; - -{ TRIANGLE } -procedure Agg2D.triangle(x1 ,y1 ,x2 ,y2 ,x3 ,y3 : double ); -begin - m_path.remove_all; - m_path.move_to(x1 ,y1 ); - m_path.line_to(x2 ,y2 ); - m_path.line_to(x3 ,y3 ); - m_path.close_polygon; - - drawPath(FillAndStroke ); - -end; - -{ RECTANGLE } -procedure Agg2D.rectangle(const x1 ,y1 ,x2 ,y2 : double; AFixAlignment: boolean); -var - lx1, ly1, lx2, ly2: double; -begin - m_path.remove_all; - - lx1 := x1; - ly1 := y1; - lx2 := x2; - ly2 := y2; - - if AFixAlignment then - begin - AlignPoint(@lx1, @ly1); - AlignPoint(@lx2, @ly2); - end; - - m_path.move_to(lx1 ,ly1 ); - m_path.line_to(lx2 ,ly1 ); - m_path.line_to(lx2 ,ly2 ); - m_path.line_to(lx1 ,ly2 ); - m_path.close_polygon; - - drawPath(FillAndStroke ); - -end; - -{ ROUNDEDRECT } -procedure Agg2D.roundedRect(x1 ,y1 ,x2 ,y2 ,r : double ); -var - rc : rounded_rect; - -begin - m_path.remove_all; - rc.Construct(x1 ,y1 ,x2 ,y2 ,r ); - - rc.normalize_radius; - rc.approximation_scale_(worldToScreen(1.0 ) * g_approxScale ); - - m_path.add_path(@rc ,0 ,false ); - - drawPath(FillAndStroke ); - -end; - -{ ROUNDEDRECT } -procedure Agg2D.roundedRect(x1 ,y1 ,x2 ,y2 ,rx ,ry : double ); -var - rc : rounded_rect; - -begin - m_path.remove_all; - rc.Construct; - - rc.rect (x1 ,y1 ,x2 ,y2 ); - rc.radius(rx ,ry ); - rc.normalize_radius; - - m_path.add_path(@rc ,0 ,false ); - - drawPath(FillAndStroke ); - -end; - -{ ROUNDEDRECT } -procedure Agg2D.roundedRect( - x1 ,y1 ,x2 ,y2 , - rxBottom ,ryBottom , - rxTop ,ryTop : double ); -var - rc : rounded_rect; - -begin - m_path.remove_all; - rc.Construct; - - rc.rect (x1 ,y1 ,x2 ,y2 ); - rc.radius(rxBottom ,ryBottom ,rxTop ,ryTop ); - rc.normalize_radius; - - rc.approximation_scale_(worldToScreen(1.0 ) * g_approxScale ); - - m_path.add_path(@rc ,0 ,false ); - - drawPath(FillAndStroke ); - -end; - -{ ELLIPSE } -procedure Agg2D.ellipse(cx ,cy ,rx ,ry : double ); -var - el : bezier_arc; - -begin - m_path.remove_all; - - el.Construct(cx ,cy ,rx ,ry ,0 ,2 * pi ); - - m_path.add_path(@el ,0 ,false ); - m_path.close_polygon; - - drawPath(FillAndStroke ); - -end; - -{ ARC } -procedure Agg2D.arc(cx ,cy ,rx ,ry ,start ,sweep : double ); -var - ar : {bezier_}agg_arc.arc; - -begin - m_path.remove_all; - - ar.Construct(cx ,cy ,rx ,ry ,start ,sweep ,false ); - - m_path.add_path(@ar ,0 ,false ); - - drawPath(StrokeOnly ); - -end; - -{ STAR } -procedure Agg2D.star(cx ,cy ,r1 ,r2 ,startAngle : double; numRays : int ); -var - da ,a ,x ,y : double; - - i : int; - -begin - m_path.remove_all; - - da:=pi / numRays; - a :=startAngle; - - i:=0; - - while i < numRays do - begin - x:=Cos(a ) * r2 + cx; - y:=Sin(a ) * r2 + cy; - - if i <> 0 then - m_path.line_to(x ,y ) - else - m_path.move_to(x ,y ); - - a:=a + da; - - m_path.line_to(Cos(a ) * r1 + cx ,Sin(a ) * r1 + cy ); - - a:=a + da; - - inc(i ); - - end; - - closePolygon; - drawPath(FillAndStroke ); - -end; - -{ CURVE } -procedure Agg2D.curve(x1 ,y1 ,x2 ,y2 ,x3 ,y3 : double ); -begin - m_path.remove_all; - m_path.move_to(x1 ,y1 ); - m_path.curve3 (x2 ,y2 ,x3 ,y3 ); - - drawPath(StrokeOnly ); - -end; - -{ CURVE } -procedure Agg2D.curve(x1 ,y1 ,x2 ,y2 ,x3 ,y3 ,x4 ,y4 : double ); -begin - m_path.remove_all; - m_path.move_to(x1 ,y1 ); - m_path.curve4 (x2 ,y2 ,x3 ,y3 ,x4 ,y4 ); - - drawPath(StrokeOnly ); - -end; - -{ POLYGON } -procedure Agg2D.polygon(xy : double_ptr; numPoints : int ); -begin - m_path.remove_all; - m_path.add_poly(double_2_ptr(xy ) ,numPoints ); - - closePolygon; - drawPath(FillAndStroke ); - -end; - -{ POLYLINE } -procedure Agg2D.polyline(xy : double_ptr; numPoints : int ); -begin - m_path.remove_all; - m_path.add_poly(double_2_ptr(xy ) ,numPoints ); - - drawPath(StrokeOnly ); - -end; - -{ FLIPTEXT } -procedure Agg2D.flipText(flip : boolean ); -begin - {$IFNDEF AGG2D_NO_FONT} - m_fontEngine.flip_y_(flip ); - {$ENDIF} -end; - -{ FONT } -procedure Agg2D.font( - fileName : char_ptr; height : double; - bold : boolean = false; - italic : boolean = false; - ch : FontCacheType = VectorFontCache; - angle : double = 0.0 ); -var - b : int; - -begin - m_textAngle :=angle; - m_fontHeight :=height; - m_fontCacheType:=ch; - -{$IFDEF AGG2D_USE_FREETYPE } - if ch = VectorFontCache then - m_fontEngine.load_font(PChar(fileName ) ,0 ,glyph_ren_outline ) - else - m_fontEngine.load_font(PChar(fileName ) ,0 ,glyph_ren_agg_gray8 ); - - m_fontEngine.hinting_(m_textHints ); - - if ch = VectorFontCache then - m_fontEngine.height_(height * 96 {screen dpi} / 72 {font dpi}) - else - m_fontEngine.height_(worldToScreen(height ) ); -{$ENDIF} -{$IFDEF AGG2D_USE_WINFONTS} - m_fontEngine.hinting_(m_textHints ); - - if bold then - b:=700 - else - b:=400; - - if ch = VectorFontCache then - m_fontEngine.create_font_(PChar(fileName ) ,glyph_ren_outline ,height ,0.0 ,b ,italic ) - else - m_fontEngine.create_font_(PChar(fileName ) ,glyph_ren_agg_gray8 ,worldToScreen(height) ,0.0 ,b ,italic ); -{$ENDIF } - -end; - -{ FONTHEIGHT } -function Agg2D.fontHeight : double; -begin - result:=m_fontHeight; - -end; - -{ TEXTALIGNMENT } -procedure Agg2D.textAlignment(alignX ,alignY : TextAlignment ); -begin - m_textAlignX:=alignX; - m_textAlignY:=alignY; - -end; - -{ TEXTHINTS } -function Agg2D.textHints : boolean; -begin - result:=m_textHints; - -end; - -{ TEXTHINTS } -procedure Agg2D.textHints(hints : boolean ); -begin - m_textHints:=hints; - {$IFNDEF AGG2D_NO_FONT} - m_fontEngine.hinting_(m_textHints ); - {$ENDIF} -end; - -{ TEXTWIDTH } -function Agg2D.textWidth(str : AnsiString ) : double; -{$IFDEF AGG2D_NO_FONT} -begin - Result := 0; -end; -{$ELSE} -var - x ,y : double; - first : boolean; - glyph : glyph_cache_ptr; - str_ : PChar; - -begin - if str = '' then exit(0); - x:=0; - y:=0; - - first:=true; - str_ := PChar(str); - - while str_^ <> #0 do - begin - glyph:=m_fontCacheManager.glyph(int32u(str_^ ) ); - - if glyph <> NIL then - begin - if not first then - m_fontCacheManager.add_kerning(@x ,@y ); - - x:=x + glyph.advance_x; - y:=y + glyph.advance_y; - - first:=false; - - end; - - inc(ptrcomp(str_ ) ); - - end; - - if m_fontCacheType = VectorFontCache then - result:=x - else - result:=screenToWorld(x ); - -end; -{$ENDIF} - -{ TEXT } -procedure Agg2D.text( - x ,y : double; str : AnsiString; - roundOff : boolean = false; - ddx : double = 0.0; - ddy : double = 0.0 ); -{$IFDEF AGG2D_NO_FONT} -begin - -end; -{$ELSE} -var - dx ,dy ,asc ,start_x ,start_y : double; - - glyph : glyph_cache_ptr; - - mtx : trans_affine; - str_ : PChar; - - tat : trans_affine_translation; - tar : trans_affine_rotation; - - tr : conv_transform; - charlen: int; - char_id: int32u; - First: Boolean; - -begin - if Str='' then exit; - - dx:=0.0; - dy:=0.0; - - case m_textAlignX of - AlignCenter : - dx:=-textWidth(str ) * 0.5; - - AlignRight : - dx:=-textWidth(str ); - - end; - - asc :=fontHeight; - glyph:=m_fontCacheManager.glyph(int32u('H' ) ); - - if glyph <> NIL then - asc:=glyph.bounds.y2 - glyph.bounds.y1; - - if m_fontCacheType = RasterFontCache then - asc:=screenToWorld(asc ); - - case m_textAlignY of - AlignCenter : - dy:=-asc * 0.5; - - AlignTop : - dy:=-asc; - - end; - - if m_fontEngine._flip_y then - dy:=-dy; - - mtx.Construct; - - start_x:=x + dx; - start_y:=y + dy; - - if roundOff then - begin - start_x:=Trunc(start_x ); - start_y:=Trunc(start_y ); - end; - - start_x:=start_x + ddx; - start_y:=start_y + ddy; - - tat.Construct(-x ,-y ); - mtx.multiply (@tat ); - - tar.Construct(m_textAngle ); - mtx.multiply (@tar ); - - tat.Construct(x ,y ); - mtx.multiply (@tat ); - - tr.Construct(m_fontCacheManager.path_adaptor ,@mtx ); - - if m_fontCacheType = RasterFontCache then - WorldToScreen(@start_x ,@start_y ); - - str_:=@str[1 ]; - First:=true; - - while str_^ <> #0 do - begin - char_id := UTF8CharToUnicode(str_, charlen); - inc(str_, charlen); - glyph := m_fontCacheManager.glyph(char_id); - - if glyph <> NIL then - begin - if First then - begin - m_fontCacheManager.add_kerning(@x ,@y ); - First:=false; - end; - - m_fontCacheManager.init_embedded_adaptors(glyph ,start_x ,start_y ); - - if glyph.data_type = glyph_data_outline then - begin - m_path.remove_all; - m_path.add_path(@tr ,0 ,false ); - drawPath; - end; - - if glyph.data_type = glyph_data_gray8 then - begin - Render( - m_fontCacheManager.gray8_adaptor , - m_fontCacheManager.gray8_scanline ); - end; - - start_x := start_x + glyph.advance_x; - start_y := start_y + glyph.advance_y; - end; - end; { if glyph <> nil } -end; -{$ENDIF} - -{ RESETPATH } -procedure Agg2D.resetPath; -begin - m_path.remove_all; - m_path.move_to(0 ,0 ); - -end; - -{ MOVETO } -procedure Agg2D.moveTo(x ,y : double ); -begin - m_path.move_to(x ,y ); - -end; - -{ MOVEREL } -procedure Agg2D.moveRel(dx ,dy : double ); -begin - m_path.move_rel(dx ,dy ); - -end; - -{ LINETO } -procedure Agg2D.lineTo(x ,y : double ); -begin - m_path.line_to(x ,y ); - -end; - -{ LINEREL } -procedure Agg2D.lineRel(dx ,dy : double ); -begin - m_path.line_rel(dx ,dy ); - -end; - -{ HORLINETO } -procedure Agg2D.horLineTo(x : double ); -begin - m_path.hline_to(x ); - -end; - -{ HORLINEREL } -procedure Agg2D.horLineRel(dx : double ); -begin - m_path.hline_rel(dx ); - -end; - -{ VERLINETO } -procedure Agg2D.verLineTo(y : double ); -begin - m_path.vline_to(y ); - -end; - -{ VERLINEREL } -procedure Agg2D.verLineRel(dy : double ); -begin - m_path.vline_rel(dy ); - -end; - -{ ARCTO } -procedure Agg2D.arcTo( - rx ,ry ,angle : double; - largeArcFlag ,sweepFlag : boolean; - x ,y : double ); -begin - m_path.arc_to(rx ,ry ,angle ,largeArcFlag ,sweepFlag ,x ,y ); - -end; - -{ ARCREL } -procedure Agg2D.arcRel( - rx ,ry ,angle : double; - largeArcFlag ,sweepFlag : boolean; - dx ,dy : double ); -begin - m_path.arc_rel(rx ,ry ,angle ,largeArcFlag ,sweepFlag ,dx ,dy ); - -end; - -{ QUADRICCURVETO } -procedure Agg2D.quadricCurveTo (xCtrl ,yCtrl ,xTo ,yTo : double ); -begin - m_path.curve3(xCtrl ,yCtrl ,xTo ,yTo ); - -end; - -{ QUADRICCURVEREL } -procedure Agg2D.quadricCurveRel(dxCtrl ,dyCtrl ,dxTo ,dyTo : double ); -begin - m_path.curve3_rel(dxCtrl ,dyCtrl ,dxTo ,dyTo ); - -end; - -{ QUADRICCURVETO } -procedure Agg2D.quadricCurveTo (xTo ,yTo : double ); -begin - m_path.curve3(xTo ,yTo ); - -end; - -{ QUADRICCURVEREL } -procedure Agg2D.quadricCurveRel(dxTo ,dyTo : double ); -begin - m_path.curve3_rel(dxTo ,dyTo ); - -end; - -{ CUBICCURVETO } -procedure Agg2D.cubicCurveTo (xCtrl1 ,yCtrl1 ,xCtrl2 ,yCtrl2 ,xTo ,yTo : double ); -begin - m_path.curve4(xCtrl1 ,yCtrl1 ,xCtrl2 ,yCtrl2 ,xTo ,yTo ); - -end; - -{ CUBICCURVEREL } -procedure Agg2D.cubicCurveRel(dxCtrl1 ,dyCtrl1 ,dxCtrl2 ,dyCtrl2 ,dxTo ,dyTo : double ); -begin - m_path.curve4_rel(dxCtrl1 ,dyCtrl1 ,dxCtrl2 ,dyCtrl2 ,dxTo ,dyTo ); - -end; - -{ CUBICCURVETO } -procedure Agg2D.cubicCurveTo (xCtrl2 ,yCtrl2 ,xTo ,yTo : double ); -begin - m_path.curve4(xCtrl2 ,yCtrl2 ,xTo ,yTo ); - -end; - -{ CUBICCURVEREL } -procedure Agg2D.cubicCurveRel(xCtrl2 ,yCtrl2 ,xTo ,yTo : double ); -begin - m_path.curve4_rel(xCtrl2 ,yCtrl2 ,xTo ,yTo ); - -end; - -{ ADDELLIPSE } -procedure Agg2D.addEllipse(cx ,cy ,rx ,ry : double; dir : Direction ); -var - ar : bezier_arc; - -begin - if dir = CCW then - ar.Construct(cx ,cy ,rx ,ry ,0 ,2 * pi ) - else - ar.Construct(cx ,cy ,rx ,ry ,0 ,-2 * pi ); - - m_path.add_path(@ar ,0 ,false ); - m_path.close_polygon; - -end; - -{ CLOSEPOLYGON } -procedure Agg2D.closePolygon; -begin - m_path.close_polygon; - -end; - -{ DRAWPATH } -procedure Agg2D.drawPath(flag : DrawPathFlag = FillAndStroke ); -begin - m_rasterizer.reset; - - case flag of - FillOnly : - if m_fillColor.a <> 0 then - begin - m_rasterizer.add_path(@m_pathTransform ); - - render(true ); - - end; - - StrokeOnly : - if (m_lineColor.a <> 0 ) and - (m_lineWidth > 0.0 ) then - begin - m_rasterizer.add_path(@m_strokeTransform ); - - render(false ); - - end; - - FillAndStroke : - begin - if m_fillColor.a <> 0 then - begin - m_rasterizer.add_path(@m_pathTransform ); - - render(true ); - - end; - - if (m_lineColor.a <> 0 ) and - (m_lineWidth > 0.0 ) then - begin - m_rasterizer.add_path(@m_strokeTransform ); - - render(false ); - - end; - - end; - - FillWithLineColor : - if m_lineColor.a <> 0 then - begin - m_rasterizer.add_path(@m_pathTransform ); - - render(false ); - - end; - - end; - -end; - -{ DRAWPATHNOTRANSFORM } -procedure Agg2D.drawPathNoTransform(flag : DrawPathFlag = FillAndStroke ); -begin -end; - -{ IMAGEFILTER } -procedure Agg2D.imageFilter(f : ImageFilter_ ); -begin - m_imageFilter:=f; - - case f of - Bilinear : - m_imageFilterLut.calculate(@m_ifBilinear ,true ); - - Hanning : - m_imageFilterLut.calculate(@m_ifHanning ,true ); - - Hermite : - m_imageFilterLut.calculate(@m_ifHermite ,true ); - - Quadric : - m_imageFilterLut.calculate(@m_ifQuadric ,true ); - - Bicubic : - m_imageFilterLut.calculate(@m_ifBicubic ,true ); - - Catrom : - m_imageFilterLut.calculate(@m_ifCatrom ,true ); - - Spline16 : - m_imageFilterLut.calculate(@m_ifSpline16 ,true ); - - Spline36 : - m_imageFilterLut.calculate(@m_ifSpline36 ,true ); - - Blackman144 : - m_imageFilterLut.calculate(@m_ifBlackman144 ,true ); - - end; - -end; - -{ IMAGEFILTER } -function Agg2D.imageFilter : ImageFilter_; -begin - result:=m_imageFilter; - -end; - -{ IMAGERESAMPLE } -procedure Agg2D.imageResample(f : ImageResample_ ); -begin - m_imageResample:=f; - -end; - -{ IMAGERESAMPLE } -function Agg2D.imageResample : ImageResample_; -begin - result:=m_imageResample; - -end; - -{ TRANSFORMIMAGE } -procedure Agg2D.transformImage( - img : Image_ptr; - imgX1 ,imgY1 ,imgX2 ,imgY2 : int; - dstX1 ,dstY1 ,dstX2 ,dstY2 : double ); -var - parall : array[0..5 ] of double; - -begin - resetPath; - moveTo(dstX1 ,dstY1 ); - lineTo(dstX2 ,dstY1 ); - lineTo(dstX2 ,dstY2 ); - lineTo(dstX1 ,dstY2 ); - closePolygon; - - parall[0 ]:=dstX1; - parall[1 ]:=dstY1; - parall[2 ]:=dstX2; - parall[3 ]:=dstY1; - parall[4 ]:=dstX2; - parall[5 ]:=dstY2; - - renderImage(img ,imgX1 ,imgY1 ,imgX2 ,imgY2 ,@parall[0 ] ); - -end; - -{ TRANSFORMIMAGE } -procedure Agg2D.transformImage( - img : Image_ptr; - dstX1 ,dstY1 ,dstX2 ,dstY2 : double ); -var - parall : array[0..5 ] of double; - -begin - resetPath; - moveTo(dstX1 ,dstY1 ); - lineTo(dstX2 ,dstY1 ); - lineTo(dstX2 ,dstY2 ); - lineTo(dstX1 ,dstY2 ); - closePolygon; - - parall[0 ]:=dstX1; - parall[1 ]:=dstY1; - parall[2 ]:=dstX2; - parall[3 ]:=dstY1; - parall[4 ]:=dstX2; - parall[5 ]:=dstY2; - - renderImage(img ,0 ,0 ,img.renBuf._width ,img.renBuf._height ,@parall[0 ] ); - -end; - -{ TRANSFORMIMAGE } -procedure Agg2D.transformImage( - img : Image_ptr; - imgX1 ,imgY1 ,imgX2 ,imgY2 : int; - parallelogram_ : double_ptr ); -begin - resetPath; - - moveTo( - double_ptr(ptrcomp(parallelogram_ ) + 0 * sizeof(double ) )^ , - double_ptr(ptrcomp(parallelogram_ ) + 1 * sizeof(double ) )^ ); - - lineTo( - double_ptr(ptrcomp(parallelogram_ ) + 2 * sizeof(double ) )^ , - double_ptr(ptrcomp(parallelogram_ ) + 3 * sizeof(double ) )^ ); - - lineTo( - double_ptr(ptrcomp(parallelogram_ ) + 4 * sizeof(double ) )^ , - double_ptr(ptrcomp(parallelogram_ ) + 5 * sizeof(double ) )^ ); - - lineTo( - double_ptr(ptrcomp(parallelogram_ ) + 0 * sizeof(double ) )^ + - double_ptr(ptrcomp(parallelogram_ ) + 4 * sizeof(double ) )^ - - double_ptr(ptrcomp(parallelogram_ ) + 2 * sizeof(double ) )^ , - double_ptr(ptrcomp(parallelogram_ ) + 1 * sizeof(double ) )^ + - double_ptr(ptrcomp(parallelogram_ ) + 5 * sizeof(double ) )^ - - double_ptr(ptrcomp(parallelogram_ ) + 3 * sizeof(double ) )^ ); - - closePolygon; - - renderImage(img ,imgX1 ,imgY1 ,imgX2 ,imgY2 ,parallelogram_ ); - -end; - -{ TRANSFORMIMAGE } -procedure Agg2D.transformImage(img : Image_ptr; parallelogram_ : double_ptr ); -begin - resetPath; - - moveTo( - double_ptr(ptrcomp(parallelogram_ ) + 0 * sizeof(double ) )^ , - double_ptr(ptrcomp(parallelogram_ ) + 1 * sizeof(double ) )^ ); - - lineTo( - double_ptr(ptrcomp(parallelogram_ ) + 2 * sizeof(double ) )^ , - double_ptr(ptrcomp(parallelogram_ ) + 3 * sizeof(double ) )^ ); - - lineTo( - double_ptr(ptrcomp(parallelogram_ ) + 4 * sizeof(double ) )^ , - double_ptr(ptrcomp(parallelogram_ ) + 5 * sizeof(double ) )^ ); - - lineTo( - double_ptr(ptrcomp(parallelogram_ ) + 0 * sizeof(double ) )^ + - double_ptr(ptrcomp(parallelogram_ ) + 4 * sizeof(double ) )^ - - double_ptr(ptrcomp(parallelogram_ ) + 2 * sizeof(double ) )^ , - double_ptr(ptrcomp(parallelogram_ ) + 1 * sizeof(double ) )^ + - double_ptr(ptrcomp(parallelogram_ ) + 5 * sizeof(double ) )^ - - double_ptr(ptrcomp(parallelogram_ ) + 3 * sizeof(double ) )^ ); - - closePolygon; - - renderImage(img ,0 ,0 ,img.renBuf._width ,img.renBuf._height ,parallelogram_ ); - -end; - -{ TRANSFORMIMAGEPATH } -procedure Agg2D.transformImagePath( - img : Image_ptr; - imgX1 ,imgY1 ,imgX2 ,imgY2 : int; - dstX1 ,dstY1 ,dstX2 ,dstY2 : double ); -var - parall : array[0..5 ] of double; - -begin - parall[0 ]:=dstX1; - parall[1 ]:=dstY1; - parall[2 ]:=dstX2; - parall[3 ]:=dstY1; - parall[4 ]:=dstX2; - parall[5 ]:=dstY2; - - renderImage(img ,imgX1 ,imgY1 ,imgX2 ,imgY2 ,@parall[0 ] ); - -end; - -{ TRANSFORMIMAGEPATH } -procedure Agg2D.transformImagePath( - img : Image_ptr; - dstX1 ,dstY1 ,dstX2 ,dstY2 : double ); -var - parall : array[0..5 ] of double; - -begin - parall[0 ]:=dstX1; - parall[1 ]:=dstY1; - parall[2 ]:=dstX2; - parall[3 ]:=dstY1; - parall[4 ]:=dstX2; - parall[5 ]:=dstY2; - - renderImage(img ,0 ,0 ,img.renBuf._width ,img.renBuf._height ,@parall[0 ] ); - -end; - -{ TRANSFORMIMAGEPATH } -procedure Agg2D.transformImagePath( - img : Image_ptr; - imgX1 ,imgY1 ,imgX2 ,imgY2 : int; - parallelogram_ : double_ptr ); -begin - renderImage(img ,imgX1 ,imgY1 ,imgX2 ,imgY2 ,parallelogram_ ); - -end; - -{ TRANSFORMIMAGEPATH } -procedure Agg2D.transformImagePath(img : Image_ptr; parallelogram_ : double_ptr ); -begin - renderImage(img ,0 ,0 ,img.renBuf._width ,img.renBuf._height ,parallelogram_ ); - -end; - -procedure Agg2D.Blur(rx, ry: unsigned); -begin - stack_blur_rgba32(@m_pixFormat, rx, ry); -end; - -{ BLENDIMAGE } -procedure Agg2D.blendImage( - img : Image_ptr; - imgX1 ,imgY1 ,imgX2 ,imgY2 : int; - dstX ,dstY : double; alpha : unsigned = 255 ); -var - pixF : pixel_formats; - - r : agg_basics.rect; - -begin - worldToScreen(@dstX ,@dstY ); - pixfmt_rgba32(pixF ,@img.renBuf ); - r.Construct (imgX1 ,imgY1 ,imgX2 ,imgY2 ); - - if m_blendMode = BlendAlpha then - m_renBasePre.blend_from(@pixF ,@r ,Trunc(dstX ) - imgX1 ,Trunc(dstY ) - imgY1 ,alpha ) - else - m_renBaseCompPre.blend_from(@pixF ,@r ,Trunc(dstX ) - imgX1 ,Trunc(dstY ) - imgY1 ,alpha ); - -end; - -{ BLENDIMAGE } -procedure Agg2D.blendImage(img : Image_ptr; dstX ,dstY : double; alpha : unsigned = 255 ); -var - pixF : pixel_formats; - -begin - worldToScreen(@dstX ,@dstY ); - pixfmt_rgba32(pixF ,@img.renBuf ); - - m_renBasePre.blend_from(@pixF ,NIL ,Trunc(dstX ) ,Trunc(dstY ) ,alpha ); - - if m_blendMode = BlendAlpha then - m_renBasePre.blend_from(@pixF ,NIL ,Trunc(dstX ) ,Trunc(dstY ) ,alpha ) - else - m_renBaseCompPre.blend_from(@pixF ,NIL ,Trunc(dstX ) ,Trunc(dstY ) ,alpha ); - -end; - -{ COPYIMAGE } -procedure Agg2D.copyImage( - img : Image_ptr; - imgX1 ,imgY1 ,imgX2 ,imgY2 : int; - dstX ,dstY : double ); -var - r : agg_basics.rect; - -begin - worldToScreen(@dstX ,@dstY ); - r.Construct (imgX1 ,imgY1 ,imgX2 ,imgY2 ); - - m_renBase.copy_from(@img.renBuf ,@r ,Trunc(dstX ) - imgX1 ,Trunc(dstY ) - imgY1 ); - -end; - -{ COPYIMAGE } -procedure Agg2D.copyImage(img : Image_ptr; dstX ,dstY : double ); -begin - worldToScreen(@dstX ,@dstY ); - - m_renBase.copy_from(@img.renBuf ,NIL ,Trunc(dstX ) ,Trunc(dstY ) ); - -end; - -{ RENDER } -procedure Agg2D.render(fillColor_ : boolean ); -begin - if m_blendMode = BlendAlpha then - Agg2DRenderer_render(@self ,@m_renBase ,@m_renSolid ,fillColor_ ) - else - Agg2DRenderer_render(@self ,@m_renBaseComp ,@m_renSolidComp ,fillColor_ ); - -end; - -{ RENDER } -procedure Agg2D.render(ras : FontRasterizer_ptr; sl : FontScanline_ptr ); -begin - if m_blendMode = BlendAlpha then - Agg2DRenderer_render(@self ,@m_renBase ,@m_renSolid ,ras ,sl ) - else - Agg2DRenderer_render(@self ,@m_renBaseComp ,@m_renSolidComp ,ras ,sl ); - -end; - -{ ADDLINE } -procedure Agg2D.addLine(x1 ,y1 ,x2 ,y2 : double ); -begin - m_path.move_to(x1 ,y1 ); - m_path.line_to(x2 ,y2 ); - -end; - -{ UPDATERASTERIZERGAMMA } -procedure Agg2D.updateRasterizerGamma; -begin - m_gammaAgg2D.Construct(m_masterAlpha ,m_antiAliasGamma ); - m_rasterizer.gamma (@m_gammaAgg2D ); - -end; - -{ RENDERIMAGE } -procedure Agg2D.renderImage( - img : Image_ptr; - x1 ,y1 ,x2 ,y2 : int; - parl : double_ptr ); -var - mtx : trans_affine; - - interpolator : span_interpolator_linear; - -begin - mtx.Construct(x1 ,y1 ,x2 ,y2 ,parallelo_ptr(parl ) ); - mtx.multiply (@m_transform ); - mtx.invert; - - m_rasterizer.reset; - m_rasterizer.add_path(@m_pathTransform ); - - interpolator.Construct(@mtx ); - - if m_blendMode = BlendAlpha then - Agg2DRenderer_renderImage(@self ,img ,@m_renBasePre ,@interpolator ) - else - Agg2DRenderer_renderImage(@self ,img ,@m_renBaseCompPre ,@interpolator ); - -end; - -{ CONSTRUCT } -constructor SpanConvImageBlend.Construct(m : BlendMode_; c : Color; p : pixel_formats_ptr ); -begin - m_mode :=m; - m_color:=c; - m_pixel:=p; - -end; - -{ CONVERT } -procedure SpanConvImageBlend.convert(span : aggclr_ptr; x ,y : int; len : unsigned ); -var - l2 ,a : unsigned; - - s2 : Color_ptr; - -begin - if m_mode <> BlendDst then - begin - l2:=len; - s2:=Color_ptr(span ); - - repeat - comp_op_adaptor_clip_to_dst_rgba_pre( - m_pixel , - unsigned(m_mode ) , - int8u_ptr(s2 ) , - m_color.r , - m_color.g , - m_color.b , - base_mask , - cover_full ); - - inc(ptrcomp(s2 ) ,sizeof(Color ) ); - dec(l2 ); - - until l2 = 0; - - end; - - if m_color.a < base_mask then - begin - l2:=len; - s2:=Color_ptr(span ); - a :=m_color.a; - - repeat - s2.r:=(s2.r * a ) shr base_shift; - s2.g:=(s2.g * a ) shr base_shift; - s2.b:=(s2.b * a ) shr base_shift; - s2.a:=(s2.a * a ) shr base_shift; - - inc(ptrcomp(s2 ) ,sizeof(Color ) ); - dec(l2 ); - - until l2 = 0; - - end; - -end; - -{ PI } -function pi : double; -begin - result:=agg_basics.pi; - -end; - -{ DEG2RAD } -function deg2Rad(v : double ) : double; -begin - result:=v * agg_basics.pi / 180.0; - -end; - -{ RAD2DEG } -function rad2Deg(v : double ) : double; -begin - result:=v * 180.0 / agg_basics.pi; - -end; - -{ OPERATOR_IS_EQUAL } -function operator_is_equal(c1 ,c2 : Color_ptr ) : boolean; -begin - result:= - (c1.r = c2.r ) and - (c1.g = c2.g ) and - (c1.b = c2.b ) and - (c1.a = c2.a ); - -end; - -{ OPERATOR_IS_NOT_EQUAL } -function operator_is_not_equal(c1 ,c2 : Color_ptr ) : boolean; -begin - result:=not operator_is_equal(c1 ,c2 ); - -end; - -{ AGG2DRENDERER_RENDER } -procedure Agg2DRenderer_render( - gr : Agg2D_ptr; - renBase : renderer_base_ptr; - renSolid : renderer_scanline_aa_solid_ptr; - fillColor_ : boolean ); -var - span : span_gradient; - ren : renderer_scanline_aa; - clr : aggclr; - -begin - if (fillColor_ and - (gr.m_fillGradientFlag = Linear ) ) or - (not fillColor_ and - (gr.m_lineGradientFlag = Linear ) ) then - if fillColor_ then - begin - span.Construct( - @gr.m_allocator , - @gr.m_fillGradientInterpolator , - @gr.m_linearGradientFunction , - @gr.m_fillGradient , - gr.m_fillGradientD1 , - gr.m_fillGradientD2 ); - - ren.Construct (renBase ,@span ); - render_scanlines(@gr.m_rasterizer ,@gr.m_scanline ,@ren ); - - end - else - begin - span.Construct( - @gr.m_allocator , - @gr.m_lineGradientInterpolator , - @gr.m_linearGradientFunction , - @gr.m_lineGradient , - gr.m_lineGradientD1 , - gr.m_lineGradientD2 ); - - ren.Construct (renBase ,@span ); - render_scanlines(@gr.m_rasterizer ,@gr.m_scanline ,@ren ); - - end - else - if (fillColor_ and - (gr.m_fillGradientFlag = Radial ) ) or - (not fillColor_ and - (gr.m_lineGradientFlag = Radial ) ) then - if fillColor_ then - begin - span.Construct( - @gr.m_allocator , - @gr.m_fillGradientInterpolator , - @gr.m_radialGradientFunction , - @gr.m_fillGradient , - gr.m_fillGradientD1 , - gr.m_fillGradientD2 ); - - ren.Construct (renBase ,@span ); - render_scanlines(@gr.m_rasterizer ,@gr.m_scanline ,@ren ); - - end - else - begin - span.Construct( - @gr.m_allocator , - @gr.m_lineGradientInterpolator , - @gr.m_radialGradientFunction , - @gr.m_lineGradient , - gr.m_lineGradientD1 , - gr.m_lineGradientD2 ); - - ren.Construct (renBase ,@span ); - render_scanlines(@gr.m_rasterizer ,@gr.m_scanline ,@ren ); - - end - else - begin - if fillColor_ then - clr.Construct(gr.m_fillColor ) - else - clr.Construct(gr.m_lineColor ); - - renSolid.color_ (@clr ); - render_scanlines(@gr.m_rasterizer ,@gr.m_scanline ,renSolid ); - - end; - -end; - -{ AGG2DRENDERER_RENDER } -procedure Agg2DRenderer_render( - gr : Agg2D_ptr; - renBase : renderer_base_ptr; - renSolid : renderer_scanline_aa_solid_ptr; - ras : gray8_adaptor_type_ptr; - sl : gray8_scanline_type_ptr ); -var - span : span_gradient; - ren : renderer_scanline_aa; - clr : aggclr; - -begin - if gr.m_fillGradientFlag = Linear then - begin - span.Construct( - @gr.m_allocator , - @gr.m_fillGradientInterpolator , - @gr.m_linearGradientFunction , - @gr.m_fillGradient , - gr.m_fillGradientD1 , - gr.m_fillGradientD2 ); - - ren.Construct (renBase ,@span ); - render_scanlines(ras ,sl ,@ren ); - - end - else - if gr.m_fillGradientFlag = Radial then - begin - span.Construct( - @gr.m_allocator , - @gr.m_fillGradientInterpolator , - @gr.m_radialGradientFunction , - @gr.m_fillGradient , - gr.m_fillGradientD1 , - gr.m_fillGradientD2 ); - - ren.Construct (renBase ,@span ); - render_scanlines(ras ,sl ,@ren ); - - end - else - begin - clr.Construct (gr.m_fillColor ); - renSolid.color_ (@clr ); - render_scanlines(ras ,sl ,renSolid ); - - end; - -end; - -{ AGG2DRENDERER_RENDERIMAGE } -procedure Agg2DRenderer_renderImage( - gr : Agg2D_ptr; - img : Image_ptr; - renBase : renderer_base_ptr; - interpolator : span_interpolator_linear_ptr ); -var - blend : SpanConvImageBlend; - - si : span_image_filter_rgba; - sg : span_image_filter_rgba_nn; - sb : span_image_filter_rgba_bilinear; - s2 : span_image_filter_rgba_2x2; - sa : span_image_resample_rgba_affine; - sc : span_converter; - ri : renderer_scanline_aa; - - clr : aggclr; - - resample : boolean; - - sx ,sy : double; - -begin - blend.Construct(gr.m_imageBlendMode ,gr.m_imageBlendColor ,@gr.m_pixFormatCompPre ); - - if gr.m_imageFilter = NoFilter then - begin - clr.ConstrInt(0 ,0 ,0 ,0 ); - sg.Construct (@gr.m_allocator ,@img.renBuf ,@clr ,interpolator ,rgba_order ); - sc.Construct (@sg ,@blend ); - ri.Construct (renBase ,@sc ); - - render_scanlines(@gr.m_rasterizer ,@gr.m_scanline ,@ri ); - - end - else - begin - resample:=gr.m_imageResample = ResampleAlways; - - if gr.m_imageResample = ResampleOnZoomOut then - begin - interpolator._transformer.scaling_abs(@sx ,@sy ); - - if (sx > 1.125 ) or - (sy > 1.125 ) then - resample:=true; - - end; - - if resample then - begin - clr.ConstrInt(0 ,0 ,0 ,0 ); - sa.Construct( - @gr.m_allocator , - @img.renBuf , - @clr , - interpolator , - @gr.m_imageFilterLut , - rgba_order ); - - sc.Construct(@sa ,@blend ); - ri.Construct(renBase ,@sc ); - - render_scanlines(@gr.m_rasterizer ,@gr.m_scanline ,@ri ); - - end - else - if gr.m_imageFilter = Bilinear then - begin - clr.ConstrInt(0 ,0 ,0 ,0 ); - sb.Construct( - @gr.m_allocator , - @img.renBuf , - @clr , - interpolator , - rgba_order ); - - sc.Construct(@sb ,@blend ); - ri.Construct(renBase ,@sc ); - - render_scanlines(@gr.m_rasterizer ,@gr.m_scanline ,@ri ); - - end - else - if gr.m_imageFilterLut.diameter = 2 then - begin - clr.ConstrInt(0 ,0 ,0 ,0 ); - s2.Construct( - @gr.m_allocator , - @img.renBuf , - @clr , - interpolator, - @gr.m_imageFilterLut , - rgba_order ); - - sc.Construct(@s2 ,@blend ); - ri.Construct(renBase ,@sc ); - - render_scanlines(@gr.m_rasterizer ,@gr.m_scanline ,@ri ); - - end - else - begin - clr.ConstrInt(0 ,0 ,0 ,0 ); - si.Construct( - @gr.m_allocator , - @img.renBuf , - @clr , - interpolator , - @gr.m_imageFilterLut , - rgba_order ); - - sc.Construct(@si ,@blend ); - ri.Construct(renBase ,@sc ); - - render_scanlines(@gr.m_rasterizer ,@gr.m_scanline ,@ri ); - - end; - - end; - -end; - -{ AGG2DUSESFREETYPE } -function Agg2DUsesFreeType : boolean; -begin -{$IFDEF AGG2D_USE_FREETYPE } - result:=true; -{$ELSE } - result:=false; -{$ENDIF } - -end; - -function Agg2DUsesWin32TrueType: boolean; -begin -{$IFDEF AGG2D_USE_WINFONTS } - result:=true; -{$ELSE } - result:=false; -{$ENDIF } -end; - -end. - From 30d2a6903c94d9210fa7683534a01941c6dbc839 Mon Sep 17 00:00:00 2001 From: James Richters Date: Sun, 18 Jun 2017 18:19:36 -0400 Subject: [PATCH 5/7] Patch Color reversal issue for rgb565 pixel format --- src/corelib/render/software/agg_2D.pas | 3 ++- src/corelib/render/software/agg_color.pas | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/corelib/render/software/agg_2D.pas b/src/corelib/render/software/agg_2D.pas index d88628762..534b80350 100644 --- a/src/corelib/render/software/agg_2D.pas +++ b/src/corelib/render/software/agg_2D.pas @@ -43,7 +43,8 @@ interface { With this define you can switch to an experimental version that is more compatible with freepascal console graphics units such as Graph and ptcgraph - ToDo: red and blue are reversed and need to be fixed } + ToDo: red and blue are reversed and need to be fixed + - temporarily patched See notes in agg_color.pas} {.$Define AGG2D_USE_RGB565} diff --git a/src/corelib/render/software/agg_color.pas b/src/corelib/render/software/agg_color.pas index 05958f8df..2df8ee533 100644 --- a/src/corelib/render/software/agg_color.pas +++ b/src/corelib/render/software/agg_color.pas @@ -40,6 +40,18 @@ {$Q- } {$R- } +{ The Following define resets the colors back to be correct for use with + RGB565 pixelformat + The original was reversed for unknown reasons but came out with red + and blue being reversed. Note that all functions and procedures which + specify a red, green, and blue channel, red and blue are normally REVERSED. + They are correct with the following define, but since I don't know the extent + to which the color reversal needed to be implemented the safest thing for now + is to correct it with the following define. +} + +{.$Define AGG2D_USE_RGB565} + uses Math , agg_basics ; @@ -121,9 +133,15 @@ order_type = record { CONSTRUCT } constructor rgba8.Construct; begin +{$IFDEF AGG2D_USE_RGB565 } + b{*}:=int8u(b_ ); + g:=int8u(g_ ); + r:=int8u(r_ ); +{$ELSE } b{*}:=int8u(r_ ); g:=int8u(g_ ); r:=int8u(b_ ); +{$ENDIF } a:=int8u(a_ ); end; From e173d8d45ef0417620cece2cbdd5ee172e510117 Mon Sep 17 00:00:00 2001 From: James Richters Date: Wed, 30 Aug 2017 16:59:52 -0400 Subject: [PATCH 6/7] Include FreeType32.dll and FreeType64.dll --- extras/freetype_windows/FreeType.zip | Bin 0 -> 599659 bytes extras/freetype_windows/freetype.zip | Bin 293839 -> 0 bytes extras/freetype_windows/readme.txt | 6 +++--- 3 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 extras/freetype_windows/FreeType.zip delete mode 100644 extras/freetype_windows/freetype.zip diff --git a/extras/freetype_windows/FreeType.zip b/extras/freetype_windows/FreeType.zip new file mode 100644 index 0000000000000000000000000000000000000000..7da84e3ac44fbd0f3001d770bf50e77a890b50a8 GIT binary patch literal 599659 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