123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263 |
- //
- // The graphics engine GLXEngine. The unit of GXScene for Delphi
- //
- unit GXS.BitmapFont;
- (* Bitmap Fonts management classes *)
- interface
- {$I Stage.Defines.inc}
- uses
- Winapi.OpenGL,
- System.Classes,
- System.SysUtils,
- System.Types,
- System.UITypes,
- FMX.Objects,
- FMX.Graphics,
- FMX.Types,
- GXS.XOpenGL,
- GXS.PersistentClasses,
- GXS.Scene,
- Stage.VectorGeometry,
- GXS.Context,
- GXS.Texture,
- GXS.State,
- Stage.Utils,
- GXS.ImageUtils,
- GXS.Graphics,
- GXS.Color,
- GXS.BaseClasses,
- GXS.RenderContextInfo,
- Stage.TextureFormat,
- Stage.VectorTypes;
- type
- (* An individual character range in a bitmap font.
- A range allows mapping ASCII characters to character tiles in a font
- bitmap, tiles are enumerated line then column (raster). *)
- TgxBitmapFontRange = class(TCollectionItem)
- private
- function GetStartASCII: WideString;
- function GetStopASCII: WideString;
- protected
- FStartASCII, FStopASCII: WideChar;
- FStartGlyphIdx, FStopGlyphIdx, FCharCount: Integer;
- procedure SetStartASCII(const val: WideString);
- procedure SetStopASCII(const val: WideString);
- procedure SetStartGlyphIdx(val: Integer);
- function GetDisplayName: string; override;
- public
- constructor Create(Collection: TCollection); override;
- destructor Destroy; override;
- procedure Assign(Source: TPersistent); override;
- procedure NotifyChange;
- published
- property StartASCII: WideString read GetStartASCII write SetStartASCII;
- property StopASCII: WideString read GetStopASCII write SetStopASCII;
- property StartGlyphIdx: Integer read FStartGlyphIdx write SetStartGlyphIdx;
- property StopGlyphIdx: Integer read FStopGlyphIdx;
- property CharCount: Integer read FCharCount;
- end;
- TgxBitmapFontRanges = class(TCollection)
- private
- FCharCount: Integer;
- protected
- FOwner: TComponent;
- function GetOwner: TPersistent; override;
- procedure SetItems(index: Integer; const val: TgxBitmapFontRange);
- function GetItems(index: Integer): TgxBitmapFontRange;
- function CalcCharacterCount: Integer;
- procedure Update(Item: TCollectionItem); override;
- public
- constructor Create(AOwner: TComponent);
- destructor Destroy; override;
- function Add: TgxBitmapFontRange; overload;
- function Add(const StartASCII, StopASCII: WideChar)
- : TgxBitmapFontRange; overload;
- function Add(const StartASCII, StopASCII: AnsiChar)
- : TgxBitmapFontRange; overload;
- function FindItemID(ID: Integer): TgxBitmapFontRange;
- property Items[index: Integer]: TgxBitmapFontRange read GetItems
- write SetItems; default;
- (* Converts an ASCII character into a tile index.
- Return -1 if character cannot be rendered. *)
- function CharacterToTileIndex(aChar: WideChar): Integer;
- function TileIndexToChar(aIndex: Integer): WideChar;
- procedure NotifyChange;
- // Total number of characters in the ranges; cached for performance
- property CharacterCount: Integer read FCharCount;
- end;
- PCharInfo = ^TCharInfo;
- TCharInfo = record
- l, t, w: word;
- end;
- (* Provides access to individual characters in a BitmapFont.
- Only fixed-width bitmap fonts are supported, the characters are enumerated
- in a raster fashion (line then column).
- Transparency is all or nothing, the transparent color being that of the
- top left pixel of the Glyphs bitmap.
- Performance note: as usual, for best performance, you base font bitmap
- dimensions should be close to a power of two, and have at least 1 pixel
- spacing between characters (horizontally and vertically) to avoid artefacts
- when rendering with linear filtering. *)
- TgxCustomBitmapFont = class(TgxUpdateAbleComponent)
- private
- FRanges: TgxBitmapFontRanges;
- FGlyphs: TImage;
- FCharWidth, FCharHeight: Integer;
- FGlyphsIntervalX, FGlyphsIntervalY: Integer;
- FHSpace, FVSpace, FHSpaceFix: Integer;
- FUsers: TList;
- FMinFilter: TgxMinFilter;
- FMagFilter: TgxMagFilter;
- FTextureWidth, FTextureHeight: Integer;
- FTextRows, FTextCols: Integer;
- FGlyphsAlpha: TgxTextureImageAlpha;
- FTextures: TList;
- FTextureModified: boolean;
- FLastTexture: TgxTextureHandle;
- protected
- FChars: array of TCharInfo;
- FCharsLoaded: boolean;
- procedure ResetCharWidths(w: Integer = -1);
- procedure SetCharWidths(index, value: Integer);
- procedure SetRanges(const val: TgxBitmapFontRanges);
- procedure SetGlyphs(const val: TImage);
- procedure SetCharWidth(const val: Integer);
- procedure SetCharHeight(const val: Integer);
- procedure SetGlyphsIntervalX(const val: Integer);
- procedure SetGlyphsIntervalY(const val: Integer);
- procedure OnGlyphsChanged(Sender: TObject);
- procedure SetHSpace(const val: Integer);
- procedure SetVSpace(const val: Integer);
- procedure SetMagFilter(AValue: TgxMagFilter);
- procedure SetMinFilter(AValue: TgxMinFilter);
- procedure SetGlyphsAlpha(val: TgxTextureImageAlpha);
- procedure TextureChanged;
- procedure FreeTextureHandle; virtual;
- function TextureFormat: Integer; virtual;
- procedure InvalidateUsers;
- function CharactersPerRow: Integer;
- procedure GetCharTexCoords(Ch: WideChar;
- var TopLeft, BottomRight: TTexPoint);
- procedure GetICharTexCoords(var ARci: TgxRenderContextInfo; Chi: Integer;
- out TopLeft, BottomRight: TTexPoint);
- procedure PrepareImage(var ARci: TgxRenderContextInfo); virtual;
- procedure PrepareParams(var ARci: TgxRenderContextInfo);
- (* A single bitmap containing all the characters.
- The transparent color is that of the top left pixel. *)
- property Glyphs: TImage read FGlyphs write SetGlyphs;
- // Nb of horizontal pixels between two columns in the Glyphs.
- property GlyphsIntervalX: Integer read FGlyphsIntervalX
- write SetGlyphsIntervalX;
- // Nb of vertical pixels between two rows in the Glyphs.
- property GlyphsIntervalY: Integer read FGlyphsIntervalY
- write SetGlyphsIntervalY;
- (* Ranges allow converting between ASCII and tile indexes.
- See TgxCustomBitmapFontRange. *)
- property Ranges: TgxBitmapFontRanges read FRanges write SetRanges;
- // Width of a single character.
- property CharWidth: Integer read FCharWidth write SetCharWidth default 16;
- // Pixels in between rendered characters (horizontally).
- property HSpace: Integer read FHSpace write SetHSpace default 1;
- // Pixels in between rendered lines (vertically).
- property VSpace: Integer read FVSpace write SetVSpace default 1;
- (* Horizontal spacing fix offset.
- This property is for internal use, and is added to the hspacing
- of each character when rendering, typically to fix extra spacing. *)
- property HSpaceFix: Integer read FHSpaceFix write FHSpaceFix;
- property MagFilter: TgxMagFilter read FMagFilter write SetMagFilter
- default maLinear;
- property MinFilter: TgxMinFilter read FMinFilter write SetMinFilter
- default miLinear;
- property GlyphsAlpha: TgxTextureImageAlpha read FGlyphsAlpha
- write FGlyphsAlpha default tiaDefault;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure RegisterUser(anObject: TgxBaseSceneObject); virtual;
- procedure UnRegisterUser(anObject: TgxBaseSceneObject); virtual;
- (* Renders the given string at current position or at position given by the optional position variable.
- The current matrix is blindly used, meaning you can render all kinds
- of rotated and linear distorted text with this method, OpenGL
- Enable states are also possibly altered. *)
- procedure RenderString(var ARci: TgxRenderContextInfo;
- const aText: UnicodeString; aAlignment: TAlignment;
- aLayout: TgxTextLayout; const aColor: TgxColorVector;
- aPosition: PVector4f = nil; aReverseY: boolean = False); overload; virtual;
- (* A simpler canvas-style TextOut helper for RenderString.
- The rendering is reversed along Y by default, to allow direct use
- with TgxCanvas *)
- procedure TextOut(var rci: TgxRenderContextInfo; X, Y: Single;
- const Text: UnicodeString; const Color: TgxColorVector); overload;
- procedure TextOut(var rci: TgxRenderContextInfo; X, Y: Single;
- const Text: UnicodeString; const Color: TColor); overload;
- function TextWidth(const Text: UnicodeString): Integer;
- function CharacterToTileIndex(aChar: WideChar): Integer; virtual;
- function TileIndexToChar(aIndex: Integer): WideChar; virtual;
- function CharacterCount: Integer; virtual;
- // Get the actual width for this char.
- function GetCharWidth(Ch: WideChar): Integer;
- // Get the actual pixel width for this string.
- function CalcStringWidth(const aText: UnicodeString): Integer;
- overload; virtual;
- // make texture if needed
- procedure CheckTexture(var ARci: TgxRenderContextInfo);
- // Height of a single character.
- property CharHeight: Integer read FCharHeight write SetCharHeight
- default 16;
- property TextureWidth: Integer read FTextureWidth write FTextureWidth;
- property TextureHeight: Integer read FTextureHeight write FTextureHeight;
- end;
- (* See TgxCustomBitmapFont.
- This class only publuishes some of the properties. *)
- TgxBitmapFont = class(TgxCustomBitmapFont)
- published
- property Glyphs;
- property GlyphsIntervalX;
- property GlyphsIntervalY;
- property Ranges;
- property CharWidth;
- property CharHeight;
- property HSpace;
- property VSpace;
- property MagFilter;
- property MinFilter;
- property GlyphsAlpha;
- end;
- TgxFlatTextOption = (ftoTwoSided);
- TgxFlatTextOptions = set of TgxFlatTextOption;
- (* A 2D text displayed and positionned in 3D coordinates.
- The FlatText uses a character font defined and stored by a TgxBitmapFont
- component. Default character scale is 1 font pixel = 1 space unit. *)
- TgxFlatText = class(TgxImmaterialSceneObject)
- private
- FBitmapFont: TgxCustomBitmapFont;
- FText: UnicodeString;
- FAlignment: TAlignment;
- FLayout: TgxTextLayout;
- FModulateColor: TgxColor;
- FOptions: TgxFlatTextOptions;
- protected
- procedure SetBitmapFont(const val: TgxCustomBitmapFont);
- procedure SetText(const val: UnicodeString);
- procedure SetAlignment(const val: TAlignment);
- procedure SetLayout(const val: TgxTextLayout);
- procedure SetModulateColor(const val: TgxColor);
- procedure SetOptions(const val: TgxFlatTextOptions);
- procedure Notification(AComponent: TComponent;
- Operation: TOperation); override;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure DoRender(var rci: TgxRenderContextInfo;
- renderSelf, renderChildren: boolean); override;
- procedure Assign(Source: TPersistent); override;
- published
- (* Refers the bitmap font to use.
- The referred bitmap font component stores and allows access to
- individual character bitmaps. *)
- property BitmapFont: TgxCustomBitmapFont read FBitmapFont
- write SetBitmapFont;
- (* Text to render.
- Be aware that only the characters available in the bitmap font will
- be rendered. CR LF sequences are allowed. *)
- property Text: UnicodeString read FText write SetText;
- (* Controls the text alignment (horizontal).
- Possible values : taLeftJustify, taRightJustify, taCenter *)
- property Alignment: TAlignment read FAlignment write SetAlignment;
- (* Controls the text layout (vertical).
- Possible values : tlTop, tlCenter, tlBottom *)
- property Layout: TgxTextLayout read FLayout write SetLayout;
- // Color modulation, can be used for fade in/out too.
- property ModulateColor: TgxColor read FModulateColor write SetModulateColor;
- (* Flat text options.
- ftoTwoSided : when set the text will be visible from its two
- sides even if faceculling is on (at the scene-level). *)
- property Options: TgxFlatTextOptions read FOptions write SetOptions;
- end;
- // ------------------------------------------------------------------
- implementation
- // ------------------------------------------------------------------
- // ------------------
- // ------------------ TgxBitmapFontRange ------------------
- // ------------------
- constructor TgxBitmapFontRange.Create(Collection: TCollection);
- begin
- inherited Create(Collection);
- end;
- destructor TgxBitmapFontRange.Destroy;
- begin
- inherited;
- end;
- procedure TgxBitmapFontRange.Assign(Source: TPersistent);
- begin
- if Source is TgxBitmapFontRange then
- begin
- FStartASCII := TgxBitmapFontRange(Source).FStartASCII;
- FStopASCII := TgxBitmapFontRange(Source).FStopASCII;
- FStartGlyphIdx := TgxBitmapFontRange(Source).FStartGlyphIdx;
- NotifyChange;
- end
- else
- inherited;
- end;
- procedure TgxBitmapFontRange.NotifyChange;
- begin
- FCharCount := Integer(FStopASCII) - Integer(FStartASCII) + 1;
- FStopGlyphIdx := FStartGlyphIdx + FCharCount - 1;
- if Assigned(Collection) then
- (Collection as TgxBitmapFontRanges).NotifyChange;
- end;
- function TgxBitmapFontRange.GetDisplayName: string;
- begin
- Result := Format('ASCII [#%d, #%d] -> Glyphs [%d, %d]',
- [Integer(FStartASCII), Integer(FStopASCII), StartGlyphIdx, StopGlyphIdx]);
- end;
- function TgxBitmapFontRange.GetStartASCII: WideString;
- begin
- Result := FStartASCII;
- end;
- function TgxBitmapFontRange.GetStopASCII: WideString;
- begin
- Result := FStopASCII;
- end;
- procedure TgxBitmapFontRange.SetStartASCII(const val: WideString);
- begin
- if (Length(val) > 0) and (val[1] <> FStartASCII) then
- begin
- FStartASCII := val[1];
- if FStartASCII > FStopASCII then
- FStopASCII := FStartASCII;
- NotifyChange;
- end;
- end;
- procedure TgxBitmapFontRange.SetStopASCII(const val: WideString);
- begin
- if (Length(val) > 0) and (FStopASCII <> val[1]) then
- begin
- FStopASCII := val[1];
- if FStopASCII < FStartASCII then
- FStartASCII := FStopASCII;
- NotifyChange;
- end;
- end;
- procedure TgxBitmapFontRange.SetStartGlyphIdx(val: Integer);
- begin
- val := MaxInteger(0, val);
- if val <> FStartGlyphIdx then
- begin
- FStartGlyphIdx := val;
- NotifyChange;
- end;
- end;
- // ------------------
- // ------------------ TgxBitmapFontRanges ------------------
- // ------------------
- constructor TgxBitmapFontRanges.Create(AOwner: TComponent);
- begin
- FOwner := AOwner;
- inherited Create(TgxBitmapFontRange);
- end;
- destructor TgxBitmapFontRanges.Destroy;
- begin
- inherited;
- end;
- function TgxBitmapFontRanges.GetOwner: TPersistent;
- begin
- Result := FOwner;
- end;
- procedure TgxBitmapFontRanges.SetItems(index: Integer;
- const val: TgxBitmapFontRange);
- begin
- inherited Items[index] := val;
- end;
- function TgxBitmapFontRanges.GetItems(index: Integer): TgxBitmapFontRange;
- begin
- Result := TgxBitmapFontRange(inherited Items[index]);
- end;
- function TgxBitmapFontRanges.Add: TgxBitmapFontRange;
- begin
- Result := (inherited Add) as TgxBitmapFontRange;
- end;
- function TgxBitmapFontRanges.Add(const StartASCII, StopASCII: WideChar)
- : TgxBitmapFontRange;
- begin
- Result := Add;
- Result.StartASCII := StartASCII;
- Result.StopASCII := StopASCII;
- end;
- function TgxBitmapFontRanges.Add(const StartASCII, StopASCII: AnsiChar)
- : TgxBitmapFontRange;
- begin
- Result := Add(CharToWideChar(StartASCII), CharToWideChar(StopASCII));
- end;
- function TgxBitmapFontRanges.FindItemID(ID: Integer): TgxBitmapFontRange;
- begin
- Result := (inherited FindItemID(ID)) as TgxBitmapFontRange;
- end;
- function TgxBitmapFontRanges.CharacterToTileIndex(aChar: WideChar): Integer;
- var
- i: Integer;
- begin
- Result := -1;
- for i := 0 to Count - 1 do
- with Items[i] do
- begin
- if (aChar >= FStartASCII) and (aChar <= FStopASCII) then
- begin
- Result := StartGlyphIdx + Integer(aChar) - Integer(FStartASCII);
- Break;
- end;
- end;
- end;
- function TgxBitmapFontRanges.TileIndexToChar(aIndex: Integer): WideChar;
- var
- i: Integer;
- begin
- Result := #0;
- for i := 0 to Count - 1 do
- with Items[i] do
- begin
- if (aIndex >= StartGlyphIdx) and (aIndex <= StopGlyphIdx) then
- begin
- Result := WideChar(aIndex - StartGlyphIdx + Integer(FStartASCII));
- Break;
- end;
- end;
- end;
- procedure TgxBitmapFontRanges.Update(Item: TCollectionItem);
- begin
- inherited;
- NotifyChange;
- end;
- procedure TgxBitmapFontRanges.NotifyChange;
- begin
- FCharCount := CalcCharacterCount;
- if Assigned(FOwner) then
- begin
- if FOwner is TgxBaseSceneObject then
- TgxBaseSceneObject(FOwner).StructureChanged
- else if FOwner is TgxCustomBitmapFont then
- TgxCustomBitmapFont(FOwner).NotifyChange(Self);
- end;
- end;
- function TgxBitmapFontRanges.CalcCharacterCount: Integer;
- var
- i: Integer;
- begin
- Result := 0;
- for i := 0 to Count - 1 do
- with Items[i] do
- Inc(Result, Integer(FStopASCII) - Integer(FStartASCII) + 1);
- end;
- // ------------------
- // ------------------ TgxCustomBitmapFont ------------------
- // ------------------
- constructor TgxCustomBitmapFont.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- FRanges := TgxBitmapFontRanges.Create(Self);
- FGlyphs := TImage.Create(AOwner);
- FGlyphs.Bitmap.OnChange := OnGlyphsChanged;
- FCharWidth := 16;
- FCharHeight := 16;
- FHSpace := 1;
- FVSpace := 1;
- FUsers := TList.Create;
- FMinFilter := miLinear;
- FMagFilter := maLinear;
- FTextures := TList.Create;
- FTextureModified := true;
- end;
- destructor TgxCustomBitmapFont.Destroy;
- begin
- FreeTextureHandle;
- inherited Destroy;
- FTextures.Free;
- FRanges.Free;
- FGlyphs.Free;
- Assert(FUsers.Count = 0);
- FUsers.Free;
- end;
- function TgxCustomBitmapFont.GetCharWidth(Ch: WideChar): Integer;
- var
- chi: Integer;
- begin
- chi := CharacterToTileIndex(ch);
- if Length(FChars) = 0 then
- ResetCharWidths;
- if chi >= 0 then
- Result := FChars[chi].w
- else
- Result := 0;
- end;
- function TgxCustomBitmapFont.CalcStringWidth(const aText
- : UnicodeString): Integer;
- var
- i: Integer;
- begin
- if aText <> '' then
- begin
- Result := -HSpace + Length(aText) * (HSpaceFix + HSpace);
- for i := 1 to Length(aText) do
- Result := Result + GetCharWidth(aText[i]);
- end
- else
- Result := 0;
- end;
- procedure TgxCustomBitmapFont.ResetCharWidths(w: Integer = -1);
- var
- i: Integer;
- begin
- FCharsLoaded := False;
- i := CharacterCount;
- if Length(FChars) < i then
- SetLength(FChars, i);
- if w < 0 then
- w := CharWidth;
- for i := 0 to High(FChars) do
- FChars[i].w := w;
- end;
- procedure TgxCustomBitmapFont.SetCharWidths(index, value: Integer);
- begin
- if index >= 0 then
- FChars[index].w := value;
- end;
- procedure TgxCustomBitmapFont.SetRanges(const val: TgxBitmapFontRanges);
- begin
- FRanges.Assign(val);
- InvalidateUsers;
- end;
- procedure TgxCustomBitmapFont.SetGlyphs(const val: TImage);
- begin
- FGlyphs.Assign(val);
- end;
- procedure TgxCustomBitmapFont.SetCharWidth(const val: Integer);
- begin
- if val <> FCharWidth then
- begin
- if val > 1 then
- FCharWidth := val
- else
- FCharWidth := 1;
- InvalidateUsers;
- end;
- end;
- procedure TgxCustomBitmapFont.SetCharHeight(const val: Integer);
- begin
- if val <> FCharHeight then
- begin
- if val > 1 then
- FCharHeight := val
- else
- FCharHeight := 1;
- InvalidateUsers;
- end;
- end;
- procedure TgxCustomBitmapFont.SetGlyphsIntervalX(const val: Integer);
- begin
- if val > 0 then
- FGlyphsIntervalX := val
- else
- FGlyphsIntervalX := 0;
- InvalidateUsers;
- end;
- procedure TgxCustomBitmapFont.SetGlyphsIntervalY(const val: Integer);
- begin
- if val > 0 then
- FGlyphsIntervalY := val
- else
- FGlyphsIntervalY := 0;
- InvalidateUsers;
- end;
- procedure TgxCustomBitmapFont.SetHSpace(const val: Integer);
- begin
- if val <> FHSpace then
- begin
- FHSpace := val;
- InvalidateUsers;
- end;
- end;
- procedure TgxCustomBitmapFont.SetVSpace(const val: Integer);
- begin
- if val <> FVSpace then
- begin
- FVSpace := val;
- InvalidateUsers;
- end;
- end;
- procedure TgxCustomBitmapFont.SetMagFilter(AValue: TgxMagFilter);
- begin
- if AValue <> FMagFilter then
- begin
- FMagFilter := AValue;
- TextureChanged;
- InvalidateUsers;
- end;
- end;
- procedure TgxCustomBitmapFont.SetMinFilter(AValue: TgxMinFilter);
- begin
- if AValue <> FMinFilter then
- begin
- FMinFilter := AValue;
- TextureChanged;
- InvalidateUsers;
- end;
- end;
- procedure TgxCustomBitmapFont.SetGlyphsAlpha(val: TgxTextureImageAlpha);
- begin
- if val <> FGlyphsAlpha then
- begin
- FGlyphsAlpha := val;
- TextureChanged;
- InvalidateUsers;
- end;
- end;
- procedure TgxCustomBitmapFont.OnGlyphsChanged(Sender: TObject);
- begin
- InvalidateUsers;
- // when empty, width is 0 and roundup give 1
- if not Glyphs.Bitmap.IsEmpty then
- begin
- if FTextureWidth = 0 then
- FTextureWidth := RoundUpToPowerOf2(Glyphs.Bitmap.Width);
- if FTextureHeight = 0 then
- FTextureHeight := RoundUpToPowerOf2(Glyphs.Bitmap.Height);
- end;
- end;
- procedure TgxCustomBitmapFont.RegisterUser(anObject: TgxBaseSceneObject);
- begin
- Assert(FUsers.IndexOf(anObject) < 0);
- FUsers.Add(anObject);
- end;
- procedure TgxCustomBitmapFont.UnRegisterUser(anObject: TgxBaseSceneObject);
- begin
- FUsers.Remove(anObject);
- end;
- procedure TgxCustomBitmapFont.PrepareImage(var ARci: TgxRenderContextInfo);
- var
- bitmap: TBitmap;
- bitmap32: TgxBitmap32;
- cap: Integer;
- X, Y, w, h: Integer;
- t: TgxTextureHandle;
- begin
- // only check when really used
- if FTextureWidth = 0 then
- begin
- FTextureWidth := ARci.gxStates.MaxTextureSize;
- if FTextureWidth > 512 then
- FTextureWidth := 512;
- if FTextureWidth < 64 then
- FTextureWidth := 64;
- end;
- if FTextureHeight = 0 then
- begin
- FTextureHeight := ARci.gxStates.MaxTextureSize;
- if FTextureHeight > 512 then
- FTextureHeight := 512;
- if FTextureHeight < 64 then
- FTextureHeight := 64;
- end;
- X := 0;
- Y := 0;
- w := Glyphs.Bitmap.Width;
- h := Glyphs.Bitmap.Height;
- // was an error...
- FTextRows := 1 + (h - 1) div FTextureHeight;
- FTextCols := 1 + (w - 1) div FTextureWidth;
- bitmap := TBitmap.Create;
- with bitmap do
- begin
- {$IFDEF MSWINDOWS}
- { TODO : E2129 Cannot assign to a read-only property }
- (*PixelFormat := TPixelFormat.RGBA32F;*)
- {$ENDIF}
- Width := RoundUpToPowerOf2(FTextureWidth);
- Height := RoundUpToPowerOf2(FTextureHeight);
- end;
- bitmap32 := TgxBitmap32.Create;
- while (X < w) and (Y < h) do
- begin
- t := TgxTextureHandle.Create;
- FTextures.Add(t);
- // prepare handle
- t.AllocateHandle;
- // texture registration
- t.Target := ttTexture2D;
- ARci.gxStates.TextureBinding[0, ttTexture2D] := t.Handle;
- // copy data
- { TODO : E2003 Undeclared identifier: 'Draw', need to use DrawBitmap() }
- (*bitmap.Canvas.Draw(-X, -Y, Glyphs.Bitmap);*)
- // Clipboard.Assign(bitmap);
- bitmap32.Assign(bitmap);
- bitmap32.Narrow;
- with bitmap32 do
- begin
- case FGlyphsAlpha of
- tiaAlphaFromIntensity:
- SetAlphaFromIntensity;
- tiaSuperBlackTransparent:
- SetAlphaTransparentForColor($000000);
- tiaLuminance:
- SetAlphaFromIntensity;
- tiaLuminanceSqrt:
- begin
- SetAlphaFromIntensity;
- SqrtAlpha;
- end;
- tiaOpaque:
- SetAlphaToValue(255);
- tiaDefault, tiaTopLeftPointColorTransparent:
- SetAlphaTransparentForColor(Data[Width * (Height - 1)]);
- else
- Assert(False);
- end;
- RegisterAsOpenRXTexture(t, not(FMinFilter in [miNearest, miLinear]),
- TextureFormat, cap, cap, cap);
- end;
- PrepareParams(ARci);
- t.NotifyDataUpdated;
- Inc(X, FTextureWidth);
- if X >= w then
- begin
- Inc(Y, FTextureHeight);
- X := 0;
- end;
- end;
- bitmap.Free;
- bitmap32.Free;
- end;
- procedure TgxCustomBitmapFont.PrepareParams(var ARci: TgxRenderContextInfo);
- const
- cTextureMagFilter: array [maNearest .. maLinear] of Cardinal = (GL_NEAREST, GL_LINEAR);
- cTextureMinFilter: array [miNearest .. miLinearMipmapLinear] of Cardinal =
- (GL_NEAREST, GL_LINEAR, GL_NEAREST_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_NEAREST,
- GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR_MIPMAP_LINEAR);
- begin
- with ARci.gxStates do
- begin
- UnpackAlignment := 4;
- UnpackRowLength := 0;
- UnpackSkipRows := 0;
- UnpackSkipPixels := 0;
- end;
- begin
- glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, cTextureMinFilter[FMinFilter]);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, cTextureMagFilter[FMagFilter]);
- end;
- end;
- function TgxCustomBitmapFont.TileIndexToChar(aIndex: Integer): WideChar;
- begin
- Result := FRanges.TileIndexToChar(aIndex);
- end;
- function TgxCustomBitmapFont.CharacterToTileIndex(aChar: WideChar): Integer;
- begin
- Result := FRanges.CharacterToTileIndex(aChar);
- end;
- procedure TgxCustomBitmapFont.RenderString(var ARci: TgxRenderContextInfo;
- const aText: UnicodeString; aAlignment: TAlignment; aLayout: TgxTextLayout;
- const aColor: TgxColorVector; aPosition: PVector4f = nil;
- aReverseY: boolean = False);
- function AlignmentAdjustement(p: Integer): Single;
- var
- i: Integer;
- begin
- i := 0;
- while (p <= Length(aText)) and (aText[p] <> #13) do
- begin
- Inc(p);
- Inc(i);
- end;
- case aAlignment of
- taLeftJustify:
- Result := 0;
- taRightJustify:
- Result := -CalcStringWidth(Copy(aText, p - i, i))
- else // taCenter
- Result := Round(-CalcStringWidth(Copy(aText, p - i, i)) * 0.5);
- end;
- end;
- function LayoutAdjustement: Single;
- var
- i, n: Integer;
- begin
- n := 1;
- for i := 1 to Length(aText) do
- if aText[i] = #13 then
- Inc(n);
- case aLayout of
- tlTop: Result := 0;
- tlBottom: Result := (n * (CharHeight + VSpace) - VSpace);
- else // tlCenter
- Result := Round((n * (CharHeight + VSpace) - VSpace) * 0.5);
- end;
- end;
- var
- i, chi: Integer;
- pch: PCharInfo;
- TopLeft, BottomRight: TTexPoint;
- vTopLeft, vBottomRight: TVector4f;
- deltaV, spaceDeltaH: Single;
- currentChar: WideChar;
- begin
- if (aText = '') then
- Exit;
- // prepare texture if necessary
- CheckTexture(ARci);
- // precalcs
- if Assigned(aPosition) then
- MakePoint(vTopLeft, aPosition.X + AlignmentAdjustement(1),
- aPosition.Y + LayoutAdjustement, 0)
- else
- MakePoint(vTopLeft, AlignmentAdjustement(1), LayoutAdjustement, 0);
- deltaV := -(CharHeight + VSpace);
- if aReverseY then
- vBottomRight.Y := vTopLeft.Y + CharHeight
- else
- vBottomRight.Y := vTopLeft.Y - CharHeight;
- vBottomRight.Z := 0;
- vBottomRight.W := 1;
- spaceDeltaH := GetCharWidth(#32) + HSpaceFix + HSpace;
- // set states
- with ARci.gxStates do
- begin
- ActiveTextureEnabled[ttTexture2D] := true;
- Disable(stLighting);
- Enable(stBlend);
- SetBlendFunc(bfSrcAlpha, bfOneMinusSrcAlpha);
- FLastTexture := nil;
- end;
- // start rendering
- glColor4fv(@aColor);
- glBegin(GL_QUADS);
- for i := 1 to Length(aText) do
- begin
- currentChar := WideChar(aText[i]);
- case currentChar of
- #0 .. #12, #14 .. #31:
- ; // ignore
- #13:
- begin
- if Assigned(aPosition) then
- vTopLeft.X := aPosition.X + AlignmentAdjustement(i + 1)
- else
- vTopLeft.X := AlignmentAdjustement(i + 1);
- vTopLeft.Y := vTopLeft.Y + deltaV;
- if aReverseY then
- vBottomRight.Y := vTopLeft.Y + CharHeight
- else
- vBottomRight.Y := vTopLeft.Y - CharHeight;
- end;
- #32:
- vTopLeft.X := vTopLeft.X + spaceDeltaH;
- else
- chi := CharacterToTileIndex(currentChar);
- if chi < 0 then
- continue; // not found
- pch := @FChars[chi];
- if pch.w > 0 then
- begin
- GetICharTexCoords(ARci, chi, TopLeft, BottomRight);
- vBottomRight.X := vTopLeft.X + pch.w;
- glTexCoord2fv(@TopLeft);
- glVertex4fv(@vTopLeft);
- glTexCoord2f(TopLeft.S, BottomRight.t);
- glVertex2f(vTopLeft.X, vBottomRight.Y);
- glTexCoord2fv(@BottomRight);
- glVertex4fv(@vBottomRight);
- glTexCoord2f(BottomRight.S, TopLeft.t);
- glVertex2f(vBottomRight.X, vTopLeft.Y);
- vTopLeft.X := vTopLeft.X + pch.w + HSpace;
- end;
- end;
- end;
- glEnd;
- // unbind texture
- ARci.gxStates.TextureBinding[0, ttTexture2D] := 0;
- ARci.gxStates.ActiveTextureEnabled[ttTexture2D] := False;
- end;
- procedure TgxCustomBitmapFont.TextOut(var rci: TgxRenderContextInfo; X, Y: Single;
- const Text: UnicodeString; const Color: TgxColorVector);
- var
- V: TVector4f;
- begin
- V.X := X;
- V.Y := Y;
- V.Z := 0;
- V.W := 1;
- ///? RenderString(rci, Text, taLeftJustify, tlTop, Color, @V, true);
- end;
- procedure TgxCustomBitmapFont.TextOut(var rci: TgxRenderContextInfo; X, Y: Single;
- const Text: UnicodeString; const Color: TColor);
- begin
- TextOut(rci, X, Y, Text, ConvertWinColor(Color));
- end;
- function TgxCustomBitmapFont.TextWidth(const Text: UnicodeString): Integer;
- begin
- Result := CalcStringWidth(Text);
- end;
- function TgxCustomBitmapFont.CharactersPerRow: Integer;
- begin
- if FGlyphs.Bitmap.Width > 0 then
- Result := (FGlyphs.Bitmap.Width + FGlyphsIntervalX)
- div (FGlyphsIntervalX + FCharWidth)
- else
- Result := 0;
- end;
- function TgxCustomBitmapFont.CharacterCount: Integer;
- begin
- Result := FRanges.CharacterCount;
- end;
- procedure TgxCustomBitmapFont.GetCharTexCoords(Ch: WideChar;
- var TopLeft, BottomRight: TTexPoint);
- var
- chi, tileIndex: Integer;
- ci: TCharInfo;
- r: Integer;
- begin
- chi := CharacterToTileIndex(ch);
- if not FCharsLoaded then
- begin
- ResetCharWidths;
- FCharsLoaded := true;
- r := CharactersPerRow;
- for tileIndex := 0 to CharacterCount - 1 do
- begin
- FChars[tileIndex].l := (tileIndex mod r) * (CharWidth + GlyphsIntervalX);
- FChars[tileIndex].t := (tileIndex div r) * (CharHeight + GlyphsIntervalY);
- end;
- end;
- if (chi < 0) or (chi >= CharacterCount) then
- begin
- // invalid char
- TopLeft := NullTexPoint;
- BottomRight := NullTexPoint;
- Exit;
- end;
- ci := FChars[chi];
- ci.l := ci.l mod FTextureWidth;
- ci.t := ci.t mod FTextureHeight;
- TopLeft.S := ci.l / FTextureWidth;
- TopLeft.t := 1 - ci.t / FTextureHeight;
- BottomRight.S := (ci.l + ci.w) / FTextureWidth;
- BottomRight.t := 1 - (ci.t + CharHeight) / FTextureHeight;
- end;
- // TileIndexToTexCoords it also activates the target texture
- procedure TgxCustomBitmapFont.GetICharTexCoords(var ARci: TgxRenderContextInfo;
- Chi: Integer; out TopLeft, BottomRight: TTexPoint);
- var
- tileIndex: Integer;
- ci: TCharInfo;
- t: TgxTextureHandle;
- r, c: Integer;
- begin
- if not FCharsLoaded then
- begin
- r := CharactersPerRow;
- if r = 0 then
- Exit;
- ResetCharWidths;
- FCharsLoaded := true;
- for tileIndex := 0 to CharacterCount - 1 do
- begin
- FChars[tileIndex].l := (tileIndex mod r) * (CharWidth + GlyphsIntervalX);
- FChars[tileIndex].t := (tileIndex div r) * (CharHeight + GlyphsIntervalY);
- end;
- end;
- if (chi < 0) or (chi >= CharacterCount) then
- begin
- // invalid char
- TopLeft := NullTexPoint;
- BottomRight := NullTexPoint;
- Exit;
- end;
- ci := FChars[chi];
- c := ci.l div FTextureWidth;
- r := ci.t div FTextureHeight;
- ci.l := ci.l mod FTextureWidth;
- ci.t := ci.t mod FTextureHeight;
- t := FTextures[r * FTextCols + c];
- TopLeft.S := ci.l / FTextureWidth;
- TopLeft.t := 1 - ci.t / FTextureHeight;
- BottomRight.S := (ci.l + ci.w) / FTextureWidth;
- BottomRight.t := 1 - (ci.t + CharHeight) / FTextureHeight;
- if t <> FLastTexture then
- begin
- FLastTexture := t;
- glEnd;
- ARci.gxStates.TextureBinding[0, ttTexture2D] := t.Handle;
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
- glBegin(GL_QUADS);
- end;
- end;
- procedure TgxCustomBitmapFont.InvalidateUsers;
- var
- i: Integer;
- begin
- FCharsLoaded := False;
- FTextureModified := true;
- for i := FUsers.Count - 1 downto 0 do
- TgxBaseSceneObject(FUsers[i]).NotifyChange(Self);
- end;
- procedure TgxCustomBitmapFont.FreeTextureHandle;
- var
- i: Integer;
- begin
- FTextureModified := true;
- for i := 0 to FTextures.Count - 1 do
- TObject(FTextures[i]).Free;
- FTextures.Clear;
- end;
- procedure TgxCustomBitmapFont.TextureChanged;
- begin
- FTextureModified := true;
- end;
- // force texture when needed
- procedure TgxCustomBitmapFont.CheckTexture(var ARci: TgxRenderContextInfo);
- var
- i: Integer;
- begin
- // important: IsDataNeedUpdate might come from another source!
- for i := 0 to FTextures.Count - 1 do
- FTextureModified := FTextureModified or TgxTextureHandle(FTextures[i])
- .IsDataNeedUpdate;
- if FTextureModified then
- begin
- FreeTextureHandle; // instances are recreated in prepare
- PrepareImage(ARci);
- FTextureModified := False;
- end;
- end;
- function TgxCustomBitmapFont.TextureFormat: Integer;
- begin
- Result := GL_RGBA;
- end;
- // ------------------
- // ------------------ TgxFlatText ------------------
- // ------------------
- constructor TgxFlatText.Create(AOwner: TComponent);
- begin
- inherited;
- ObjectStyle := ObjectStyle + [osDirectDraw, osNoVisibilityCulling];
- FModulateColor := TgxColor.CreateInitialized(Self, clrWhite);
- end;
- destructor TgxFlatText.Destroy;
- begin
- FModulateColor.Free;
- BitmapFont := nil;
- inherited;
- end;
- procedure TgxFlatText.Notification(AComponent: TComponent;
- Operation: TOperation);
- begin
- if (Operation = opRemove) and (AComponent = FBitmapFont) then
- BitmapFont := nil;
- inherited;
- end;
- procedure TgxFlatText.SetBitmapFont(const val: TgxCustomBitmapFont);
- begin
- if val <> FBitmapFont then
- begin
- if Assigned(FBitmapFont) then
- FBitmapFont.UnRegisterUser(Self);
- FBitmapFont := val;
- if Assigned(FBitmapFont) then
- begin
- FBitmapFont.RegisterUser(Self);
- FBitmapFont.FreeNotification(Self);
- end;
- StructureChanged;
- end;
- end;
- procedure TgxFlatText.SetText(const val: UnicodeString);
- begin
- FText := val;
- StructureChanged;
- end;
- procedure TgxFlatText.SetAlignment(const val: TAlignment);
- begin
- FAlignment := val;
- StructureChanged;
- end;
- procedure TgxFlatText.SetLayout(const val: TgxTextLayout);
- begin
- FLayout := val;
- StructureChanged;
- end;
- procedure TgxFlatText.SetModulateColor(const val: TgxColor);
- begin
- FModulateColor.Assign(val);
- end;
- procedure TgxFlatText.SetOptions(const val: TgxFlatTextOptions);
- begin
- if val <> FOptions then
- begin
- FOptions := val;
- StructureChanged;
- end;
- end;
- procedure TgxFlatText.DoRender(var rci: TgxRenderContextInfo;
- renderSelf, renderChildren: boolean);
- begin
- if Assigned(FBitmapFont) and (Text <> '') then
- begin
- rci.gxStates.PolygonMode := pmFill;
- if FModulateColor.Alpha <> 1 then
- begin
- rci.gxStates.Enable(stBlend);
- rci.gxStates.SetBlendFunc(bfSrcAlpha, bfOneMinusSrcAlpha);
- end;
- if ftoTwoSided in FOptions then
- rci.gxStates.Disable(stCullFace);
- FBitmapFont.RenderString(rci, Text, FAlignment, FLayout,
- FModulateColor.Color);
- end;
- if Count > 0 then
- Self.renderChildren(0, Count - 1, rci);
- end;
- procedure TgxFlatText.Assign(Source: TPersistent);
- begin
- if Assigned(Source) and (Source is TgxFlatText) then
- begin
- BitmapFont := TgxFlatText(Source).BitmapFont;
- Text := TgxFlatText(Source).Text;
- Alignment := TgxFlatText(Source).Alignment;
- Layout := TgxFlatText(Source).Layout;
- ModulateColor := TgxFlatText(Source).ModulateColor;
- Options := TgxFlatText(Source).Options;
- end;
- inherited Assign(Source);
- end;
- // ------------------------------------------------------------------
- initialization
- // ------------------------------------------------------------------
- RegisterClasses([TgxBitmapFont, TgxFlatText]);
- end.
|