Ignore:
Timestamp:
Apr 9, 2015, 9:58:36 PM (9 years ago)
Author:
chronos
Message:
  • Fixed: Use csOpaque control style also to Image, PaintBox and OpenGLControl.
  • Modified: Change size of test frame with SpinEdits as delayed using timer.
  • Updated: BRGABitmap package to version 8.1.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • GraphicTest/Packages/bgrabitmap/bgrafreetype.pas

    r452 r472  
    33{$mode objfpc}{$H+}
    44
     5{
     6  Font rendering units : BGRAText, BGRATextFX, BGRAVectorize, BGRAFreeType
     7
     8  This units provide a font renderer with FreeType fonts, using the integrated FreeType font engine in Lazarus.
     9  The simplest way to render effects is to use TBGRAFreeTypeFontRenderer class.
     10  To do this, create an instance of this class and assign it to a TBGRABitmap.FontRenderer property. Now functions
     11  to draw text like TBGRABitmap.TextOut will use the chosen renderer.
     12
     13  >> Note that you need to defined the default FreeType font collection
     14  >> using LazFreeTypeFontCollection unit.
     15
     16  To set the effects, keep a variable containing
     17  the TBGRAFreeTypeFontRenderer class and modify ShadowVisible and other effects parameters. The FontHinted property
     18  allows you to choose if the font is snapped to pixels to make it more readable.
     19
     20  TBGRAFreeTypeDrawer class is the class that provides basic FreeType drawing
     21  by deriving the TFreeTypeDrawer type. You can use it directly, but it is not
     22  recommended, because there are less text layout parameters. However, it is
     23  necessary if you want to create TBGRATextEffect objects using FreeType fonts.
     24}
     25
    526interface
    627
    728uses
    8   Classes, SysUtils, Graphics, BGRABitmapTypes, EasyLazFreeType, FPimage;
     29  Types, Classes, SysUtils, Graphics, BGRABitmapTypes, EasyLazFreeType, FPimage, BGRAText, BGRATextFX, BGRAPhongTypes, LCLVersion;
    930
    1031type
     32  TBGRAFreeTypeDrawer = class;
     33
     34  //this is the class to assign to FontRenderer property of TBGRABitmap
     35  { TBGRAFreeTypeFontRenderer }
     36
     37  TBGRAFreeTypeFontRenderer = class(TBGRACustomFontRenderer)
     38  private
     39    FDrawer: TBGRAFreeTypeDrawer;
     40    FFont: TFreeTypeFont;
     41    function GetCollection: TCustomFreeTypeFontCollection;
     42    function GetDrawer(ASurface: TBGRACustomBitmap): TBGRAFreeTypeDrawer;
     43    function GetShaderLightPosition: TPoint;
     44    procedure SetShaderLightPosition(AValue: TPoint);
     45  protected
     46    FShaderOwner: boolean;
     47    FShader: TCustomPhongShading;
     48    procedure UpdateFont;
     49    procedure Init;
     50  public
     51    FontHinted: boolean;
     52
     53    ShaderActive: boolean;
     54
     55    ShadowVisible: boolean;
     56    ShadowColor: TBGRAPixel;
     57    ShadowRadius: integer;
     58    ShadowOffset: TPoint;
     59
     60    OutlineColor: TBGRAPixel;
     61    OutlineVisible,OuterOutlineOnly: boolean;
     62    OutlineTexture: IBGRAScanner;
     63
     64    constructor Create;
     65    constructor Create(AShader: TCustomPhongShading; AShaderOwner: boolean);
     66    function GetFontPixelMetric: TFontPixelMetric; override;
     67    procedure TextOutAngle({%H-}ADest: TBGRACustomBitmap; {%H-}x, {%H-}y: single; {%H-}orientation: integer; {%H-}s: string; {%H-}c: TBGRAPixel; {%H-}align: TAlignment); override;
     68    procedure TextOutAngle({%H-}ADest: TBGRACustomBitmap; {%H-}x, {%H-}y: single; {%H-}orientation: integer; {%H-}s: string; {%H-}texture: IBGRAScanner; {%H-}align: TAlignment); override;
     69    procedure TextOut(ADest: TBGRACustomBitmap; x, y: single; s: string; texture: IBGRAScanner; align: TAlignment); override;
     70    procedure TextOut(ADest: TBGRACustomBitmap; x, y: single; s: string; c: TBGRAPixel; align: TAlignment); override;
     71    procedure TextRect(ADest: TBGRACustomBitmap; ARect: TRect; x, y: integer; s: string; style: TTextStyle; c: TBGRAPixel); override;
     72    procedure TextRect(ADest: TBGRACustomBitmap; ARect: TRect; x, y: integer; s: string; style: TTextStyle; texture: IBGRAScanner); override;
     73    function TextSize(s: string): TSize; override;
     74    destructor Destroy; override;
     75    property Collection: TCustomFreeTypeFontCollection read GetCollection;
     76    property ShaderLightPosition: TPoint read GetShaderLightPosition write SetShaderLightPosition;
     77  end;
    1178
    1279  { TBGRAFreeTypeDrawer }
     
    1683    FMask: TBGRACustomBitmap;
    1784    FColor: TBGRAPixel;
     85    FInCreateTextEffect: boolean;
    1886    procedure RenderDirectly(x, y, tx: integer; data: pointer);
    1987    procedure RenderDirectlyClearType(x, y, tx: integer; data: pointer);
     88    function ShadowActuallyVisible :boolean;
     89    function OutlineActuallyVisible: boolean;
     90    function ShaderActuallyActive : boolean;
    2091  public
    2192    Destination: TBGRACustomBitmap;
    2293    ClearTypeRGBOrder: boolean;
     94    Texture: IBGRAScanner;
     95
     96    Shader: TCustomPhongShading;
     97    ShaderActive: boolean;
     98
     99    ShadowVisible: boolean;
     100    ShadowColor: TBGRAPixel;
     101    ShadowRadius: integer;
     102    ShadowOffset: TPoint;
     103
     104    OutlineColor: TBGRAPixel;
     105    OutlineVisible,OuterOutlineOnly: boolean;
     106    OutlineTexture: IBGRAScanner;
     107
    23108    constructor Create(ADestination: TBGRACustomBitmap);
    24109    procedure DrawText(AText: string; AFont: TFreeTypeRenderableFont; x,y: single; AColor: TFPColor); override; overload;
    25110    procedure DrawText(AText: string; AFont: TFreeTypeRenderableFont; x,y: single; AColor: TBGRAPixel); overload;
    26111    procedure DrawText(AText: string; AFont: TFreeTypeRenderableFont; x,y: single; AColor: TBGRAPixel; AAlign: TFreeTypeAlignments); overload;
     112    function CreateTextEffect(AText: string; AFont: TFreeTypeRenderableFont): TBGRATextEffect;
    27113    destructor Destroy; override;
    28114  end;
    29115
     116
    30117implementation
    31118
    32 uses LCLType, BGRABlend, BGRAText;
     119uses LCLType, BGRABlend, Math;
     120
     121{ TBGRAFreeTypeFontRenderer }
     122
     123function TBGRAFreeTypeFontRenderer.GetCollection: TCustomFreeTypeFontCollection;
     124begin
     125  result := EasyLazFreeType.FontCollection;
     126end;
     127
     128function TBGRAFreeTypeFontRenderer.GetDrawer(ASurface: TBGRACustomBitmap): TBGRAFreeTypeDrawer;
     129begin
     130  result := FDrawer;
     131  result.ShadowColor := ShadowColor;
     132  result.ShadowOffset := ShadowOffset;
     133  result.ShadowRadius := ShadowRadius;
     134  result.ShadowVisible := ShadowVisible;
     135  result.ClearTypeRGBOrder := FontQuality <> fqFineClearTypeBGR;
     136  result.Destination := ASurface;
     137  result.OutlineColor := OutlineColor;
     138  result.OutlineVisible := OutlineVisible;
     139  result.OuterOutlineOnly := OuterOutlineOnly;
     140  result.OutlineTexture := OutlineTexture;
     141  if ShaderActive then result.Shader := FShader
     142   else result.Shader := nil;
     143end;
     144
     145function TBGRAFreeTypeFontRenderer.GetShaderLightPosition: TPoint;
     146begin
     147  if FShader = nil then
     148    result := point(0,0)
     149  else
     150    result := FShader.LightPosition;
     151end;
     152
     153procedure TBGRAFreeTypeFontRenderer.SetShaderLightPosition(AValue: TPoint);
     154begin
     155  if FShader <> nil then
     156    FShader.LightPosition := AValue;
     157end;
     158
     159procedure TBGRAFreeTypeFontRenderer.UpdateFont;
     160var fts: TFreeTypeStyles;
     161begin
     162  fts := [];
     163  if fsBold in FontStyle then fts += [ftsBold];
     164  if fsItalic in FontStyle then fts += [ftsItalic];
     165  try
     166    {$IF (lcl_fullversion>=1010000)}
     167    FFont.SetNameAndStyle(FontName,fts);
     168    {$ELSE}
     169    FFont.Name := FontName;
     170    FFont.Style := fts;
     171    {$ENDIF}
     172  except
     173    on ex: exception do
     174    begin
     175    end;
     176  end;
     177  if FontEmHeight >= 0 then
     178    FFont.SizeInPixels := FontEmHeight
     179  else
     180    FFont.LineFullHeight := -FontEmHeight;
     181  case FontQuality of
     182    fqSystem:
     183    begin
     184      FFont.Quality := grqMonochrome;
     185      FFont.ClearType := false;
     186    end;
     187    fqSystemClearType:
     188    begin
     189      FFont.Quality:= grqLowQuality;
     190      FFont.ClearType:= true;
     191    end;
     192    fqFineAntialiasing:
     193    begin
     194      FFont.Quality:= grqHighQuality;
     195      FFont.ClearType:= false;
     196    end;
     197    fqFineClearTypeRGB,fqFineClearTypeBGR:
     198    begin
     199      FFont.Quality:= grqHighQuality;
     200      FFont.ClearType:= true;
     201    end;
     202  end;
     203  FFont.Hinted := FontHinted;
     204  {$IF (lcl_fullversion>=1010000)}
     205  FFont.StrikeOutDecoration := fsStrikeOut in FontStyle;
     206  FFont.UnderlineDecoration := fsUnderline in FontStyle;
     207  {$ENDIF}
     208end;
     209
     210procedure TBGRAFreeTypeFontRenderer.Init;
     211begin
     212  ShaderActive := true;
     213
     214  FDrawer := TBGRAFreeTypeDrawer.Create(nil);
     215  FFont := TFreeTypeFont.Create;
     216  FontHinted:= True;
     217
     218  ShadowColor := BGRABlack;
     219  ShadowVisible := false;
     220  ShadowOffset := Point(5,5);
     221  ShadowRadius := 5;
     222end;
     223
     224constructor TBGRAFreeTypeFontRenderer.Create;
     225begin
     226  Init;
     227end;
     228
     229constructor TBGRAFreeTypeFontRenderer.Create(AShader: TCustomPhongShading;
     230  AShaderOwner: boolean);
     231begin
     232  Init;
     233  FShader := AShader;
     234  FShaderOwner := AShaderOwner;
     235end;
     236
     237function TBGRAFreeTypeFontRenderer.GetFontPixelMetric: TFontPixelMetric;
     238begin
     239  UpdateFont;
     240  result.Baseline := round(FFont.Ascent);
     241  result.CapLine:= round(FFont.Ascent*0.2);
     242  result.DescentLine:= round(FFont.Ascent+FFont.Descent);
     243  result.Lineheight := round(FFont.LineFullHeight);
     244  result.xLine := round(FFont.Ascent*0.45);
     245  result.Defined := True;
     246end;
     247
     248procedure TBGRAFreeTypeFontRenderer.TextOutAngle(ADest: TBGRACustomBitmap; x,
     249  y: single; orientation: integer; s: string; c: TBGRAPixel; align: TAlignment);
     250begin
     251
     252end;
     253
     254procedure TBGRAFreeTypeFontRenderer.TextOutAngle(ADest: TBGRACustomBitmap; x,
     255  y: single; orientation: integer; s: string; texture: IBGRAScanner;
     256  align: TAlignment);
     257begin
     258
     259end;
     260
     261procedure TBGRAFreeTypeFontRenderer.TextOut(ADest: TBGRACustomBitmap; x,
     262  y: single; s: string; texture: IBGRAScanner; align: TAlignment);
     263begin
     264  FDrawer.Texture := texture;
     265  TextOut(ADest,x,y,s,BGRAWhite,align);
     266  FDrawer.Texture := nil;
     267end;
     268
     269procedure TBGRAFreeTypeFontRenderer.TextOut(ADest: TBGRACustomBitmap; x,
     270  y: single; s: string; c: TBGRAPixel; align: TAlignment);
     271var
     272  ftaAlign: TFreeTypeAlignments;
     273begin
     274  UpdateFont;
     275  ftaAlign:= [ftaTop];
     276  case align of
     277  taLeftJustify: ftaAlign += [ftaLeft];
     278  taCenter: ftaAlign += [ftaCenter];
     279  taRightJustify: ftaAlign += [ftaRight];
     280  end;
     281  GetDrawer(ADest).DrawText(s,FFont,x,y,BGRAToFPColor(c),ftaAlign);
     282end;
     283
     284procedure TBGRAFreeTypeFontRenderer.TextRect(ADest: TBGRACustomBitmap;
     285  ARect: TRect; x, y: integer; s: string; style: TTextStyle; c: TBGRAPixel);
     286var align: TFreeTypeAlignments;
     287    intersectedClip,previousClip: TRect;
     288begin
     289  previousClip := ADest.ClipRect;
     290  if style.Clipping then
     291  begin
     292    intersectedClip := rect(0,0,0,0);
     293    if not IntersectRect(intersectedClip, previousClip, ARect) then exit;
     294    ADest.ClipRect := intersectedClip;
     295  end;
     296  UpdateFont;
     297  align := [];
     298  case style.Alignment of
     299  taCenter: begin ARect.Left := x; align += [ftaCenter]; end;
     300  taRightJustify: begin ARect.Left := x; align += [ftaRight]; end;
     301  else
     302    align += [ftaLeft];
     303  end;
     304  case style.Layout of
     305  {$IF (lcl_fullversion>=1010000)}
     306  tlCenter: begin ARect.Top := y; align += [ftaVerticalCenter]; end;
     307  {$ENDIF}
     308  tlBottom: begin ARect.top := y; align += [ftaBottom]; end;
     309  else align += [ftaTop];
     310  end;
     311  try
     312    {$IF (lcl_fullversion>=1010000)}
     313    if style.Wordbreak then
     314      GetDrawer(ADest).DrawTextRect(s, FFont, ARect.Left,ARect.Top,ARect.Right,ARect.Bottom,BGRAToFPColor(c),align)
     315    else
     316    {$ENDIF}
     317    begin
     318      case style.Layout of
     319      tlCenter: y := (ARect.Top+ARect.Bottom) div 2;
     320      tlBottom: y := ARect.Bottom;
     321      else
     322        y := ARect.Top;
     323      end;
     324      case style.Alignment of
     325      taLeftJustify: GetDrawer(ADest).DrawText(s,FFont,ARect.Left,y,BGRAToFPColor(c),align);
     326      taCenter: GetDrawer(ADest).DrawText(s,FFont,(ARect.Left+ARect.Right-1) div 2,y,BGRAToFPColor(c),align);
     327      taRightJustify: GetDrawer(ADest).DrawText(s,FFont,ARect.Right,y,BGRAToFPColor(c),align);
     328      end;
     329    end;
     330  finally
     331    if style.Clipping then
     332      ADest.ClipRect := previousClip;
     333  end;
     334end;
     335
     336procedure TBGRAFreeTypeFontRenderer.TextRect(ADest: TBGRACustomBitmap;
     337  ARect: TRect; x, y: integer; s: string; style: TTextStyle;
     338  texture: IBGRAScanner);
     339begin
     340  FDrawer.Texture := texture;
     341  TextRect(ADest,ARect,x,y,s,style,BGRAWhite);
     342  FDrawer.Texture := nil;
     343end;
     344
     345function TBGRAFreeTypeFontRenderer.TextSize(s: string): TSize;
     346begin
     347  result.cx := round(FFont.TextWidth(s));
     348  result.cy := round(FFont.LineFullHeight);
     349end;
     350
     351destructor TBGRAFreeTypeFontRenderer.Destroy;
     352begin
     353  FDrawer.Free;
     354  FFont.Free;
     355  if FShaderOwner then FShader.Free;
     356  inherited Destroy;
     357end;
    33358
    34359{ TBGRAFreeTypeDrawer }
     
    45370    if (y < 0) or (y >= Destination.height) or (x < 0) or (x > Destination.width-tx) then exit;
    46371
    47     c := FColor;
    48372    psrc := pbyte(data);
    49373    pdest := Destination.ScanLine[y]+x;
    50     while tx > 0 do
    51     begin
    52       DrawPixelInlineWithAlphaCheck(pdest,c,psrc^);
    53       inc(psrc);
    54       inc(pdest);
    55       dec(tx);
     374    if Texture = nil then
     375    begin
     376      c := FColor;
     377      while tx > 0 do
     378      begin
     379        DrawPixelInlineWithAlphaCheck(pdest,c,psrc^);
     380        inc(psrc);
     381        inc(pdest);
     382        dec(tx);
     383      end;
     384    end else
     385    begin
     386      Texture.ScanMoveTo(x,y);
     387      while tx > 0 do
     388      begin
     389        DrawPixelInlineWithAlphaCheck(pdest,Texture.ScanNextPixel,psrc^);
     390        inc(psrc);
     391        inc(pdest);
     392        dec(tx);
     393      end;
    56394    end;
    57395  end;
     
    95433      pdest^.blue := ((psrc+1)^ + (psrc+2)^ + (psrc+2)^) div 3;
    96434    end;
    97     BGRAFillClearTypeRGBMask(Destination,x div 3,y,FMask,FColor,nil,ClearTypeRGBOrder);
    98   end;
     435    BGRAFillClearTypeRGBMask(Destination,x div 3,y,FMask,FColor,Texture,ClearTypeRGBOrder);
     436  end;
     437end;
     438
     439function TBGRAFreeTypeDrawer.ShadowActuallyVisible: boolean;
     440begin
     441  result := ShadowVisible and (ShadowColor.alpha <> 0);
     442end;
     443
     444function TBGRAFreeTypeDrawer.OutlineActuallyVisible: boolean;
     445begin
     446  result := ((OutlineTexture <> nil) or (OutlineColor.alpha <> 0)) and OutlineVisible;
     447end;
     448
     449function TBGRAFreeTypeDrawer.ShaderActuallyActive: boolean;
     450begin
     451  result := (Shader <> nil) and ShaderActive;
    99452end;
    100453
     
    103456  Destination := ADestination;
    104457  ClearTypeRGBOrder:= true;
     458  ShaderActive := true;
    105459end;
    106460
    107461procedure TBGRAFreeTypeDrawer.DrawText(AText: string;
    108462  AFont: TFreeTypeRenderableFont; x, y: single; AColor: TFPColor);
    109 begin
    110   FColor := FPColorToBGRA(AColor);
    111   if AFont.ClearType then
    112     AFont.RenderText(AText, x, y, Destination.ClipRect, @RenderDirectlyClearType)
    113   else
    114     AFont.RenderText(AText, x, y, Destination.ClipRect, @RenderDirectly);
     463var fx: TBGRATextEffect;
     464  procedure DoOutline;
     465  begin
     466    if OutlineActuallyVisible then
     467    begin
     468      if OutlineTexture <> nil then
     469        fx.DrawOutline(Destination,round(x),round(y), OutlineTexture)
     470      else
     471        fx.DrawOutline(Destination,round(x),round(y), OutlineColor);
     472    end;
     473  end;
     474begin
     475  if not FInCreateTextEffect and (ShadowActuallyVisible or OutlineActuallyVisible or ShaderActuallyActive) then
     476  begin
     477    fx := CreateTextEffect(AText, AFont);
     478    y -= AFont.Ascent;
     479    if ShadowActuallyVisible then fx.DrawShadow(Destination, round(x+ShadowOffset.X),round(y+ShadowOffset.Y), ShadowRadius, ShadowColor);
     480    if OuterOutlineOnly then DoOutline;
     481
     482    if texture <> nil then
     483    begin
     484      if ShaderActuallyActive then
     485        fx.DrawShaded(Destination,floor(x),floor(y), Shader, round(fx.TextSize.cy*0.05), texture)
     486      else
     487        fx.Draw(Destination,round(x),round(y), texture);
     488    end else
     489    begin
     490      if ShaderActuallyActive then
     491        fx.DrawShaded(Destination,floor(x),floor(y), Shader, round(fx.TextSize.cy*0.05), FPColorToBGRA(AColor))
     492      else
     493        fx.Draw(Destination,round(x),round(y), FPColorToBGRA(AColor));
     494    end;
     495    if not OuterOutlineOnly then DoOutline;
     496    fx.Free;
     497  end else
     498  begin
     499    FColor := FPColorToBGRA(AColor);
     500    if AFont.ClearType then
     501      AFont.RenderText(AText, x, y, Destination.ClipRect, @RenderDirectlyClearType)
     502    else
     503      AFont.RenderText(AText, x, y, Destination.ClipRect, @RenderDirectly);
     504  end;
    115505end;
    116506
     
    128518end;
    129519
     520function TBGRAFreeTypeDrawer.CreateTextEffect(AText: string;
     521  AFont: TFreeTypeRenderableFont): TBGRATextEffect;
     522var
     523  mask: TBGRACustomBitmap;
     524  tx,ty,marginHoriz,marginVert: integer;
     525  tempDest: TBGRACustomBitmap;
     526  tempTex: IBGRAScanner;
     527  tempClearType: boolean;
     528begin
     529  FInCreateTextEffect:= True;
     530  try
     531    tx := ceil(AFont.TextWidth(AText));
     532    ty := ceil(AFont.TextHeight(AText));
     533    marginHoriz := ty div 2;
     534    marginVert := 1;
     535    mask := BGRABitmapFactory.Create(tx+2*marginHoriz,ty+2*marginVert,BGRABlack);
     536    tempDest := Destination;
     537    tempTex := Texture;
     538    tempClearType:= AFont.ClearType;
     539    Destination := mask;
     540    Texture := nil;
     541    AFont.ClearType := false;
     542    DrawText(AText,AFont,marginHoriz,marginVert,BGRAWhite,[ftaTop,ftaLeft]);
     543    Destination := tempDest;
     544    Texture := tempTex;
     545    AFont.ClearType := tempClearType;
     546    mask.ConvertToLinearRGB;
     547    result := TBGRATextEffect.Create(mask, true,tx,ty,point(-marginHoriz,-marginVert));
     548  finally
     549    FInCreateTextEffect:= false;
     550  end;
     551end;
     552
    130553destructor TBGRAFreeTypeDrawer.Destroy;
    131554begin
Note: See TracChangeset for help on using the changeset viewer.